上篇文章介绍了kafka以紧凑的二进制来保存kafka的基础数据,这样能提高内存的利用率。Offset有两个不同的概念。ISR意思是replica保证数据与leader同步一致,只有一个partition里的replica集合全部接受到数据,才会标记消息发送成功。
一、kafka的历史、新版本
总所周知,kafka是美国一家LinkedIn(公司简称)的工程师研发,当时主要解决数据管道(data pipeline)的问题。
当时这家公司内部有很多子系统用于收集和分析,1、业务系统和应用程序性能监测指标。2、用户行为操作。对于第一项,虽然有些开源框架,但是linkedIn还是开发了自有监测系统来追踪这些数据。比起开源框架,自研的肯定会高度匹配自己系统,很强的针对性。当然也有很多不足的地方:
1、数据正确性不足:当时采用轮询的方式来收集的,那么必然有轮询间隔时间。
2、系统需要高度定制化,人工成本高。
与此同时,针对第二个业务,linkedIn收集用户操作采用另一种方式,定期把数据以xml的格式发送到统一的地方进行离线处理(offline batch processing)。既然是离线处理,必然无法做到强实时性,而对数据进行实时处理几乎已经成为当下所有互联网公司需要解决的问题。
总之,linkedIn这两套系统根据公开资料显示,无法实现交互,实时性差,而且维护成本高。当时工程师尝试用active MQ来解决,但最终鉴于扩展性不足,最终还是放弃了。
所以上面都预示着大统一时候的到了,kafka。
Kafka设计之初就旨在提供三方面功能:
1、为生产者消费者提供简单的api。
2、降低网络和磁盘的开销。
3、具有高伸缩架构。
新版本的producer大致是将用户待发送消息封装成一个producerRecord对象,然后使用kafkaProducer.send发送。实际上,kafkaProducer拿到消息后对其序列化,然后结合本地缓存的元数据信息确立目标分区,最后写入内存缓冲区。同时kafkaProducer还有一个专门的sender/io线程负责将缓冲区中的消息分批次发给kafka broker。
比起旧版本,新版本有几个特点:
1、发送过程被划分到两个不同的线程:用户主线程和sender/io线程,逻辑更容易把控。
2、完全异步发送消息,并且提供回调机制(callback)判断是否发送成功。
3、分批机制(batching),每个批次包括多个发送请求,提升整个吞吐量。
4、更加合理分区策略:对于没指定的key消息而言,旧版本producer分区策略是默认在一段时间内将消息发送到固定分区,这样容易造成数据倾斜(skewed),新版本采用轮询方式,消息更均匀的发送。
5、底层统一使用网络客户端java selector,结合java和future实现更加健壮和优化。
新版本的api也比较简单,比较常见的主要就这几个:
Send:实现消息发送的主逻辑方法。
Close:关闭producer。后面章节会讲关闭producer对于程序正确性而言至关重要。
Metrics:获取producer的实时监控指标数据,比如发送消息速率等。
新版本的consumer在设计时候摒弃了旧版本多线程消费不同分区的思想,采用类似linux epoll的轮询机制,使得consumer一个线程就可以管理连接不同的broker的多个socket,减少了线程间的开销成本。比起旧版本,优化设计如下:
1、单线程设计:单个consumer线程可以管理多个分区的消费socket连接,极大简化实现。虽然0.10.1.0版本额外引入了后台心跳线程(background heartbeat thread),不过双线程也比以前多线程设计好很多。
2、位移提交与保存交由kafka处理:位移不在保存在zookeeper,而是单独保存在内部的topic,这种涉及避免了频繁读写瓶颈,同时也依赖kafka备份机制天然实现高可用管理。
3、消费者组集中管理:上面提到zookeeper要管理位移,其实他还负责管理整个消费组(consumer group)的成员。这进一步家中zookeeper的依赖,新版本中,实现了一个coordinator的角色,所有成员都交给coordinator负责,因此对group更加可控。
比起旧版本,新版本api:
1、poll:最重要的方法。实现读取消息的核心方法。
2、Subcribe:订阅方法,指定consumer要消费哪些topic的哪些分区。
3、CommitSync/commitAsync:手动提交位移。新版本提供了comsumer手动提交位移,并且异步同步两种。
4、Seek/seekToBeginning/seekToEnd:设置位移方法,除了手动提交位移,还可以指定位移进行消费。
和producer不同的是,目前新旧版本consumer共存于kafka中,虽然打算放弃旧版本,但是使用旧版本的kafka用户不在少数,故至今没有移除。
二、kafka的历史、旧版本
对于早起使用kafka的公司,他们大多还在使用kafka0.8x,最广泛的0.8.2.2版本而言,这个版本刚刚推出java版producer,而java consumer还没开发。
旧版本的producer:
旧版本默认同步发送,即每条消息需要等服务端响应客户端,明确告诉消息发送的结果,才能发送下一条消息,但是这样结果就是吞吐量差,当然他也提供了一个异步的消息发送逻辑,但是凡是有利有弊,旧版本的producer强持久化的需求来说不合适,容易丢失数据。因此新版本的producer提升很好,在kafka0.9.0.0版本中,正式把旧版本producer下架。
Api而言,旧版也非常有限:
有send和close方法,另外提供了sync参数用于控制producer是同步发消息还是异步发,因此整套api非常简陋。
旧版本consumer:
不同于producer,旧版本consumer,即scala consumer其实性能不错,目前依然很多用户用着旧版的consumer,这也是迟迟没有下架的原因。