RocketMQ消费失败消息处理

闲着研究了下RocketMQ消费失败消息的处理逻辑这里记录下,更细化说这里只讨论Push模式(其实实现还是Pull的模式)非顺序消费的情况Pull和顺序消息这里暂时不做讨论哈~(还没研究- -)

消费失败处理逻辑

  • 消费成功的情况RockeMQ会通过移动消费offset位点向前来标示消息已被处理
  • 而对于业务处里失败的消息采用的策略是将消息回发回Broker(并存放到一个%RETRY%XX的topic中), 大家一听可以想到的是回发broker这时候broker挂了怎么办?
  • 回发失败的时候会在本机启动个task来重试..恩 然后这时候consumer机器挂了了怎么办重试没了,难道丢消息?
  • 所以为了保证consumer掉电不丢消费失败且回发失败的消息,代码里保证offsetManage(local or remote)中offset不会前移超过重发失败消息的offset,这样可以保证在下次需要,如果下次consumer活过来时(这时一定会从offsetManage中取offset, 恩其实正常运行中不会每次都取, 顺序消息除外...),一定可以重拉到消费失败的消息(后面会提到这个的代价是会重复拉到很多上次已经消费的消息,不过业务同学的代码都是幂等的,所以逃~)
  • 对于消费失败但回发成功的消息,会直接更新offset假装认为那几条消息已经被消费成功,因为他们已经转生在%RETRY%XX topic里作为新消息等待消费了~当前消费者可以专注于干其他事情.(补充: RERTRY topic实际会带上delay所以实际是先SCHEDULE_TOPIC然后再%RETRY%XX, 这个具体见其他同学关于delay消息的解析~)

可以看到,重发这种模式是不会丢消息的,即使broker挂了,consumer挂了,一定会消费到,虽然可能获得很多不想要的重复消息- -

为啥这么搞

写本文的原因就是我组几个小伙伴都觉得这个很奇怪,为啥这么弄呢~?个人研究了下理解是这样的....(其实自己刚开始研究RocketMQ很多理解可能有问题,欢迎大家一块讨论学习 哈哈哈)

可以冷静看下当前消息消费场景特点:

  • 给了我们一个Queue,访问的时候需要通过一层网络
  • 为了希望消费者能尽快的获得大量消息,结合上条希望consumer更好是一次获取一批而不是一条消息
  • 因为顺序并不重要,consumer本身应该可以并发消费这批消息
  • 因为并发消费消息,不是等上条ok才能消费下一条,就会有ack先后顺序问题
  • 为了server端ack应该是高效的,每条记录一个状态 vs 已成功offset?
  • 更进一步,获取获取第二批消息能否需要等待上一批消费完成? 其实没必要只要消费者有空闲线程可以先抓过来消费第二批,虽然第一批里某几条处理比较慢,但多数情况下应该能不会一会就恢复,其他线程先干第二批的活, 所以拉取和处理应该分离
  • 其实从上条可以看出对于抓取的速度应该根据消费者处理能力来控制~如果消费还有闲的可以疯狂的从Queue中先抓过来,只要不把没处理成功的给ack掉;如果消费者已经严重delay无力处理则需要降低抓取速度

完整处理

