springboot kafka2.x 生产者同步发送异步发送说明

一、前言

1.1 结论

我喜欢把结论摆在前面,后面再做解释。

  • 同步写法,等待结果返回:
        SendResult<String, String> stringStringSendResult = kafkaTemplate.send("cancan", "5", msg).get();
  • 异步的写法,不等待结果返回:
ProducerRecord<String, String> record = new ProducerRecord<>("xixi", "5", msg);
ListenableFuture<SendResult<String, String>> future = kafkaTemplate.send(record);

future.addCallback(new ListenableFutureCallback<SendResult<String, String>>() {
    @Override
    public void onFailure(@NonNull Throwable throwable) {
        //错误结果
    }

    @Override
    public void onSuccess(SendResult<String, String> result) {
        //正确结果
    }
});

2.1 对比

有些同学在用rocketmq的时候,同步发送和异步发送一目了然,如下图

在这里插入图片描述
到了 springboot kafka,有些同学就迷惑了,如下图,没有很明显的说明哪一个是同步,哪一个是异步发送。

在这里插入图片描述

二、案例

2.1 依赖

我用的是 springboot 2.2.1
kafka的依赖为:

<dependency>
	<groupId>org.springframework.kafka</groupId>
	<artifactId>spring-kafka</artifactId>
</dependency>

2.2 直接摆出案例

同步发送

    @Autowired
    private KafkaTemplate<String, String> kafkaTemplate;


    //get的时候,为同步
    @RequestMapping("/sendsyn")
    public String sendSyn() throws ExecutionException, InterruptedException {

        //一个400k的字符串
        String msg = FileUtil.fileToBase64("test2");

        long s1 = System.currentTimeMillis();

        SendResult<String, String> stringStringSendResult = kafkaTemplate.send("cancan", "5", msg).get();

        ProducerRecord<String, String> producerRecord = stringStringSendResult.getProducerRecord();
        System.out.println(producerRecord.toString());

        long s2 = System.currentTimeMillis();
        System.out.println("同步耗时:"+ (s2 - s1));  //同步耗时长:312

        return "同步发送";
    }

异步发送1

    //不为get,为异步
    @RequestMapping("/sendasy")
    public String sendAsy() throws ExecutionException, InterruptedException {

        //一个400k的字符串
        String msg = FileUtil.fileToBase64("test2");

        long s1 = System.currentTimeMillis();

        ListenableFuture<SendResult<String, String>> cancan = kafkaTemplate.send("cancan", "5", msg);

        cancan.addCallback(new ListenableFutureCallback<SendResult<String, String>>() {
            @Override
            public void onFailure(@NonNull Throwable throwable) {
                System.out.println("结果失败");
            }

            @Override
            public void onSuccess(SendResult<String, String> result) {

                ProducerRecord<String, String> producerRecord = result.getProducerRecord();
                System.out.println(producerRecord.toString());

                long s4 = System.currentTimeMillis();
                System.out.println("结果成功,耗时:"+(s4 - s1)); //结果成功,耗时:521
            }
        });

        long s2 = System.currentTimeMillis();
        System.out.println("异步耗时:"+ (s2 - s1));  //异步耗时长:3

        return "异步发送";
    }

异步发送2

    //异步的其他写法
    @RequestMapping("sendasy2")
    public String sendasy2() throws ExecutionException, InterruptedException {

        //一个400k的字符串
        String msg = FileUtil.fileToBase64("test2");

        ProducerRecord<String, String> record = new ProducerRecord<>("cancan", "5", msg);

        long s1 = System.currentTimeMillis();

        ListenableFuture<SendResult<String, String>> cancan = kafkaTemplate.send(record);

        cancan.addCallback(new ListenableFutureCallback<SendResult<String, String>>() {
            @Override
            public void onFailure(@NonNull Throwable throwable) {
                System.out.println("结果失败");
            }

            @Override
            public void onSuccess(SendResult<String, String> result) {

                ProducerRecord<String, String> producerRecord = result.getProducerRecord();
                System.out.println(producerRecord.toString());

                long s4 = System.currentTimeMillis();
                System.out.println("结果成功,耗时:"+(s4 - s1)); //结果成功,耗时:521
            }
        });

        long s2 = System.currentTimeMillis();
        System.out.println("异步耗时:"+ (s2 - s1));  //异步耗时长:2

        return "异步发送2";
    }

