RocketMQ学习
RocketMQ(ons)特性
0拷贝 顺序写盘 随机读 延迟消息 事务消息 顺序消息 (rabbit没有这个)
基于netty nio框架
NameServer代替Zookeeper,寻址方式,更轻量级。
集群架构无单点,扩展性强。
消息重试机制,消息查询(rabbit不支持重试)
社区活跃、成熟度好
模型
Producer
Consumer
Broker
Netty分析
- RemotingService
- RemotingClient
- 更新服务列表
- 同步发送
- 异步发送
- 注册服务
- 检查事务状态
- 回调函数,生产者发异步消息的时候
- RemotingServer
- 注册admin接口
- getProcessorPair
- 同步发送
- 异步发送
-
-
这一块是netty编程模型
-
- netty底层源码解析
- + 消息长度
- + 序列化类型&&头部长度
- + 消息头数据
- + 消息主体数据。
racketMq: fastJson传输
消息投递 消息返回状态
- send_ok 发送成功
- flush_disk_timeout 有可能刷盘失败了
- flush_slave_timeout 从节点同步失败
- slave_not_available 从节点不可用
后三种要可靠性重投递。
延迟消息
在message上设置一个delayTimeLevel。发到broker后,会延迟。
这个时间不能改,就固定选这些。
- lv1 1s
- lv2 5s
- lv3 10s
- 以此类推
怎么把消息发送到指定队列里
一个message默认有四个Mseeage Queue
MessageQueueSelector 负载均衡策略 轮询去发消息
cousumer 也是轮询消费
producer.send(Msg, selector, Obj); selector就是指定发送的对象
Broker存储结构
consumer Queue
记录了,消息偏移量信息 ;对commit log的关系类似于索引对数据库的关系;queue是内存中的,性能好。
当我们需要消费某个topic的消息时,通过对Commit Log整体遍历寻找消息的方式无疑非常的低效。所以本章将引出2个很重要的概念:消费队列、IndexFile
与commitLog只有一个文件不同,
consumeQueue
是每个topic的每个消费队列都会生产多个文件
commit Log
所有信息,包括偏移信息
commit log虽说是单文件结构,但是并不是所有的message都存储在同一个物理文件中,Rocket MQ设定了单commit log的文件大小为固定1G,而命名则与kafka相似:总长度20位,标记当前文件的物理偏移量,高位用0补齐,如下:
00000000000000000000
第一个文件,物理偏移量为000000000001073741824
第二个文件,物理偏移量为1G00000000002147483648
第三个文件,物理偏移量为2G00000000003221225472
第四个文件,物理偏移量为3G- ......
问:为什么要每个文件设定1G大小呢?
答:虽然FileChannel在映射文件时,size的入参是long值,但FileChannel内部会判断size是否超过了`Integer.MAX_VALUE`(2147483647),如果超了,会扔出`IllegalArgumentException`异常,而2147483647正好小于2G,所以文件映射无法一次性映射一个大于等于2G的文件,再加上减少理解投入及文件过期等因素,故设定commit log文件均为1G
问:因为消息都是变长字段,假如第一个文件还没写满1G,但新的消息又写不进去时,怎么处理呢?
答:其实这种情况一定会存在,解决策略是在每个文件的结尾会写入“尾部空余大小(4byte)”,以及“结束标记魔法值(4byte)”,此魔法值为固定值-875286124
写盘方式 随机写 顺序读
消费端 0拷贝
同步刷盘 异步刷盘
内存+磁盘存储两种刷盘方式
异步刷盘
同步刷盘
事务消息
不用事务的话,阻塞,增加处理时间,降低了RT。
架构场景
例子:支付A和支付B怎么可靠性解耦
- 消息发到MQ集群,同时提交事务A账户-100。
- 提交本地事务,发一个确认消息。
- 3这个时候才可见,之前不可见。
问题是:
2确认消息有可能发送失败,那一直都不可见。用mysql的存储,例如:0是不可见,1可见
解决:
MQ集群主动查询生产端,check是否成功。发ACK。
不断重试。
代码例子
(大致)
顺序消息
消费顺序和生成的顺序是相同的。例如场景:生成订单、付款、发货。
分为:
- 全局顺序
- 生成消费都是1个,这样才行。
- 局部顺序
- 保证每一组消息顺序执行
- 生产和消费都要做限制才行
- 要求:
- 投递到同一个消息下,同一个队列中。
- 消费端就是单线程取。读栈的模式。
消费端
相关问题:
1.为什么使用mq,具体场景是什么?
削峰填谷;扣减预算,积分,同步数据,记录日志,巡检优化,bcp检查,数据兜底。
2.使用什么mq,基于什么选型
同事推荐;大qps单机最大写50Wtps;支持分布式高并发业务;有事务消息和顺序消息。
3.异步发送,怎么保证消息可靠性
防止生产者丢失:异步有回调和异步无回调;本地消息表,更改状态,人工介入。
防止MQ本身丢失:同步刷盘和异步刷盘,根据业务做取舍,异步的不可靠,但是效率高。
防止消费者丢失:消费成功返回resume,否则一直执行,直到进入死信队列,人工处理。
4.消费失败重试,导致消息积压,怎么处理?
修复时,同时建一个consumer去消费当前消息,记录消息内容。
修复问题代码或服务。
重试消息。
5.消息积压达到磁盘上限,消息丢失怎么办?
本地消息表,筛选出未成功的数据。
6.rocketMq
nameServer 注册中心
producer 生产者集群
consumer 消费者
7.为什么注册中心不用zookeeper
- zk满足cp,不能保证可用性。
- nameServer轻量级,水平扩展性好,
- 持久化机制zk太重
- 若依赖注册中心,从nameServer获取broker地址后,在生产者本地缓存。
8.brocker是怎么保存数据
9.master和slave是怎么同步的
raft协议 broker收到消息 置为uncommited,随后置为slave,置为commit。
10.Rocket为什么速度快
顺序存储,pagecache,异步刷盘。