一. 消息中间件kafka
(1)基本概念
(2) 生产者
生产者将消息发送到topic中去,同时负责选择将message发送到topic的哪一个partition中。通过round-robin做简单的负载均衡。也可以根据消息中的某一个关键字来进行区分。通常第二种方式使用的更多。
(3)消费者
消费模式
传统的消息传递模式有2种:队列( queue) 和(publish-subscribe)
- queue模式:多个consumer从服务器中读取数据,消息只会到达一个consumer。
- publish-subscribe模式:消息会被广播给所有的consumer。
Kafka基于这2种模式提供了一种consumer的抽象概念:consumer group。
- queue模式:所有的consumer都位于同一个consumer group 下。
- publish-subscribe模式:所有的consumer都有着自己唯一的consumer group。
消费顺序
- 一个partition同一个时刻在一个consumer group中只能有一个consumer instance在消费,从而保证消费顺序。
- consumer group中的consumer instance的数量不能比一个Topic中的partition的数量多,否则,多出来的consumer消费不到消息。
- Kafka只在partition的范围内保证消息消费的局部顺序性,不能在同一个topic中的多个partition中保证总的消费顺序性。
- 如果有在总体上保证消费顺序的需求,那么我们可以通过将topic的partition数量设置为1,将consumer group中的consumer instance数量也设置为1,但是这样会影响性能,所以kafka的顺序消费很少用。
(4)rebalance
rebalance就是说如果消费组里的消费者数量有变化或消费的分区数有变化,kafka会重新分配消费者消费分区的关系。比如consumer group中某个消费者挂了,此时会自动把分配给他的分区交给其他的消费者,如果他又重启了,那么又会把一些分区重新交还给他。
如下情况可能会触发消费者rebalance
- 消费组里的consumer增加或减少了
- 动态给topic增加了分区
- 消费组订阅了更多的topic
rebalance过程中,消费者无法从kafka消费消息,这对kafka的TPS会有影响,如果kafka集群内节点较多,比如数百个,那重平衡可能会耗时极多,所以应尽量避免在系统高峰期的重平衡发生。
消费者Rebalance分区分配策略:
主要有三种rebalance的策略:range、round-robin、sticky。
Kafka 提供了消费者客户端参数partition.assignment.strategy 来设置消费者与订阅主题之间的分区分配策略。默认情况为range分配策略。
(5)应用场景
日志收集:一个公司可以用Kafka收集各种服务的log,通过kafka以统一接口服务的方式开放给各种consumer,例如hadoop、Hbase、Solr等。
消息系统:解耦和生产者和消费者、缓存消息等。
用户活动跟踪:Kafka经常被用来记录web用户或者app用户的各种活动,如浏览网页、搜索、点击等活动,这些活动信息被各个服务器发布到kafka的topic中,然后订阅者通过订阅这些topic来做实时的监控分析,或者装载到hadoop、数据仓库中做离线分析和挖掘。
运营指标:Kafka也经常用来记录运营监控数据。包括收集各种分布式应用的数据,生产各种操作的集中反馈,比如报警和报告。
(6)高性能原因
- 磁盘顺序读写:kafka消息不能修改以及不会从文件中间删除保证了磁盘顺序读,kafka的消息写入文件都是追加在文件末尾,不会写入文件中的某个位置(随机写)保证了磁盘顺序写。
- 数据传输的零拷贝
(7)kafka副本的作用
副本机制(Replication)
又称为备份机制,通常是指在分布式系中在多台机器中存储相同的数据进行备份的机制,副本机制只要有3个好处。
提供数据冗余:即使部分机器出现故障,系统仍然可以提供服务,增加了整体的可用性和数据持久化。提供高伸缩性:支持横向扩展,可以通过增加副本数,来提供读性能。改善数据局部性:允许将数据放入与用户地理位置相近的地方,从而降低系统延时。但是kafka的副本机制只提供了第一个特点,即提供数据冗余的特性。
在kafka中副本是有一个leader节点和多个follower节点组成,leader节点负责接收消息和消费消息,follower既不提供写服务也不提供读服务,仅仅用于同步leader副本的消息。follower副本的唯一作用就是当leader副本出现问题时,通过ZooKeeper 提供的监控功能能够实时感知到,并立即开启新一轮的领导者选举,从追随者副本中选一个作为新的领导者。
所谓的ISR集合,就是指副本中的消息和leader副本的消息是同步的,没有落后太多的,其中集合中,是包含leader副本自身的。
ISR集合的作用主要有两个方面
leader选举范围:当leader部分挂掉后,某个follower副本会被选为新的leader副本,能够被选为leader副本的条件就是需要在ISR集合中,当然这个是可以进行参数配置的,broker有一个参数unclean.leader.election.enable ,用来进行控制是否可以从非ISR集合中的副本选为leader节点。如果设置为true,开启 Unclean 领导者选举可能会造成数据丢失,但好处是,它使得分区 Leader 副本一直存在,不至于停止对外提供服务,因此提升了高可用性。反之,禁止 Unclean 领导者选举的好处在于维护了数据的一致性,避免了消息丢失,但牺牲了高可用性。这个就是CAP原理中,C和A的取舍问题。
生产ack为-1发送写入的数据:生产者发送消息后,消息需要写入ISR集合中全部副本,才算提交成功;ISR集合中,只有leader一个节点,那么这个时候-1就退化为了1。
副本同步机制
在kafka中,follower副本需要定期从leader部分中拉取消息,在进行消息拉取时,主要有两个概念需要弄清楚
高水位(HW):定义消息可见性,即用来标识分区下的哪些消息是可以被消费者消费的:只有在高水位以下的消息才能被消费者进行消费;并且利用次机制来完成kafka副本的消息同步。
日志末端位移(LEO):即Log End Offset,表示消息下一条消息写入的位置,注意此时这条消息是未写入到kafka中的。在kafka中每个副本都有自己的高水位和LEO信息。
高水位更新机制
在kafka中,leader副本所在的broker节点上,会保存所有follower副本的LEO值。在leader副本所在broker节点上的follower副本值,称之为远程副本(Remote Replica),kafka在运行过程中,会不断更新Broker 1 上 Follower 副本的高水位和 LEO 值,同时也会更新 Broker 0 上 Leader 副本的高水位和 LEO 以及所有远程副本的 LEO,但它不会更新远程副本的高水位值。broker0保存远程副本的信息值,就是为了leader副本来确定高水位值;leader副本的HW就是整个分区的HW值。
每个值的更新时机
Broker1上的follower副本会从leader副本拉取消息,写入到本地磁盘后,会更新其LEO的值。Broker0上的leader副本接收到生产者发送的消息,写入到本地磁盘后,会更新其LEO的值。Follower副本从leader副本拉取消失时,会告诉leader副本从哪个位置开始拉取消息。leader副本收到这个消息后,会更新本机上对应的远程副本的LEO值。Follower副本成功更新LEO值后,会比较其LEO值,和Leader副本发过来的HW的值,取两者的最小值来更新自己的HW值。当Leader副本更新完自身LEO值(或者更新了远程副本的LEO值)时,然后比较Leader副本和所有远程部分的LEO值,其最小值作为自己的HW值,并进行更新。副本同步流程解析
在初始状态下,所有值都为0
当生成者给主题发送消息后,leader分区写入消息后,leader的LEO变为1
此时follower过来拉取消息,消息拉取成功,将自身的LEO也更新为1,此时每个副本的HW还是为0,需要在下一次fetchOffset请求时,更新对应的值
当follower再次拉取消息时,follwoer副本请求拉取的值为1,Leader 副本接收到此请求后,更新远程副本 LEO 为 1,然后更新 Leader 高水位为 1。做完这些之后,它会将当前已更新过的高水位值 1 发送给 Follower 副本。Follower 副本接收到以后,也将自己的高水位值更新成 1。
高水位存在的问题:Leader 副本高水位更新和 Follower 副本高水位更新在时间上是存在错配的。这种错配是很多“数据丢失”或“数据不一致”问题的根源。为了防止,这种问题,社区在0.11版本之后,引入了Leader Epoch 概念,来规避因高水位更新错配导致的各种不一致问题。
数据丢失场景分析:因为整个消息同步过程,存在HW同步的一个延迟,当A的HW为1,B的HW为2值,此时A还没同步到B的HW值时,RelicaA发生宕机,A重启后会根据之前的HW值(保存在本地replication-offset-checkpoint中)进行日志截断,这时消息m2就会丢失,刚好此时ReplicaB发送宕机,ReplicaA被选为了Leader节点;由于follower副本的HW不能比Leader的HW值高,节点B在恢复后也会进行日志截取,消息m2就会彻底丢失掉。
Leader Epoch
可以理解为Leader的版本,由两部门组成
Epoch,一个单调递增的版本号,每当发送leader变更时,就会增加,小版本号的 Leader 被认为是过期 Leader,不能再行使 Leader 权力。起始位移(Start Offset),Leader 副本在该 Epoch 值上写入的首条消息的位移。举例说明:假设有两个Leader Epoch,Leader Epoch<0, 0> 和 <1, 120>,第一个Leader Epoch表示版本号为0,Leader 从位移 0 开始保存消息;在写了120条消息后,发生了leader变更,新的leader的版本号为1,起始位移为120。
如何防止数据丢失:此时如果A发生了宕机重启后,并不会马上进行日志截取,而是会向Leader发送一个OffsetsForLeaderEpochRequest请求,那么此时Leader返回的是2,此时该 LEO 值不比它自己的 LEO 值小,而且缓存中也没有保存任何起始位移值 > 2 的 Epoch 条目,因此 A 无需执行任何日志截断操作。
(8)kafka副本对性能的影响
(9)kafka与其他消息队列相比优势
出发点不一样,kafka定位就是处理日志和大数据 在这些业务领域,topic不会太多,延迟问题自然也就没有。
数据存储结构是主要原因,还有就是kafka只支持pull模式。而rocketmq有pull、push两种模式 (虽然这个push模式是假push),push模式延迟肯定是比pull模式延迟低。
push模式是基于pull模式的,本地有个定时线程去pull broker的消息,缓存到本地,然后push到消费线程那边。
rabbit 的push模式 是真的push 所以 延迟最低的就是兔子。 兔子不支持分布式,只支持主从模式 本身设计就是小而美的单机版。cpu消耗比kafka之类低多了。
1.是否支持延时消息
- RocketMQ支持固定延时等级的延时消息,等级可配置
- kafka不支持延时消息
2.消息过滤方式不同
- RocketMQ执行过滤是在Broker端,支持tag过滤及自定义过滤逻辑
- Kafka不支持Broker端的消息过滤,需要在消费端自定义实现
3.消息失败是否支持重试
- Kafka不支持重试 (通过另外创建消息重试topic实现重试)
- RocketMQ支持定时重试,每次重试间隔逐渐增加
4.事务机制不同
两个消息中心的事务机制也有所不同。RocketMq通过二阶段提交和回查机制能够实现分布式场景下的事务:两个系统进行处理同一业务流程交易时,保证生产方处理和发送消息阶段两个动作要么同时成功,要么同时失败。而Kafka则是保证生产者发送多条消息可以封装在一个事务中,形成一个原子操作
kafka & rocket mq对比(【精选】rocketMq和kafka对比_kafka和rocketmq-CSDN博客):
1. 使用场景:Kafka适合日志处理;RocketMQ适合业务处理
2. 性能:Kafka吞吐量更高,单机百万/秒;RocketMQ单机10万/秒。
因为Kafka一个topic有很多partition,代表很多目录,每个目录下有很多segment,每个代表一个消息文件,而RocketMQ存储消息只有commitLog文件。所以Kafka可以并发写,快于RocketMQ。但同样的,当Topic增加,Kafka分区文件增多,文件刷盘时会竞争磁盘资源,而导致效率降低。
同时,生产者有一个发送消息的缓存队列,客户端发送后,放入缓存,立刻返回成功。当缓存队列达到阈值,才真正发送给broker,此举合并了多次请求,批量发送&批量压缩,减少网络IO,但增大消息丢失风险
3. 特殊消息:Kafka不支持定时,事务消息等
4. 支持队列数:Kafka超过64个队列(partition)性能下降严重,而RocketMQ最高支持5万个队列
消息队列原理和选型:Kafka、RocketMQ 、RabbitMQ 和 ActiveMQ - 知乎
(10)kafka如何确保不丢失消息
1.生产者环节丢失
生产者环节发送失败导致的丢失,导致的原因可能是网络波动的原因,或是kafka节点故障的原因;
生产者发送消息的方式有两种: 同步 与 异步;
【解决方案】:
采用异步推送消息的方式,因为消息异步推送后,会有一个回调函数,根据回调函数的情况可以对消息进行补发;
此外,还可以设置消息重试次数;
代码如下:
2.Broker存储环节丢失
Broker存储环节,kafka对此有一个发送确认机制acks;
结合考虑kafka集群的情况下;
【解决方案】
acks发送确认机制有三种模式:
默认acks=1,只要集群leader节点,收到消息就响应成功;
acks=all,可以避免在极端情况下,消息在存储环节出现问题,但是要综合考虑其性能[不建议];
该处使用的url网络请求的数据。
刷盘机制分同步刷盘和异步刷盘:
生产者消息发过来时,只有持久化到磁盘,存储端Broker才返回一个成功的ACK响应,这就是同步刷盘。它保证消息不丢失,但是影响了性能。
异步刷盘的话,只要消息写入PageCache缓存,就返回一个成功的ACK响应。这样提高了MQ的性能,但是如果这时候机器断电了,就会丢失消息。
Broker一般是集群部署的,有master主节点和slave从节点。消息到Broker存储端,只有主节点和从节点都写入成功,才反馈成功的ack给生产者,这就是同步复制,它保证了消息不丢失,但是降低了系统的吞吐量。与之对应的就是异步复制,只要消息写入主节点成功,就返回成功的ack,它速度快,但是会有性能问题。
在kafka中避免broker宕机,可以设置多副本冗余的高可用机制
3.消费者环节丢失
该环节丢失原因: 节点重平衡 和 偏移量自动提交导致的;
【消费者节点重平衡】可以简单的理解为,一个消费者组中,有一个消费者挂了,接着另一个消费者会接班之前的消费工作;
【偏移量自动提交】:每次poll数据之后,消费者默认每隔5s就会提交一次已消费的偏移量;
会导致一下情况:
【重复消费】: 消费者节点宕机之前,还未来得及提交偏移量,重平衡之后,新分配的消费者,按照之前的偏移量进行消费从而导致了重复消费;
【消费丢失】:消费者节点宕机之前,提交了偏移量,但是实际的消费偏移量还未到达提交的偏移量,从而导致了消费丢失;
【解决方案】:
禁用自动提交偏移量,改为手动:
enable-auto-commit:false
代码如下:
【扩展】为什么采用了 异步 +同步的方式?
因为 同步提交的时候,消费端的程序会处于阻塞状态,进而会影响系统数据的吞吐量;
而 异步提交方式,虽然解决了提交偏移量阻塞的问题,但是是没有自动重试机制的,会出现一定的风险,
所以二者相组合使用,进行互补;
kafka消息丢失解决方案_勤天的博客-CSDN博客
【348期】面试官:Kafka和RocketMQ有什么区别? - 知乎
https://zhuanlan.zhihu.com/p/423309452rocketmq 与 kafka 对比漫谈 - 简书
Spring Cloud(十二):消息中心篇-RocketMq与Kafka选型(四) - 墨天轮
kafka和rocketmq区别对比_—Phoenix的博客-CSDN博客
Kafka基础原理 - 简书
美团面试官让我聊聊kafka的副本同步机制,我忍不住哭了_wx646db0e245a37的技术博客_51CTO博客
kafka副本机制
浅析操作系统和Netty中的零拷贝机制