1. 实现Kafka的生产者客户端:
1.1 创建Producer生产者实例:
一个正常的生产逻辑 需要具备以下几个步骤:
- 配置生产者客户端参数 及 创建相应的生产者实例;
- 构建待发送的消息;
- 发送消息;
- 关闭生产者实例。
1.2 发送消息的步骤:
消息构建好后,在通过 RdKafka::Producer::produce()
方法发往broker的过程中,需要先后经过 “序列化器、分区器、生产者拦截器”,最后到达broker的分区上。
拦截器一般不是必需的,而序列化器是必需的。
1.2.1 序列化器:
生产者需要使用 “序列化器(Serializer)” 把对象转换成 字节数组 才能通过网络发送给Kafka;
而在对端,消费者需要使用 “反序列化器(Deserializer)” 把从Kafka中收到的字节数组 转换成相应的对象。
1.2.2 分区器:
1.2.2.1 用户自定义生产者分区器:
生产者客户端根据分区器决定将消息发送到broker的哪一个分区上。在librdkafka中,分区器实际上就是在RdKafka::Conf
中配置的RdKafka::DeliveryReportCb
回调函数,在函数内部实现用户自定义的分区规则。
1.2.2.2 默认的生产者分区器:
如果用户没有自定义分区方法,则生产者会根据 默认的分区方法 对消息进行分配:
(1)如果 key 不为 null,那么默认的分区器会对 key 进行 哈希(采用MurmurHash2 算法,具备高运算性能及低碰撞率),最终根据得到的哈希值来计算分区号,拥有相同key 的消息会被写入到同一个分区;
(2)如果 key 为null,那么消息将会以 轮询 的方式发往主题内的各个可用分区。
1.2.2.3 关于分区器的注意事项:
(1)如果key不为null,那么计算得到的分区号是 所有分区 中的任意一个;如果key为null,并且有可用分区时,那么计算得到的分区号仅为 可用分区 中的任意一个,注意两者的差别;
(2)在不改变主题分区数量的情况下,key与分区之间的映射关系可以保持不变。但是,一旦主题中增加了分区(目前Kafka不支持删除分区,所以分区的变化方式只能是新增),那么就无法保证key与分区之间的映射关系了。
1.2.3 生产者拦截器:
Kafka一共有两种拦截器:生产者拦截器 和 消费者拦截器。
生产者拦截器可以用在 消息发送前做一些准备工作,按照某个规则过滤不符合要求的消息、修改消息内容等;
也可以用来在发送回调逻辑前做一些定制化的需求,比如统计类工作。
1.3 发送消息的三种模式:
发送消息有三种模式:
- 发后即忘;
- 同步;
- 异步。
在librdkafka中,实际的 RdKafka::Producer::produce()
方法本身是异步的,需要通过提前设置好的回调函数RdKafka::DeliveryReportCb
来获取返回结果,返回结果保存在 RdKafka::Message
类型的对象中(结果中包括是否发送成功、发送到的主题、分区、发送的消息长度等信息)。
如果想要实现 同步 的发送方法,则需要在 produce() 之后调用 RdKafka::Handle::poll(timeout_ms)
方法对produce进行阻塞,参数timeout_ms
用于设定阻塞时间。
1.4 重要的生产者参数:
1. acks
2. max.request.size
3. retries 和 retry.backoff.ms
4. compression.type
5. connections.max.idle.ms
6. linger.ms
7. receive.buffer.bytes
8. send.buffer.bytes
9. request.timeout.ms
2. 使用librdkafka的C++接口实现生产者客户端: