消息中间件流水账

JMS 模型

PTP,发送队列,一对一。
发布订阅模式。notify
保存一个连接列表,都是长连接,拥有所有的机器列表,每台机器算一个连接,轮训发送。
数据写入轮询写入,检索消息扫描方式,未来可拓展,加机器不用改变算法。只要有一个订阅着没有收到消息数据就保存。
每个消息都是绑定到固定的server上。notify推给所有订阅者

metaq
写本地磁盘,速度快。
消费者来拉一批去消费。多个消息被同一个订阅者拉走返回一次ACK,效率高。
拉消息不至于像发消息那样造成消息堆积,如线程池满的情况。主动拉会根据自己的情况来拉,相当于一个自身的限流。实时性没有那么高。
rocket mq:

SendMessageProcessor processRequest 处理请求(rocket mq使用netty做io通信)。
sendMessage PutMessageResult putMessageResult = this.brokerController.getMessageStore().putMessage(msgInner);
MessageStore:构造函数会IndexService start;
putMessage,先判断服务是否shutdown,broker是否是slave、broker是否可写、消息长度;各种检查,然后调用commitLog.putMessage
CommitLog:
putMessage:先判断是不是TransactionNotType或者TransactionCommitType,如果是,再看getDelayTimeLevel>0则更改消息的Topic为SCHEDULE_TOPIC
然后调用mapedFileQueue.getLastMapedFile()获取上次的MappedFile,调用其appendMessage并以一个callback为参数传过去
然后MessageStore调用putDispatchRequest(new一个DispatchRequest)

消息写入内存消费队列和磁盘。刷盘失败如果服务器不重启可以正常消费。

判断同步刷盘SYNC_FLUSH,则GroupCommitRequest调用waitForFlush;否则让flushCommitLogService唤醒wakeup,
判断同步双写SYNC_MASTER,则GroupCommitRequest调用waitForFlush;

Producer send 有重试机制。
1.最多三次。
2.这个方法的总耗时时间不超过 sendMsgTimeout 设置的值,默认 10s。所以,如果本身向 broker 发送消息产生超时异常,就不会再做重试。

无法保证一定成功,如果调用 send 同步方法发送失败,则尝试将消息存储到 db,由后台线程定时重试,保证消息一定到达 Broker。

上述 db 重试方式为什么没有集成到 MQ 客户端内部做,而是要求应用自己去完成,我们基于以下几点考虑
1. MQ 的客户端设计为无状态模式,方便任意的水平扩展,且对机器资源的消耗仅仅是 cpu、内存、网络。
2. 如果 MQ 客户端内部集成一个 KV 存储模块,那么数据只有同步落盘才能较可靠,而同步落盘本身性能开销
较大,所以通常会采用异步落盘,又由于应用关闭过程不受 MQ 运维人员控制,可能经常会发生 kill -9 这样
暴力方式关闭,造成数据没有及时落盘而丢失。
3. Producer 所在机器的可靠性较低,一般为虚拟机,不适合存。

要在业务层面去重,有以下几种去重方式
1. 将消息的唯一键,可以是 msgId,也可以是消息内容中的唯一标识字段,例如订单 Id 等,消费之前判断是否在
Db 或 Tair(全局 KV 存储)中存在,如果不存在则插入,并消费,否则跳过。(实际过程要考虑原子性问题,判断
是否存在可以尝试插入,如果报主键冲突,则插入失败,直接跳过)
msgId 一定是全局唯一标识符,但是可能会存在同样的消息有两个不同 msgId 的情况(有多种原因),这种情
况可能会使业务上重复消费,建议最好使用消息内容中的唯一标识字段去重。
2. 使用业务层面的状态机去重

consumer 客户端

创建对象启动一个listener,consumer创建一个MQClientInstance对象。
netty 建立连接 this.mQClientAPIImpl.start();
PullMessageService启动线程,broker数据写入request queue;
从消息队列中取出对象 PullRequest pullRequest = this.pullRequestQueue.take();

posted @ 2017-01-26 23:55  睡死猴  阅读(162)  评论(1)    收藏  举报