kafka本身是一个流式处理平台,同时也具有消息系统得能力,在我们得系统中更多得是把kafka作为一个消息队列系统来使用
而如果来介绍kafka,大致可以分为这几块:
传统的消息队列模型包括点对点和发布订阅模式
点对点很好理解,就是一个生产者对应一个消费者,
发布订阅模式表示 消息可以被所有消费者消费
而kafka是通过消费者组Consumer Group的概念来实现
如果说所有的消费者都同属一个消费者组,那么一条消息只会被这个这个消费者下的一个实例消费,这就是点对点模式
而如果每个消费者都对应一个消费者组,那么就是发布订阅模式

分为有key和没有key
我们可以反过来想下如果没有分区的概念,那其实意味着消息都会写入到一台机器,这样一来,非常不利于数据的负载均衡和横向扩展。
因此引入分区使得再发消息时可以根据分区的数量落在不同的kafka节点上,这提高并发写消息的性能,同时消费消息的时候是跟消费者组进行绑定,可以从不同节点的不同分区进行消费消息,提高了读消息的能力
另外一点,就是再分区的基础上又引入了副本,冗余的副本保证了kafka的高可用和高持久性
消息可靠性的保证基本上我们都要从3个方面
kafka支持3种方式发送消息,这也是常规的3种方式,发送后不管结果、同步发送、异步发送
retries=N,设置一个非常大的值,可以让生产者发送消息失败后不停重试
针对kafka自身丢失的可能设置参数:
消费者丢失的可能就比较简单,关闭自动提交位移即可,改为业务处理成功手动提交
具体修改参数
enable.auto.commit=false,设置为手动提交
auto.offset.reset=earliest,这个参数代表没有偏移量可以提交或者broker上不存在偏移量的时候,消费者如何处理。earliest代表从分区的开始位置读取,可能会重复读取消息,但是不会丢失,消费方一般我们肯定要自己保证幂等,另外一种latest表示从分区末尾读取,那就会有概率丢失消息
消费者组的好处:可以支持多种消息模型,另外的话根据消费者和分区的消费关系,支撑横向扩容伸缩
当消费者数量小于分区数量的时候,那么必然会有一个消费者消费多个分区的消息。
而消费者数量超过分区的数量的时候,那么必然会有消费者没有分区可以消费。
消费者重平衡主要是通过协调者来完成,每一次新的消费者加入都会发送请求给协调者去获取分区的分配,这个分区分配的算法逻辑由协调者来完成
而重平衡Rebalance就是指的有新消费者加入的情况,比如刚开始我们只有消费者A在消费消息,过了一段时间消费者B和C加入了,这时候分区就需要重新分配,这就是重平衡,也可以叫做再平衡,但是重平衡的过程和我们的GC时候STW很像,会导致整个消费群组停止工作,重平衡期间都无法消息消息。
另外,发生重平衡并不是只有这一种情况,因为消费者和分区总数是存在绑定关系的,上面也说了,消费者数量最好和所有主题的分区总数一样。
那只要消费者数量、主题数量(比如用的正则订阅的主题)、分区数量任何一个发生改变,都会触发重平衡。
重平衡的机制依赖消费者和协调者之间的心跳来维持,消费者会有一个独立的线程去定时发送心跳给协调者,这个可以通过参数heartbeat.interval.ms来控制发送心跳的间隔时间(默认值 3秒)。
每个消费者第一次加入组的时候都会向协调者发送JoinGroup请求,第一个发送这个请求的消费者会成为“群主”,协调者会返回组成员列表给群主
群主执行分区分配策略,然后把分配结果通过SyncGroup请求发送给协调者,协调者收到分区分配结果
其他组内成员也向协调者发送SyncGroup,协调者把每个消费者的分区分配分别响应给他们

Kafka副本的之前提到过,分为Leader副本和Follower副本,也就是主副本和从副本,和其他的比如Mysql不一样的是,Kafka中只有Leader副本会对外提供服务,Follower副本只是单纯地和Leader保持数据同步,作为数据冗余容灾的作用。
在Kafka中我们把所有副本的集合统称为AR(Assigned Replicas),和Leader副本保持同步的副本集合称为ISR(InSyncReplicas)。
ISR是一个动态的集合,维持这个集合会通过replica.lag.time.max.ms参数来控制,这个代表落后Leader副本的最长时间,默认值10秒,所以只要Follower副本没有落后Leader副本超过10秒以上,就可以认为是和Leader同步的(简单可以认为就是同步时间差)。
另外还有两个关键的概念用于副本之间的同步:
HW(High Watermark):高水位,也叫做复制点,表示副本间同步的位置。
LEO(Log End Offset):下一条待写入消息的位移
首先 Kafka 在写入磁盘文件的时候,可以直接写入这个 os cache 里,也就是仅仅写入内存中,接下来由操作系统自己决定什么时候把 os cache 里的数据真的刷入磁盘文件中。通过这一个步骤,就可以将磁盘文件写性能提升很多了,因为其实这里相当于是在写内存,不是在写磁盘
其次另一个主要功能是 kafka 写数据的时候,是以磁盘顺序写的方式来写的。也就是说,仅仅将数据追加到文件的末尾,不是在文件的随机位置来修改数据
并且kafka再读数据的时候引入零拷贝技术

参考资料
https://kafka.apache.org/documentation/
《kafka核心技术与实战》
https://mp.weixin.qq.com/s/4X5oCIrxxpNf83IV6vwqHQ
https://mp.weixin.qq.com/s/WJ-JnzxVIagzQskN53L__Q
https://www.szzdzhp.com/kafka/qa/acksAndMir#%E6%9C%80%E5%B0%8F%E5%90%8C%E6%AD%A5%E5%89%AF%E6%9C%AC%E6%95%B0-min-insync-replicas