kafka和RocketMq关键特性解析

RocketMq关键特性

顺序消费

首先多个queue只能保证单个queue里的顺序,queue是典型的FIFO,天然顺序。多个queue同时消费是无法绝对保证消息的有序性的。可以使用同一topic,同一个QUEUE,发消息的时候一个线程去发送消息,消费的时候一个线程去消费一个queue里的消息。消费端就有消费者通过业务保证消费的一致性
例如:一笔订单产生了3条消息,分别是订单创建、订单付款、订单完成。消费时,必须按照顺序消费才有意义,与此同时多笔订单之间又是可以并行消费的。RocketMQ默认提供了两种MessageQueueSelector实现:随机/Hash,由于以上个都有相同的订单id通过hash都会选择同一个队列

消息重复

造成消息重复的根本原因是:网络络不可达。
只要通过网络交换数据,就无法避免这个问题。所以解决这个问题的办法是绕过这个问题。那么问题就变成了:如果消费端收到两条一样的消息,应该怎样处理?

  1. 消费端处理消息的业务逻辑要保持幂等性。
  2. .保证每条数据都有唯一编号,且保证消息处理成功与去重表的日志同时出现。

第1条很好理解,只要保持幂等性,不管来多少条重复消息,最后处理的结果都一样。
第2条原理就是利用一张日志表来记录已经处理成功的消息的ID,如果新到的消息ID已经在日志表中,那么久不在处理这条消息。

事务消息

Half Message(半消息)

是指暂不能被Consumer消费的消息。Producer 已经把消息成功发送到了 Broker 端,但此消息被标记为暂不能投递状态,处于该种状态下的消息称为半消息。需要 Producer对消息的二次确认后,Consumer才能去消费它。

消息回查

由于网络闪段,生产者应用重启等原因。导致 Producer 端一直没有对 Half Message(半消息) 进行 二次确认。这是Brock服务器会定时扫描长期处于半消息的消息,会主动询问 Producer端 该消息的最终状态(Commit或者Rollback),该消息即为 消息回查。
理解这张阿里官方的图,就能理解RocketMQ分布式事务的原理了。
在这里插入图片描述
1、A服务先发送个Half Message给Brock端。

2、当A服务知道Half Message发送成功后,那么开始第3步执行本地事务。

3、执行本地事务(会有三种情况1、执行成功。2、执行失败。3、网络等原因导致没有响应)

4.1)、如果本地事务成功,那么Product像Brock服务器发送Commit,这样B服务就可以消费该message。

4.2)、如果本地事务失败,那么Product像Brock服务器发送Rollback,那么就会直接删除上面这条半消息。

4.3)、如果因为网络等原因迟迟没有返回失败还是成功,那么会执行RocketMQ的回调接口,来进行事务的回查。

为什么要先发送Half Message(半消息)
  1. 可以确认brock是否是正常运行的如果半消息发送都失败了,那就说明brock都挂了不需要进行之后的操作了
  2. 可以通过半消息进行消息的回查,如果brock迟迟没有等到生产者的conmmit和Rollback的消息就可以通过半消息进行回查.
什么情况会回查
  1. 执行本地事务的时候,由于突然网络等原因一直没有返回执行事务的结果(commit或者rollback)导致最终返回UNKNOW,那么就会回查。
  2. 本地事务执行成功后,返回Commit进行消息二次确认的时候的服务挂了,在重启服务那么这个时候在brock端
    它还是个Half Message(半消息),这也会回查。

特别注意:
1.如果回查,那么一定要先查看当前事务的执行情况,再看是否需要重新执行本地事务。
2.想象下如果出现第二种情况而引起的回查,如果不先查看当前事务的执行情况,而是直接执行事务,那么就相当于成功执行了两个本地事务。

Producer如何发送消息

Producer轮询某Topic下所有队列的方式来实现发送方的负载均衡。

  1. 在整个升命周期内,升产者需要调用一次start方法来初始化,初始化主要完成的任务有:
  2. 如果没有指定namesrv地址,将会自动寻址
  3. .启动定时任务:更新namesrv地址、从namesrv更新Topic路由信息、清理已经挂掉的broker、向所有的broker发送心跳…
  4. 启动负载均衡的服务

消息存储

RocketMQ的消息存储是由comsume queue 和 cimmit log配合完成的。consume queue是消息的逻辑队列,相当于字典的j记录,用来指定消息在物理⽂件commit log上的位置。

CommitLog

要想知道RocketMQ如何存储消息,我们先看看CommitLog。在RocketMQ中,所有topic的消息都存储在一个称为CommitLog的文件中,该文件默认最大为1GB,超过1GB后会轮到下一个CommitLog文件。通过CommitLog,RocketMQ将所有消息存储在一起,以顺序IO的方式写入磁盘,充分利用了磁盘顺序写减少了IO争用提高数据存储的性能

ConsumeQueue加粗样式

一个ConsumeQueue表示一个topic的一个queue,RocketMQ的ConsumeQueue中不存储具体的消息,具体的消息由CommitLog存储,ConsumeQueue中只存储路由到该queue中的消息在CommitLog中的offffset,消息的大学以及消息所属的tag的hash(tagCode),一共只占20个字节

消费模式