感觉RocketMQ处理这部分的代码挺巧妙...几个核心参与类:

  • ConsumeQueue: Consumer角度消费的一个Queue(有些类似kafka里partition的概念, 一个Queue只会被一个consumer消费,虽然一个consumer可以消费多个Q)
  • PullRequest: 当前consumer下已分配的每个ConsumeQueue消费者端都会新建一个PullRequest,里面记录nextOffset即从Server拉取offset拉取offset消费offset是两个offset才能第一批没消费完就拉第二批; 这个Request会在rebalanceService中创建,并被多次更新nextOffset多次进入PullRequestQueue来达到持续拉取的循环效果- -(也会被延迟丢Q来控制速率)
  • PullRequestQueue: 一个内存队列,充当PullMessageService的入参
  • PullMessageService: 负责拉取消息的拉取线程,不停的读取PullRequestQueue根据request拉取消息,然后将消息丢到ProcessQueue中并新建ConsumeRequest提交到ConsumeService处理, 然后生成下一批的PullRequest丢到PullRequestQueue:继续消费下一批,达到持续循环拉取的作用
  • ConsumeRequest: 虽然叫request但除了要consume的消息数据外,还有具体的消费逻辑(是个Runnable- -); 关键元素就是这批要处理msg列表对这批消息的处理逻辑,run里会调用用户注册的listener,并根据处理情况,对失败消息回发,并根据失败和回发结果, 更新ProcessQueue以及OffsetStore
  • ProcessQueue: 又一个内存队列保存实现是TreeMap,在处理中的消息,处理处理成功或处理失败但回发成功都会从这个Queue中移除,消费offset的上报基于ProcessQueue中最小的offset来完成(所以失败未回发成功的不会被移除);另外在ProcessQueue里最大offset和最小offset过大(MaxSpan)时,前面的PullMessageService会减速等一会在基于运行抓取(等一会儿再往PullRequestQueue里扔消息).
  • ConsumeService: 一个ConsumeRequest的Executor可以理解为一个线程池
  • OffsetStore: 维护消费offset(即offset之前都处理完成)
  • RebalanceService: 负责给consume分配queue,而对于目前讨论过程他的作用是初始化了了对应的PullRequestQueue和首次的PullRequest, offset从offsetStore获取

简单画了个图说明上面几个类的关系~(手指在ipad上画得没有笔所以特别难看- -先将就吧)

Notes - Page 1.png

失败重试的细节好像没画出来,= = 画图不好画。。结合上面描述看代码哈~- -

最终达到的效果

  • 从Server是批量拉取的
  • 拉取线程不需要等待上一批被处理就能开始拉取下一批,只要ProcessQueue没超MaxSpan(也就是消费某几条卡主太久), 就可以一直拉取
  • 消费listener可以并发消费,并各自返回完成状态, 部分消费者卡一段时间不影响其他消费者消费
  • Consumer保证实际消费端offset保证offset之前必须是已处理成功或处理失败但已回发成功
  • 回发不成功会本地重试且远端offset不会前移
  • 如果重启或被新分配队列会从offsetStrore获取初始offset,所以可能会有不必要的重复消息,所以消息处理需要做好幂等

总结

  • 可以批量,且拉取和处理分离,同时保证不丢数据,提升效率同时代价是重复消息
  • 通过只记录offset提升ack效率(可以一次ack一批,并且不用每条记录记录状态)
  • 通过分离拉取offset(in PullRequest)和消费offset(in OffsetStore)分离拉取和处理进度,提升拉取效率,并根据消费者处理卡主情况做拉取阀值控制
  • 通过回发消息加速批次中其他已处理成功消息的ack消费offset,如果不回发那消费offset不能迁移,重启之类会导致更多的消息重发, 而有回发后只要回发成功了就可以前移offset(反正不关心顺序只要求效率)
  • 对于回发失败,只能不前移消费offset。。。然后通过本地重试做非consumer宕机情况的优化
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,560评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,104评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,297评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,869评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,275评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,563评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,833评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,543评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,245评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,512评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,011评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,359评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,006评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,062评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,825评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,590评论 2 273
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,501评论 2 268

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,099评论 18 139
  • Kafka入门经典教程-Kafka-about云开发 http://www.aboutyun.com/threa...
    葡萄喃喃呓语阅读 10,748评论 4 54
  • 项目4月份发版,直接需要整合kafka,今天开始学,一个月内完成kafka的部分。 资料来源:http://www...
    MisterCH阅读 1,701评论 0 4
  • 【卓越背后的力量】[太阳] 中国某著名商学院的教材里, 玫琳凯作为了2016年度 《组织行为学》的教案, 这已经不...
    高露予首席阅读 2,589评论 0 4
  • 1、弹出屏蔽罩一般用在提示用户一些重要信息,和系统自带的UIAlertController起到一样的效果,只不过自...
    紫荆秋雪_文阅读 120评论 0 0