2.3 小结,kafka的 send 都是异步发送,调用get()实现同步

从以上看出,kafka的 send 都是异步发送,如果想同步,就调用get的方法,就可以等待结果的出现。

扫描二维码关注公众号,回复: 12623905 查看本文章

三、题外话

3.1 message.max.bytes

kafka服务端的默认只接收一条数据为 1m 大小的数据
如果想要发送大于 1m 大小的数据 需要设置
服务端配置
message.max.bytes = 20000000
默认 1000000
server可以接收的消息最大尺寸。重要的是,consumer和producer有关这个属性的设置必须同步,否则producer发布的消息对consumer来说太大

3.2 max.request.size

客户端配置
max.request.size = 20000000
默认 1028576
请求的最大字节数。这也是对最大记录尺寸的有效覆盖。注意:server具有自己对消息记录尺寸的覆盖,这些尺寸和这个设置不同。此项设置将会限制producer每次批量发送请求的数目,以防发出巨量的请求。

3.3 文件转base64的类

package com.cat.demo.kafkaspringboot.utils;

import org.apache.tomcat.util.codec.binary.Base64;

import java.io.*;

//需要的jar包名commons-codec-1.6.jar

/**
 * 文件和Base64之间的相互转化工具类
 * @author rmk
 */
public class FileUtil {
 
	/**
	 * 
	 * @param path  文件全路径(加文件名)
	 * @return String
	 * @description 将文件转base64字符串
	 * @date 2019年11月24日
	 * @author rmk
	 */
	public static String fileToBase64(String path) {
		String base64 = null;
		InputStream in = null;
		try {
			File file = new File(path);
			in = new FileInputStream(file);
			byte[] bytes = new byte[(int) file.length()];
			in.read(bytes);
			base64 = new String(Base64.encodeBase64(bytes),"UTF-8");
			System.out.println("将文件["+path+"]转base64字符串:"+base64);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (in != null) {
				try {
					in.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		return base64;
	}
 
	/**
	 * @param outFilePath  输出文件路径,  base64   base64文件编码字符串,  outFileName  输出文件名 
	 * @return String
	 * @description BASE64解码成File文件
	 * @date 2019年11月24日
	 * @author rmk
	 */
	public static void base64ToFile(String outFilePath,String base64, String outFileName) {
		System.out.println("BASE64:["+base64+"]解码成File文件["+outFilePath+"\\"+outFileName+"]");
	        File file = null;
	        //创建文件目录
	        String filePath=outFilePath;
	        File  dir=new File(filePath);
	        if (!dir.exists() && !dir.isDirectory()) {
	            dir.mkdirs();
	        }
	        BufferedOutputStream bos = null;
	        java.io.FileOutputStream fos = null;
	        try {
	        	byte[] bytes = Base64.decodeBase64(base64);
	            file=new File(filePath+"/"+outFileName);
	            fos = new java.io.FileOutputStream(file);
	            bos = new BufferedOutputStream(fos);
	            bos.write(bytes);
	        } catch (Exception e) {
	            e.printStackTrace();
	        } finally {
	            if (bos != null) {
	                try {
	                    bos.close();
	                } catch (IOException e) {
	                    e.printStackTrace();
	                }
	            }
	            if (fos != null) {
	                try {
	                    fos.close();
	                } catch (IOException e) {
	                    e.printStackTrace();
	                }
	            }
	        }
	}
}

猜你喜欢

转载自blog.csdn.net/qq_34168515/article/details/109209902
今日推荐