集群消费
消费者的一种消费模式。一个ConsumerGroup中的各个Consumer实例分摊去消费消息,即一条消息只会投递到一个ConsumerGroup下面的一个实例。
广播消费
消费者的一种消费模式。消息将对一个ConsumerGroup下的各个Consumer实例都投递一遍。即即使这些Consumer属于同一个ConsumerGroup,消息也会被ConsumerGroup中的每个Consumer都消费一次。

RocketMQ消息订阅有两种模式

PushConsumer
推送模式(虽然RocketMQ使用的是长轮询)的消费者。消息的能及时被消费。使用非常简单,内部已处理如线程池消费、流控、负载均衡、异常处理等等的各种场景。
PullConsumer
拉取模式的消费者。应用主动控制拉取的时机,怎么拉取,怎么消费等。主动权更高。但要自己处理各种场景。

kafka关键特性

日志存储

kafka日志是以topic主题为进本单位的,一个主题下对应着一个或者多个分区。topic与topic之间的逻辑是相互独立的。分区数量可以在创建topic的时候设置也可以通过之后修改。在发送消息的是根据分区规则把消息发送到不同的分区,然后分配一个唯一的序列号,也就是常说的偏移量(offset)
在这里插入图片描述
kafka为了更好的维护和清理,引入了日志分段的概念(logSegment),将一个log文件分成了多个Log Segment,每一个 partition 对应多个个 log 文件(最大 1G), 每一个 log 文件又对应一个 index 文件
在这里插入图片描述
查找 Message 流程:

  1. 先根据 offset ,通过二分法找到最大小于等于offset的.index文件
  2. 然后再根据二分法找到.index文件里面最大小于该offset的.log文件
  3. 然后再.log文件中顺序

分区副本剖析

kafka通过分区副本实现故障转移和容灾,在kafka集群下某个节点brock挂了还能继续的为我们提供服务可用

副本机制
  1. 副本分为Leader副本(领导者副本)和follwer副本(追随者副本)
  2. 所有的请求都是Leader副本来处理的,Follwer副本不对外提供服务,只同步Leader副本的数据。
  3. 在领导者副本挂掉了或者是说宕机了就会立即开启新一轮的领导者选举,从ISR集合中的追随者副本中选一个作为新的领导者。当老的Leader副本重启回来后,只能作为追随者副本加入到集群中。
ISR and AR and OSR
  1. 简单来说,分区中的所有副本统称为 AR。
  2. 在设置的一同步时间内能够完成leader副本数据的同步就可以把该副本放入ISR集合里面。
  3. 相反在同步的时间里面没有完成数据的同步,也就是说同步滞后的副本,将放入OSR集合里面。
  4. 由此可见,AR = ISR + OSR。正常情况下,所有的follower副本都应该与leader 副本保持 一定程度的同步,即AR=ISR,OSR集合为空。

ISR 的伸缩性

leader副本负责跟踪和维护ISR集合中副本如果滞后了就会把该副本提出ISR集合然后把该副本加入OSR集合,如果OSR集合中的副本同步数据的进度赶上了Leader副本的进度,则也会把这个副本加入到ISR集合当中去。在Leader副本挂掉之后开启新的的一轮leader的选举的时候也只会在ISR集合中选举,OSR集合中的副本是没有机会的。

可靠性ack分析

  1. acks=0的时候生产者不需要等brock返回ack就可以进行下条消息的发送,这样子效率是最高的但是数据丢失几率也是最高的
  2. acks=1的时候,等leader副本收到数据成功之后,follwer副本不需要完成数据的同步就会返回ack给生产者。这样子效率会比acks=0的时候低。消息的可靠性要比acks=0要好。但是等leader副本宕机之后,follwer副本没有同步完成leader副本的数据那么会造成数据的丢失
  3. acks=-1的时候,要等leader副本和follwer副本都需要完成数据的同步,才会发送acks给生产者。

kafka高性能

消息顺序追加

Kafka是通过文件追加的方式来写入消息的,只能在日志文件的最后追加新的消息,并且不允许修改已经写入的消息,这种方式就是顺序写磁盘,而顺序写磁盘的速度是非常快的。
在这里插入图片描述

页缓存

页缓存是一种操作系统的磁盘缓存,用来减少和磁盘的io操作来提高性能。具体来说就是kafka会使用大量的缓存页把对磁盘的访问变成对内存的访问,这样就会大大提高访问的效率。消息写入都是先写入到内存,然后根据操作系统自行的进行刷盘任务把内存中的消息写入到磁盘里面

零拷贝

零拷贝技术是一种避免CPU将数据从一块存储拷贝到另一块存储的技术。Kafka使用零拷贝技术将数据直接从磁盘复制到网卡设备缓冲区中,而不需要经过应用程序的转发。

在这里插入图片描述

通常应用程序将磁盘上的数据传送至网卡需要经过4步:
    1. 调用read(),将数据从磁盘复制到内核模式的缓冲区;
    2. CPU会将数据从内核模式复制到用户模式下的缓冲区;
    3. 调用write(),将数据从用户模式下复制到内核模式下的Socket缓冲区;
    4. 将数据从内核模式的Socket缓冲区复制到网卡设备。
  上面的步骤中,第2、3步将数据从内核模式经过用户模式再绕回内核模式,浪费了两次复制过程。采用零拷贝技术,Kafka可以直接请求内核把磁盘中的数据复制到Socket缓冲区,而不用再经过用户模式。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值