rocketMq 借鉴了Kafka的思想
1.一个topic下的一个queue中的一个消息只能被一个消费者组中的一个消费者消息。一个消费者组可以消费多个queue(分区),一个分区不能被多个消费者组消费。
2. 一个broker就是一个mq实例,一个topic会在多个broker上有分片。分片的下一级是queue
3. msgId:生产者生成的id,offsetMsgId: broker生成, key:用户生成的业务id ,queueOffset 在queue中的第几个。
4. 生产者都是以生产者组的形式存在,可以给多个topic生产消息。
5. 消费者以消费者组的形式出现,一个消费者组只能对应一个topic。
6. 消费者组方便了负载均衡,这个负载均衡是指在queque级别上,将queque均匀的分配给消费者。
7. 消费者组也方便了容错,指一个消费者消费失败了,这个消息还可以被其它消费者消费。
8. 一个消费者组中的consume个数不能多余queue数量,如果超出,则超出的consumer不能工作,也就是说一个queque最多只能被一个消费者消费。
9. nameserver 是borker和topic的注册中心,支持borker的动态注册和发现。rocketMq 的前身 meteQ 没用nameserver 而是用的zookeeper。
10. nameserver 是无状态的,集群部署的,各个节点之间不进行通讯。borker 会轮询每个nameserver注册自己的信息。这样的优点是nameserver扩容简单,缺点是nameserver增加节点时必须在broker中重新配置nameserver的地址。
11. 路由剔除,nameserver 没10秒遍历下borker列表,发现上一次心跳消息超过了120秒,则剔除。
12. topic 路由信息变化时,nameserver 不会推给客户端,而是客户端默认每30秒从nameserver拉一次。这叫pull 模型。
13. push 模型需要维护长连接,pull模型实时性不好。
14. 长轮询:long polling 轮询并保持连接一段时间。
15. 客户端选择要连接的nameserver 时,先随机选一个,如果连接失败,就轮询逐个尝试。
16. broker分broker master 和 broker slave
17. 设置主从的方式是设置相同的broker name,设置不同的borderId,borderId为0的
18. 启动时, broker 和所有 nameserver 建立长连接 ,每30秒发心跳。生产者和一台nameserver保持长连接,获取一次broker地址和topic的queue的对应关系,在queue 级别通过负载均衡选中一个queue后,查到这个queue的路由信息,即ip+port ,然后发送消息。以后每30秒更新一次。
19. consumer是需要像nameserver发送心跳的,product 不用。
20. topic 的集群创建模式下,每个borker上的queue数量相同;borker 创建模式下,不一定相同。
21. 发消息时自动创建的topic , 默认采用broker模式,默认每个broker4的queue。
22. 读写队列,读写队列在物理上是相同的,就是可以控制一个queue 是否开启读或写功能。或者说,可以控制生产者或消费者可见的queue 。这样就 方便queue的缩容。
23. perm 用于设置当前topic的权限, 2:只读,4:只写,6:读写。
24. rocket console 的安装和启动需要 JAXB 依赖,一种根据xml生成java类的规范。
25. 对于生产者和消费者集群,需要的配置就只是相同的groupNmae。
26. 主从broker的数据复制有同步复制和异步复制。
27. 每个broker的刷盘策略也分同步刷盘和异步刷盘之分。
28. 在RAID10 的磁盘配置下,如果是同步刷盘,机器宕机也不会数据丢失,异步刷盘会丢失少量消息。
29. 多master多slave的同步双写 模式下,mster宕机后slave不会自动切换成master。 异步复制是会的。
30. RAID 磁盘阵列技术就是用多个磁盘有机组合成一套可靠存储系统的技术。
31. topic 的路由表是个map ,key是topic名,value 是一个 QueueData ,一个queueData 是一个borker下该topic的所有queue
32. borker 列表是个map , key是broker名,value 是 broderData ,一个broderData 是一套名为该broker名的主从borker 集合。
33. queque 先择算法,1,轮询算法,这种算法容易收到较慢queue的影响,造成延迟。 2,最小延迟法,统计每次投递的延迟时间,选择最小时间的queue,这种缺点是可能造成消息分配不均匀最后造成积压。
34. rocketMq 的消息文件在本地,默认在用户主目录下的 store 目录中。
35. commitlog 目录下存放着 mappedFile 文件 , 当前broker的消息落盘就是存在这些文件中的,单个mappedFile 文件最大为1G,文件名是该文件第一条消息的偏移量。mappedFile 文件不分 topic ,所有topic的消息都是顺序记录在mappedFile 文件中的。
36. 偏移量的具体含义是字节大小,比如第一个mappedFile 文件中存了 100 B 的数据,则第二个文件的文件名是 00000000000000000100 .
37. mappedFile 文件内容由一个个消息单元构成,消息单元记录了20多项消息有关的信息。
38. consumequeue 目录下是以topic 名为名的目录,topc 目录下 是以queueId 为名的 queue 目录,queue 目录下是consumequeue 文件,每个文件的大小固定,所以第n个consumequeue文件的名字也一定固定,文件中的每个数据记录了消息在mappedFile 文件中的 commitlogOffset ,消息长度,消息tag的hashcode值。 每个单元数据 20 字节,每个文件存 30 万条数据,每个文件大小 30万 * 20 字节。
39. 写入时,先根据 queueId , 确定queueOffset ,再写入commitlog文件,再写入 consumequeue 文件。
40. 读取时,consumer 先根据当前读取消息的位置,加1 则为下一条消息的位置, 发送请求给broker ,broker 用消息位置 * 20 字节得到queueOffset ,再查到 commitlogOffset 。
41. 由于数据都是顺序存放的,pageCache 机制可以很好提高读取性能。
42. index 目录下 的indexFile文件中保存了对用户设置的key的索引,方便根据key查询信息。
43. indexFile的文件名时创建文件时的时间戳,再根据业务key查询时,还要指定一个时间戳,查询时间不大于此时间的最新消息,提高查询效率。
44. 每个indelFile最多村2000万个单元数据。
45. 每个indeXFile文件,显示 40 字节的基础信息,然后时500万个slot信息,每个slot信息4字节,最后是所有index信息,每个index占20字节,最多2000万个index
46. 写入时,先跟据 key 取hash,对500万取模找到slot,创建新index单元数数据,新index的preIndexNO为当前slot的indexNo,然后修改slot的indexNo 为新index的indexNo,indexNo是index单元在indelFile中顺序,即第几个index,40+500万 * 4 + (indexNo-1)* 20 就是内存offset ,index 单元中保存了commitlogOffset ,key,和indexFile创建时间时间差等。记录时间差是为了方便查询。
47. 获取消息方式:pull 模式需要consumer自己指定拉取时间,实时性不好。 push模式需要长连接,且consumer不能控制消费速度。
48. 消费模式:广播消费,消费组中的每个消费者都可消费全量topic消费。 集群消费下,topic 的消息平均分到每个消费者。
49. 消息进度保存: 广播消费模式下,每个消费者记录自己的消费进度。 集群消费模式下,消费进度由broker保存。
50. 消费进度保存在 store/config/consumerOffset.json 文件中。
51. reblance 机制是指在消费者组中的消费者数量或者queue数量变更时,重新分配消费者的机制。当然,在集群消费的模式下才需要重新分配。
52. reblance 会造成消费暂停,重复消费,消费突刺(reblance之后的短时间内需要消费很多消息)等问题。
53. 消费者向broker提交自己已经消费的消息offset时,同步提交的话,需要等broker返回ack才继续请求下一批消息。异步提交的话,不等broker返回ack就请求消费下一批消息。所以异步提交的情况下rebance 时就可能重复消费。
54. broker 检测到queque或者消费者数量发生变化时,发送reblance命令给consumer,consumer自行根据算法重新选择queue。
55. queue 的分配规则有四种: 1,平均分配规则。 2, 环形分配规则,顺序遍历queue,依次分发给consumer,像是发牌一样。 3, 一致性hash,将consumer 和queue的hash一起放在一个环上,顺时针遍历,queue属于它前面的那个consumer。 4. 同机房策略,在统一机房内的queue和consumer平均分。如果有的机房没有queue,则全局用其它策略分。
56. 一致性hash的主要作用就是当节点数量变更时,需要重新分配资源的节点很少,redis的cluser 可以减少数据迁移。rocket的consumer可以减少reblance过程中变更queue的consumer。它的应用场景就是节点经常变动的情况。
57. 至少一次原则,rocket 保证消费至少要被成功消费一次。
58. 广播消费模式下,consumer 的消费进度offset 保存在 用户目录的 .rocketmq_offsets/${clientId}/group/offset.json
59. 集群模式下 消费进度offset保存在broker上。
60. consumer.setConsumerFromWhere() 指定从哪里开始消费。有6中固定的起始方式。
61. 消费者消费异常时,将消息offset提交给 %RETRY%-topic 名的重试队列中,到达重试时间后进行重试消费。 疑问:代码中时手动提交的吗?
62. consumer 同步提交消费offset时,从ack信息中获取下一个需要消费的消息offset,异步提交时,直接从broker读取下一个消息offset。
63. 消息重复的场景: 1, 网络闪断导致生产者重复提交。 2, 因网络闪断导致消费者提交的已消费offset没有被broker收到。 3,reblance 时重复消费。
64. 处理重复消费的方案:两个要素: 1,幂等令牌,要有全局业务唯一的消息id。 2,幂等的业务代码逻辑。
65. 消息堆积的主要原因时消费者消息费相对较慢。
66. 线程数的确定: CPU核心数*总耗时/CPU耗时
67. 清理消息只能以清理commitlog 的形式清理,默认过期时间72小时。除手动清除外,会自动根据过期时间和磁盘使用清空清理文件。
68. 官方建议linux文件系统用ex4 比 ex3 好。
### rocketMq 的请用
69. 发送消息也有同步发送和异步发送之分。异步发送的情况下broker是会返回ack的只是是异步的,还有一种是单向发送(oneway),broker不返回ack。
70. java 中用的 rocketmq依赖版本应和rocketmq的版本号相同。
71. 使用同步发送还是异步发送主要是sdk的producer调用的方法不一样。
72. 使用集群消费还是广播消费是在consumer端设置的。
73. 创建topic时有三种指定queue个数的方式,通过producer设置,通过控制台设置,通过mqadmin命令设置。
74. 如何指定queue发送?可以在创建producer时自定义queue选择器。如果可以用key对queue数量取模。
75. 因为一个queue只会被一个consumer消费,所以只要保证一批有序消息放入同一个queue,则消费时一定也是有序的。
76. 延迟等级配置在broker 的 conf/broker.conf 中,等级的数量可以增加。
77. 投递消息到broker时,会先写入commitlog ,再判断其延时等级,如果大于0则表示时需要延时,则创建名为 SCHEDULE-TOPIC-topic名 的topic , 再创建queueId 为延时等级-1
的queue,将消息写入,写入时,原来放 tag 的hash值的地方放上 加上延迟时间后,消息真正应该被消费的时间值。
78. borker 内部有一个ScheduleMessageService , service 中有与等级数相同个数个的timer 定时器,每个定时器负责监控对应queue中的第一条消息是否到达投递时间,如果到了,就按普通消息重新投递一次。就到了普通队列中去了。
79. 批量发送消息,最多不能大于4m ,这个4m是指这批被封装成Message 对象后的大小累计, 不能发送延时消息和事务消息。
80. 批量消费消息,默认情况下,虽然consumer的listener的consumerMessage 中的第一个参数是List 但其实只有一个消息,可以设置Consumer的consumerMessageBatchSize来设置每次消费的条数,最多不能超过32,因为默认每次最多也就拉32条,这个值超过了32,也只能消费32个.如果要修改每次拉取的条数,可以设置consumer的pullBathSize,这个值不宜过大,一是数据量大导致传输时间加长,更容易出现网络错误,二是一旦有某一个消息消费出错,则整一批都算失败.
81. 消息过滤,通过tag过滤或者sql过滤,过滤topic中的消息.
82. 只有push模式的消费类型可以进行sql过滤
83. cousumer 的subscribe方法中可以传tag的过滤参数
84. 生产者生产消息时,可以给Message对象设置一些 key-value 属性.cousumer 的subscribe方法中传入MessageSelector , MessageSelector 中传入类似sql中wehere条件即可过滤.
85. 默认情况下,broker没有开启sql过滤,需要在broker的配置文件中加入 enableProperFilter = true
86. broker启动命令中使用 -c 指定配置文件
87. 生产者发送重试,同步发送和异步发送会失败重试,单向(oneway)发送不会失败重试.
88. produce 可设置重试次数,默认2次.
89. 同步发送下,重试发送时会重新选则另外的broker发送,除非只有一个broker,这种情况下也会选择发到其它的queue.还有失败隔离功能,尽量选择没发生过发送失败的broker发送消息.
90. 异步发送重试时,不会重新选择broker
91. 如果在消息刷盘时失败了,重试时发送其它broker还是不更换时可以在broker中配置的.默认不会现在其它broker
92. 消费重试:对顺序消息的消费,为了保证消费顺序性,如果失败会一直重试,每次间隔默认1秒,这样就会导致系统阻塞,要注意监控并避免阻塞. 所谓消费失败,是指应用中给broker返回了消息失败的状态,所以才会不停的重试.也就是说,这个重试机制,是broker提供的,不是consumer提供的.
93. 消费重试只在集群消费模式下才有.
94. 无序消费最多重试16次,每次间隔时间越来越长,可修改重试次数,但超过16后每次也都延迟2小时.只要修改了一个consumer的重试次数,则整个group都修改,若多个consumer都修改了,则最后一个设置覆盖前面的.达到最大重试次数还没有成功就进入死信队列.
95. 重试队列: 对每个consumerGroup 都有个 %RETRY%-consumergroup-topic名 队列, 消息失败时,先投入要延时时间的一个延时,然后在流入重试队列.
96. 集群消费下,若失败希望重新消费,在可以返回 RECONSUME_LEATER ,或者返回 null ,或者抛异常
97. 不希望重试,返回 CONSUME_SUCESS 就好了
98. 死信队列,消费一直失败后,就发给 %DLQ%-consumerGroup@consumerGroup 私信队列,当某个消费者组出现死信时,就为其创建死信队列,开发人员可以订阅这个死信队列.