Kafka C++客户端库librdkafka笔记
目录
1. 前言
librdkafka提供的异步的生产接口,异步的消费接口和同步的消息接口,没有同步的生产接口。
2. 缩略语
|
缩略语 |
缩略语全称 |
示例或说明 |
|
rd |
Rapid Development |
rd.h |
|
rk |
RdKafka |
|
|
toppar |
Topic Partition |
struct rd_kafka_toppar_t { }; |
|
rep |
Reply, |
struct rd_kafka_t { rd_kafka_q_t *rk_rep }; |
|
msgq |
Message Queue |
struct rd_kafka_msgq_t { }; |
|
rkb |
RdKafka Broker |
Kafka代理 |
|
rko |
RdKafka Operation |
Kafka操作 |
|
rkm |
RdKafka Message |
Kafka消息 |
|
payload |
存在Kafka上的消息(或叫Log) |
3. 配置和主题
3.1. 配置和主题结构
3.1.1. Conf
配置接口,配置分两种:全局的和主题的。
3.1.2. ConfImpl
配置的实现。
3.1.3. Topic
主题接口。
3.1.4. TopicImpl
主题的实现。
4. 线程
RdKafka编程涉及到三类线程:
1) 应用线程,业务代码的实现
2) Kafka Broker线程rd_kafka_broker_thread_main,负责与Broker通讯,多个
3) Kafka Handler线程rd_kafka_thread_main,每创建一个consumer或producer即会创建一个Handler线程。
5. 消费者
5.1. 消费者结构
5.1.1. Handle
定义了poll等接口,它的实现者为HandleImpl。
5.1.2. HandleImpl
实现了消费者和生产者均使用的poll等,其中poll的作用为:
1) 为生产者回调消息发送结果;
2) 为生产者和消费者回调事件。
|
class Handle { /** * @brief Polls the provided kafka handle for events. * * Events will trigger application provided callbacks to be called. * * The \p timeout_ms argument specifies the maximum amount of time * (in milliseconds) that the call will block waiting for events. * For non-blocking calls, provide 0 as \p timeout_ms. * To wait indefinately for events, provide -1. * * Events: * - delivery report callbacks (if an RdKafka::DeliveryCb is configured) [producer] * - event callbacks (if an RdKafka::EventCb is configured) [producer & consumer] * * @remark An application should make sure to call poll() at regular * intervals to serve any queued callbacks waiting to be called. * * @warning This method MUST NOT be used with the RdKafka::KafkaConsumer, * use its RdKafka::KafkaConsumer::consume() instead. * * @returns the number of events served. */ virtual int poll(int timeout_ms) = 0; }; |
5.1.3. ConsumeCb
只针对消费者的Callback。
5.1.4. RebalanceCb
只针对消费者的Callback。
5.1.5. EventCb
消费者和生产者均可设置EventCb,如:_global_conf->set("event_cb", &_event_cb, errmsg);。
|
/** * @brief Event callback class * * Events are a generic interface for propagating errors, statistics, logs, etc * from librdkafka to the application. * * @sa RdKafka::Event */ class RD_EXPORT EventCb { public: /** * @brief Event callback * * @sa RdKafka::Event */ virtual void event_cb (Event &event) = 0; virtual ~EventCb() { } }; /** * @brief Event object class as passed to the EventCb callback. */ class RD_EXPORT Event { public: /** @brief Event type */ enum Type { EVENT_ERROR, /**< Event is an error condition */ EVENT_STATS, /**< Event is a statistics JSON document */ EVENT_LOG, /**< Event is a log message */ EVENT_THROTTLE /**< Event is a throttle level signaling from the broker */ }; }; |
5.1.6. Consumer
简单消息者,一般不使用,而是使用KafkaConsumer。
5.1.7. KafkaConsumer
消费者和生产者均采用多重继承方式,其中KafkaConsumer为消费者接口,KafkaConsumerImpl为消费者实现。
5.1.8. KafkaConsumerImpl
KafkaConsumerImpl为消费者实现。
5.1.9. rd_kafka_message_t
消息结构。
5.1.10. rd_kafka_msg_s
消息结构,但消息数据实际存储在rd_kafka_message_t,结构大致如下:
|
struct rd_kafka_msg_s { rd_kafka_message_t rkm_rkmessage; struct { rd_kafka_msg_s* tqe_next; rd_kafka_msg_s** tqe_prev; int64_t rkm_timestamp; rd_kafka_timestamp_type_t rkm_tstype; }rkm_link; }; |
5.1.11. rd_kafka_msgq_t
存储消息的消息队列,生产者生产的消息并不直接socket发送到brokers,而是放入了这个队列,结构大致如下:
|
struct rd_kafka_msgq_t { struct { rd_kafka_msg_s* tqh_first; // 队首 rd_kafka_msg_s* tqh_last; // 队尾 }; // 消息个数 rd_atomic32_t rkmq_msg_cnt; // 所有消息加起来的字节数 rd_atomic64_t rkmq_msg_bytes; }; |
5.1.12. rd_kafka_toppar_t
Topic-Partition队列,很复杂的一个结构,部分内容如下:
|
// Topic + Partition combination typedef struct rd_kafka_toppar_s { struct { rd_kafka_toppar_s* tqe_next; rd_kafka_toppar_s** tqe_prev; }rktp_rklink; struct { rd_kafka_toppar_s* tqe_next; rd_kafka_toppar_s** tqe_prev; }rktp_rkblink; struct { rd_kafka_toppar_s* cqe_next; rd_kafka_toppar_s* cqe_prev; }rktp_fetchlink; struct { rd_kafka_toppar_s* tqe_next; rd_kafka_toppar_s** tqe_prev; }rktp_rktlink; struct { rd_kafka_toppar_s* tqe_next; rd_kafka_toppar_s** tqe_prev; }rktp_cgrplink; rd_kafka_itopic_t* rktp_rkt; int32_t rktp_partition; int32_t rktp_leader_id; rd_kafka_broker_t* rktp_leader; rd_kafka_broker_t* rktp_next_leader; rd_refcnt_t rktp_refcnt; rd_kafka_msgq_t rktp_msgq; // application->rdkafka queue }rd_kafka_toppar_t; |
6. 生产者
6.1. 生产者结构
6.1.1. DeliveryReportCb
消息已经成功递送到Broker时回调,只针对生产者有效。
6.1.2. PartitionerCb
计算分区号回调函数,只针对生产者有效。
6.1.3. Producer
Producer为生产者接口,它的实现者为ProducerImpl。
6.1.4. ProduceImpl
ProducerImpl为生产者的实现。
6.2. 生产者启动过程1
启动时会创建两组线程:一组Broker线程(rd_kafka_broker_thread_main,多个),实为与Broker间的网络IO线程;一组Handler线程(rd_kafka_thread_main,单个),每调用一次RdKafka::Producer::create或rd_kafka_new即创建一Handler线程。
Handler线程调用栈:
|
(gdb) t 17 [Switching to thread 17 (Thread 0x7ff7059d3700 (LWP 16765))] #0 0x00007ff7091e6cf2 in pthread_cond_timedwait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0 (gdb) bt #0 0x00007ff7091e6cf2 in pthread_cond_timedwait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0 #1 0x00000000005b4d2f in cnd_timedwait_ms (cnd=0x1517748, mtx=0x1517720, timeout_ms=898) at tinycthread.c:501 #2 0x0000000000580e16 in rd_kafka_q_serve (rkq=0x1517720, timeout_ms=898, max_cnt=0, cb_type=RD_KAFKA_Q_CB_CALLBACK, callback=0x0, opaque=0x0) at rdkafka_queue.c:440 #3 0x000000000054ee9b in rd_kafka_thread_main (arg=0x1516df0) at rdkafka.c:1227 #4 0x00000000005b4e0f in _thrd_wrapper_function (aArg=0x15179d0) at tinycthread.c:624 #5 0x00007ff7091e2e25 in start_thread () from /lib64/libpthread.so.0 #6 0x00007ff7082d135d in clone () from /lib64/libc.so.6 |
6.3. 生产者启动过程2
创建网络IO线程,消费者启动过程类似,只是一个调用rd_kafka_broker_producer_serve(rkb),另一个调用rd_kafka_broker_consumer_serve(rkb)。
IO线程负责消息的收和发,发送底层调用的是sendmsg,收调用的是recvmsg(但MSVC平台调用send和recv)。
6.4. 生产者生产过程
生产者生产的消息并不直接socket发送到brokers,而是放入队列rd_kafka_msgq_t中。Broker线程(rd_kafka_broker_thread_main)消费这个队列。
Broker线程同时监控与Broker间的网络连接,又要监控队列中是否有数据,如何实现的?这个队列和管道绑定在一起的,绑定的是管道写端(rktp->rktp_msgq_wakeup_fd = rkb->rkb_toppar_wakeup_fd; rkb->rkb_toppar_wakeup_fd=rkb->rkb_wakeup_fd[1])。
这样Broker线程即可同时监听网络数据和管道数据。
|
// int rd_kafka_msg_partitioner(rd_kafka_itopic_t *rkt, rd_kafka_msg_t *rkm,int do_lock) (gdb) p *rkm $7 = {rkm_rkmessage = {err = RD_KAFKA_RESP_ERR_NO_ERROR, rkt = 0x1590c10, partition = 1, payload = 0x7f48c4001260, len = 203, key = 0x7f48c400132b, key_len = 14, offset = 0, _private = 0x0}, rkm_link = {tqe_next = 0x5b5d47554245445b, tqe_prev = 0x6361667265746e69}, rkm_flags = 196610, rkm_timestamp = 1524829399009, rkm_tstype = RD_KAFKA_TIMESTAMP_CREATE_TIME, rkm_u = {producer = {ts_timeout = 16074575505526, ts_enq = 16074275505526}}} (gdb) p rkm->rkm_rkmessage $8 = {err = RD_KAFKA_RESP_ERR_NO_ERROR, rkt = 0x1590c10, partition = 1, payload = 0x7f48c4001260, len = 203, key = 0x7f48c400132b, key_len = 14, offset = 0, _private = 0x0} (gdb) p rkm->rkm_rkmessage->payload $9 = (void *) 0x7f48c4001260 (gdb) p (char*)rkm->rkm_rkmessage->payload $10 = 0x7f48c4001260 "{\"p\":\"f\",\"o\":1,\"d\":\"m\",\"d\":\"m\",\"i\":\"f2\",\"ip\":\"127.0.0.1\",\"pt\":2018,\"sc\":0,\"fc\":1,\"tc\":0,\"acc\":395,\"mcc\":395,\"cd\":\"test\",\"cmd\":\"tester\",\"cf\":\"main\",\"cp\":\"1.49.16.9"... |
7. poll过程
poll的作用是触发回调,生产者即使不调用poll,消息也会发送出去,但是如果不通过poll触发回调,则不能确定消息发送状态(成功或失败等)。
消费队列rd_kafka_t->rk_rep,rk_rep为响应队列,类型为rd_kafka_q_t或rd_kafka_q_s:
Kafka C++客户端库librdkafka笔记的更多相关文章
- kafka C客户端librdkafka producer源码分析
from:http://www.cnblogs.com/xhcqwl/p/3905412.html kafka C客户端librdkafka producer源码分析 简介 kafka网站上提供了C语 ...
- kafka环境搭建及librdkafka测试
kafka环境搭建及librdkafka测试 (2016-04-05 10:18:25) 一.kafka环境搭建(转自http://kafka.apache.org/documentation.h ...
- 大数据学习day31------spark11-------1. Redis的安装和启动,2 redis客户端 3.Redis的数据类型 4. kafka(安装和常用命令)5.kafka java客户端
1. Redis Redis是目前一个非常优秀的key-value存储系统(内存的NoSQL数据库).和Memcached类似,它支持存储的value类型相对更多,包括string(字符串).list ...
- Alljoyn瘦客户端库介绍(官方文档翻译 下)
由于其他事情耽误,这个翻译现在才完成.接上篇—— 4 瘦客户端核心库架构 由于AllJoyn瘦客户端核心库(AJTCL)必须运行在那些功耗受限.计算能力有限.资源紧缺的设备上,因此它无法像运行在通用型 ...
- Alljoyn瘦客户端库介绍(官方文档翻译)
Alljoyn瘦客户端库介绍(上) 1.简介 本文档对AllJoynTM瘦客户端的核心库文件(AJTCL)进行了详尽的介绍.本文档介绍了系统整体架构,AllJoyn框架结构,并着重于介绍如何将嵌入式设 ...
- 尝试加载 Oracle 客户端库时引发 BadImageFormatException
尝试加载 Oracle 客户端库时引发 BadImageFormatException 工程师给计算机诊断,就像医生给病人诊断一样,很多同样的症状,可能是由多种截然不同的原因导致的. 最近进行C# ...
- 即时聊天IM之三 XMPP协议客户端库的和Android端框架概述
合肥程序员群:49313181. 合肥实名程序员群:128131462 (不愿透露姓名和信息者勿加入) Q Q:408365330 E-Mail:egojit@qq.com smack ...
- 尝试加载 Oracle 客户端库时引发 BadImageFormatException。问题记录
电脑是win8 64位,安装oracle 11g r2 64位的,谁知道一切装完毕后,打开项目却连不上oracle数据了...首先是pl/sql连不上,装了oracle服务器,应该是不用再装客户端,p ...
- Appium 客户端库 API
## Appium 客户端库 Appium 有对应以下语言的客户端库: 语言 | 代码 :--|--:[Ruby][rubygems] | [GitHub](https://github.com/ap ...
随机推荐
- C#的格式化(进制转换|位运算)
1.首先做一下知识的普及C或c Currency 货币格式D或d Decimal 十进制格式E或e Exponent 指数格式F或f Fixed point (float)固定精度格式G或g Gene ...
- 我的第一个WCF程序
写WCF,VS需要一管理员身份呢启动,否则服务无法访问. model层 using System; using System.Runtime.Serialization; namespace MyMo ...
- golang语言中os/user包的学习与使用
package main; import ( "os/user" "fmt" ) func main() { //返回当前用户的结构 u, _ := user. ...
- visio2013专业版激活密匙
Visio 2013最新产品密钥分享,在安装时可以使用以下密钥: 2NYF6-QG2CY-9F8XC-GWMBW-29VV8 FJ2N7-W8TXC-JB8KB-DCQ7Q-7T7V3 VXX6C-D ...
- ecplise中创建jsp页面时默认的编码格式为ISO-8859-1,这里我们将其编码格式设置为utf-8
我们在创建jsp页面时,默认的编码格式为ISO-8859-1,我们如果想要将其改为utf-8还要自己手动去更改. 因此可以设置Jsp默认的编码为utf-8,具体步骤如下: 启动Eclipse,点击菜单 ...
- Jmeter常用脚本开发之Java请求
Java请求:就是用来对java项目的类进行压测 例子:将输入的两个参数通过IO存入文件 1.创建Java工程,工程目录如下 2.将Jmeter-lib下面的所有jar包导入java工程, 3.创建一 ...
- PAT 1004 成绩排名 (20)(代码)
1004 成绩排名 (20)(20 分) 读入n名学生的姓名.学号.成绩,分别输出成绩最高和成绩最低学生的姓名和学号. 输入格式:每个测试输入包含1个测试用例,格式为\ 第1行:正整数n 第2行:第1 ...
- Porsche PIWIS TESTER III
Allscanner VXDIAG Porsche Piwis III with Lenovo T440P Laptop Porsche Piwis tester III V37.250.020 N ...
- java mina框架使用
1.目前为止,看到写mina最清晰的一篇博客:https://my.oschina.net/ielts0909/blog/85946! 2.官网的开发文档:http://mina.apache.org ...
- [AI]神经网络章1 神经网络基本工作原理
神经元细胞的数学计算模型 神经网络由基本的神经元组成,下图就是一个神经元的数学/计算模型,便于我们用程序来实现. 输入 (x1,x2,x3) 是外界输入信号,一般是一个训练数据样本的多个属性,比如,我 ...