参考博文:https://blog.csdn.net/weixin_38004638/article/details/91975123
基础概念:
Producer :消息生产者,就是向broker发指定topic消息的客户端。
Consumer :消息消费者,通过订阅一组topic的消息,从broker读取消息的客户端。
Broker :一个kafka集群包含一个或多个服务器,一台kafka服务器就是一个broker,用于保存producer发送的消息。一个broker可以容纳多个topic。
Topic :每条发送到broker的消息都有一个类别,可以理解为一个队列或者数据库的一张表。
Partition:一个topic的消息由多个partition队列存储的,一个partition队列在kafka上称为一个分区。每个partition是一个有序的队列,多个partition间则是无序的。partition中的每条消息都会被分配一个有序的id(offset)。
Offset:偏移量。kafka为每条在分区的消息保存一个偏移量offset,这也是消费者在分区的位置。kafka的存储文件都是按照offset.kafka来命名,位于2049位置的即为2048.kafka的文件。比如一个偏移量是5的消费者,表示已经消费了从0-4偏移量的消息,下一个要消费的消息的偏移量是5。
消费策略
前提规则:同一个分区的数据,只能都由同一个group里消费者消费。
Consumer Group (CG):若干个Consumer组成的集合。这是kafka用来实现一个topic消息的广播(发给所有的consumer)和单播(发给任意一个consumer)的手段。一个topic可以有多个CG。topic的消息会复制(不是真的复制,是概念上的)到所有的CG,但每个CG只会把消息发给该CG中的一个consumer。*如果需要实现广播,只要每个consumer有一个独立的CG就可以了。要实现单播只要所有的consumer在同一个CG。(可以理解同一个group会维护同一个offset)***用CG还可以将consumer进行自由的分组而不需要多次发送消息到不同的topic,下面是producer和consumer group的关系图:
场景中有3个consumer,con1,con2一个group,con3另一个group,某topic指定3个partition,那么根据消费策略,默认(范围策略)会把P0,P1分配给con1,P2分配给con2; 而consumer因为组里只有他一个消费者,所以P0,P1,P2都给它消费。
除此之外,消费策略还可以选择轮询策略(P0分配 con1,P1分配con2,P2分配P0)
kafka数据是以Key Value形式存储于磁盘而并非内存,其中key可以省略,但由于kafka有partition(分区)概念,如果key值相同,那么算出的hash相同就会把数据放到同一个分区里面(这个概念又像hash槽)。
类似传统消息引擎,kafka也支持点对点、发布/订阅模型两种方式传输消息数据。
1.点对点 客户A的消息只能被客户B接收
2.发布/订阅 它有一个“主题”的概念,存在可能同时有多个消息生产者向同一个topic发布消息,消费者也有可以多个。
*为什么要使用消息引擎? A:削峰填谷。
举个例子,假设上游订单系统给下游N个自服务发送消息。因为上游系统发送指令快速简单,他只是向下游请求进行订单操作(点击下订单按钮),而下游的服务复杂,例如订单生产、走流程、调用支付宝接口等,所以遇上秒杀活动的流量,上游的流量会瞬间膨胀,直接把下游系统搞崩。加消息引擎,可以把上游的请求暂存起来,让下游服务有充足时间处理问题。
再者,使用消息引擎,还可以解耦,减少重复性工作。
Kafka 的三层消息架构:
1.第一层是主题层,每个主题可以配置 M 个分区,而每个分区又可配置N个副本
2.第二层是分区层,每个分区的 N 个副本中只能有一个充当领导者角色,对外提供服务;其他 N-1 个副本是追随者副本,只是提供数据冗余之用。
3.第三层是消息层,分区中包含若干条消息,每条消息的位移从 0开始,依次递增。
4.最后,客户端程序只能与分区的领导者副本进行交互。
kafka功能细节
kafka以高吞吐量出名:
1.它以顺序写的方式存储数据,看下图可以知道分区数据是有序,所以写数据某种规则上能有序,而不是磁盘随机IO(因为随机IO需要寻址,额外消耗)
2.为了解决频繁IO带来的问题(包括网络IO和磁盘IO),kafka采用了批量发送的机制;以这两个参数为因素,batch.size[最大值]/linger.ms[发送时间间隔]
假如一个消费者组有两个消费者,订阅了一个具有4个分区的topic的消息,那么这个消费者组的每一个消费者都会消费两个分区的消息。消费者组的成员是动态维护的,如果新增或者减少了消费者组中的消费者,那么每个消费者消费的分区的消息也会动态变化。比如原来一个消费者组有两个消费者,其中一个消费者因为故障而不能继续消费消息了,那么剩下一个消费者将会消费全部4个分区的消息。
副本同步机制
kafka主要使用场景还是集群的方式,leader写,follower会紧跟着从leader同步数据,那样就有问题了,怎么以一个比较好的方式防止数据丢失呢?
1. 副本
其中–partition 3,–replication -factor 2
表示该topic数据形成3个分区,2个副本。
场景假设:搞3台机器作为kafka集群,那么topic0在机器A,topic1在机器B,topic2在机器C,数据以均分的形式分配到集群不同机器上,那么假设这时机器B宕机了,部分数据不就都查不出来了(数据丢失)?
这时候副本就起作用了,2个副本,代表topic 0 /1 会存储在机器A,topic 1/2 会存储于机器B,topic 2/0会存储于机器C,这样假设其中一台机器挂了,也不会造成严重的数据丢失问题。
2. ISR(副本同步机制)
假设leader有三条数据,follower们读完三条后,leader没来新数据,follower们就会阻塞同步
leader来了两条新数据,于是通知follower们解锁并同步数据,由于follower这时还是同步完,那么leader会暂时锁住新增的还没同步完的数据,不让消费掉(不然消费掉就会导致未同步的那部分节点永远丢失数据了),这时候问题来了,假设有某个follower网络问题同步极其慢,不就会导致leader的数据长期被锁住?这时候就要引出ISR这个概念了,因为网络慢的follower很快会达不到第二点标准,所以它会被从副本同步队列中移除掉。
还不大明白,可以看下图解析:
消息的可靠性:
producer发送消息到broker,有下面几种策略:
消息存储的可靠性
由kafka在zookeeper里,topic里面的日志文件0000000000.log和00000000000.index维护,
因为日志和索引的记录都是有序的,查找数据会从日志找到offset和索引号,再到index文件找到相应索引的数据。
kafka部署
简单代码示例:
producer
简单说下应用场景
kafka的分区分组消费模式,很适合数据量大的,又不是很需要有序性和一致性的应用场景。例如做应用日志的收集,或者做用户行为数据的收集等等。
当然,kafka也可以只用来做广播和点对点直传消息发布消费。