深入Kafka源码02:生产者Producer原理与初始化源码分析、一些常用的元数据及数据结构信息

1、生产者Producer

1.1 发送消息Demo

位置:java\kafka\examples\Producer.java

  • 生产者往Kafka发送消息

步骤:

      1、初始化生产者类,配置Brokers源

      2、准备消息并不断开始发送消息

      3、利用异步或同步发送消息,若是异步,重写回调函数,处理消息返回与发送状态;若是同步,则发送完后等待消息返回值,可能会产生阻塞

      4、由于生产者是一个不断发送消息机制,不需要关闭

//消息生产者
public class Producer extends Thread {
    private final KafkaProducer<Integer, String> producer;
    private final String topic;
    private final Boolean isAsync;

    //利用构造方法初始化各种参数
    public Producer(String topic, Boolean isAsync) {
        Properties props = new Properties();
        //配置Broker数据,方便用户拉取Kafka元数据
        props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, KafkaProperties.KAFKA_SERVER_URL + ":" + KafkaProperties.KAFKA_SERVER_PORT);
        //客户端ID,没有时会自动生成一个客户ID
        props.put(ProducerConfig.CLIENT_ID_CONFIG, "DemoProducer");
        //设置消息k/v传输时序列化的类 消费者消费抓取数据时再进行反序列化
        props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, IntegerSerializer.class.getName());
        props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName());
        //构建生产者
        producer = new KafkaProducer<>(props);
        this.topic = topic;
        //Kafka发送数据的方式:isAsync为true则异步发送,为false则同步进行发送
        this.isAsync = isAsync;
    }

    public void run() {
        int messageNo = 1;
        //一启动就会一直往kafka发送数据
        while (true) {
            //模拟生成消息,不断生成并进行发送
            String messageStr = "Message_" + messageNo;
            long startTime = System.currentTimeMillis();
            if (isAsync) { // Send asynchronously
                //异步发送:消息发送完成后直接进行下一条消息发送,不需要等待,
                // 而是等服务调用DemoCallBack回调函数获取消息发送的返回信息,以判断消息是否发送成功而执行相应的操作
                /**
                 * ProducerRecord:一条消息结构
                 * topic:消息的主题  messageNo:消息key  messageStr:消息本身value
                 */
                producer.send(new ProducerRecord<>(topic,
                    messageNo,
                    messageStr), new DemoCallBack(startTime, messageNo, messageStr));
            } else { // Send synchronously
                //同步发送:消息发送完后,需要等get返回才能进行下面的下一条消息,可能会出现阻塞
                try {
                    producer.send(new ProducerRecord<>(topic,
                        messageNo,
                        messageStr)).get();
                    System.out.println("Sent message: (" + messageNo + ", " + messageStr + ")");
                } catch (InterruptedException | ExecutionException e) {
                    e.printStackTrace();
                }
            }
            ++messageNo;
        }
    }
}

//异步时的回调函数
class DemoCallBack implements Callback {

    private final long startTime;
    private final int key;
    private final String message;

    public DemoCallBack(long startTime, int key, String message) {
        this.startTime = startTime;
        this.key = key;
        this.message = message;
    }

    /**
     * A callback method the user can implement to provide asynchronous handling of request completion. This method will
     * be called when the record sent to the server has been acknowledged. Exactly one of the arguments will be
     * non-null.
     *
     * @param metadata  The metadata for the record that was sent (i.e. the partition and offset). Null if an error
     *                  occurred.
     * @param exception The exception thrown during processing of this record. Null if no error occurred.
     */
    //重写onCompletion方法,metadata:服务端元数据信息,
    public void onCompletion(RecordMetadata metadata, Exception exception) {
        long elapsedTime = System.currentTimeMillis() - startTime;
        if (metadata != null) {
            System.out.println(
                "message(" + key + ", " + message + ") sent to partition(" + metadata.partition() +
                    "), " +
                    "offset(" + metadata.offset() + ") in " + elapsedTime + " ms");
        } else {
            exception.printStackTrace();
        }
    }
}
  • 消息类ProducerRecord
//消息类:每一条消息都会以主题为单位进行归类,Kafka根据消息的key按主题不同而分配不同的分区,相同的Key会被划分到同一个分区之中
public class ProducerRecord<K, V> {

    //主题
    private final String topic;
    //分区号
    private final Integer partition;
    //消息头
    private final Headers headers;
    //消息key:用来指定消息的键,可以计算出分区号进而可以将消息发往特定的分区中,
    private final K key;
    //消息的值,一般不为空,若为空则为墓碑消息
    private final V value;
    //消息时间戳
    private final Long timestamp;

    /**
     * Creates a record with a specified timestamp to be sent to a specified topic and partition
     * 
     * @param topic The topic the record will be appended to
     * @param partition The partition to which the record should be sent
     * @param timestamp The timestamp of the record, in milliseconds since epoch. If null, the producer will assign
     *                  the timestamp using System.currentTimeMillis().
     * @param key The key that will be included in the record
     * @param value The record contents
     * @param headers the headers that will be included in the record
     */
    public ProducerRecord(String topic, Integer partition, Long timestamp, K key, V value, Iterable<Header> headers) {
        if (topic == null)
            throw new IllegalArgumentException("Topic cannot be null.");
        if (timestamp != null && timestamp < 0)
            throw new IllegalArgumentException(
                    String.format("Invalid timestamp: %d. Timestamp should always be non-negative or null.", timestamp));
        if (partition != null && partition < 0)
            throw new IllegalArgumentException(
                    String.format("Invalid partition: %d. Partition number should always be non-negative or null.", partition));
        this.topic = topic;
        this.partition = partition;
        this.key = key;
        this.value = value;
        this.timestamp = timestamp;
        this.headers = new RecordHeaders(headers);
    }

    /**
     * Creates a record with a specified timestamp to be sent to a specified topic and partition
     *
     * @param topic The topic the record will be appended to
     * @param partition The partition to which the record should be sent
     * @param timestamp The timestamp of the record, in milliseconds since epoch. If null, the producer will assign the
     *                  timestamp using System.currentTimeMillis().
     * @param key The key that will be included in the record
     * @param value The record contents
     */
    public ProducerRecord(String topic, Integer partition, Long timestamp, K key, V value) 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

pub.ryan

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值