RocketMQ 在同程旅行的落地实践
本文作者:刘树东 - 同程艺龙技术专家
01/使用概况
同程旅行选择RocketMQ主要基于以下几个方面的考虑:
技术栈:公司主要以 Java 开发为主,因此我们倾向于选择一款用 Java 实现的MQ,且没有任何第三方依赖为最佳;
久经考验:Rocket MQ 经历了阿里双11考验,性能、稳定性得到了充分验证;
功能实用:RocketMQ 的发送端提供改了同步、异步、单边、延时发送的功能;消费端有重试队列、死信队列以及消息重置功能,非常方便实用。
综合以上三点,我们选择了 Rocket MQ。
Rocket MQ 在同程旅行的使用场景有削峰、解耦、异步处理以及数据同步等。目前已经在公司各大业务线的核心系统里得到广泛使用,承受了来自微信入口的巨大流量,每天有1000+ 亿条消息周转。
同程旅行RocketMQ 框架图如上。机票、交通和酒店三大业务线通过 Java SDK 以及Http Proxy 的方式接入到 MQ 集群。其中Http Proxy 主要为了方便其他语言客户端使用;同时为了更好地实现资源隔离,我们将后端服务端节点按照业务线做了物理隔离,能够最大程度地确保业务线之间不会互相影响。整个 MQ 集群通过 MQ 服务平台进行治理。
02/同城双中心
同城双中心主要为实现以下三个目标:
单机放故障时保证业务可用
保证数据可靠
横向扩容
外部用户请求经过 LVS 以及 Nginx 调用服务与应用,应用底层主要调用了 MySQL、Redis 以及 MQ,双中心可分为同城冷备和同城双活两个方案。
同城冷备有两个 MQ 集群,分别是 source 集群和target 集群。生产者会将消息生产到 source 集群,之后经过消息同步集群将 source 集群里的元数据比如 topic、消费组、消息等同步给 target 集群。source 集群和 target 集群中的消费者都可以进行消费。
同城双活我们建立了跨中心的全局 MQ 集群。用户流量分散到两个中心,每个业务会将生产的消息往自己中心的 MQ 写。同时,其他服务与应用会从本中心消费所需消息。
当出现单机房 broker 节点故障时,每组 broker 的两 slave 位于不同机房,至少有一台 slave 拥有近乎全量的数据;消息生产会跨机房到另一个机房,另一个机房的消费者继续消费。
简单对比下,同城冷备方案需要 source 和target 两个集群,因此资源使用率不高,还需要同步 topic 、消费组、消费进度等元数据;同城双活方案资源使用比较合理,业务流量在何处,就在该处进行生产与消费消息。
同城双活有以下三点诉求:
①就近生产:生产端在A机房,则生产的消息也存于A机房的 broker。
②就近消费者:消费者在A机房,则消费者消息也来自A机房的 broker。
③broker 主节点故障,能够实现自动的选主。
就近生产与就近消费的核心问题是如何识别客户端与服务端是否在同一机房。识别客户端所在机房可以通过两个途径:
第一,获取客户端所在IP,然后通过第三方组件解析出 IP 所属机房;
第二,与运维人员配合,在每一台容器或物理机里设置环境变量,通过读取环境变量来感知客户端所在机房。比如从环境变量里读取到逻辑机房的 ID或逻辑机房的名称。
识别服务端机房有三种途径:
第一,通过 IP 查询,解析IP 段属于哪个机房;
第二,服务端节点向元数据节点注册时,在协议层增加机房标识;
第三,在 broker 名字上增加机房标识。
就近生产的原则:优先就近生产,就近生产无法满足时则跨机房生产。
如果机房后端的服务节点可用,则生产端会将消息生产到各自的机房里。如果机房的所有 broker节点都不可用,则生产端会将消息投递到另一个中心的 broker。
两个机房消费端都正常的情况下,每个机房的消费端只会消费本机房的消息。
如上图,如果idc 2 的消费端全部故障,则所有消息会被另一个机房idc1的消费端消费。
为了实现就近消费,我们实现了按机房分配队列算法:
每个机房的消息会平均分给此机房的消费端;
如果机房没有消费端,则消息会平均分配给其他机房的消费端。
故障切主的实现步骤如下:
第一步:Nameserver 基于 raft 协议选主;
第二步:所有 broker 向 Nameserver leader 节点注册,leader 节点将 broker 的注册信息同步给其他 Nameserver 节点;
第三步:broker主节点出现异常时,由Nameserver 负责从剩下的 broker节点里重新选主节点;
第四步:此时生产端无法向旧broker leader发送消息。如果旧 broker的主节点复活,则会自动切换成从节点。
Nameserver 元数据系统有一主多从,broker 有一台 master 与两台 slave。如果 master 故障,则 Nameserver 元数据系统会从 slave1 与 slave2 中根据一定的条件,比如根据同步进度或版本号选出新主,上图为将 slave2 选为主。之后新主会向 nameserver 元数据系统注册,并将版本号+1。如果旧主复活,因会其版本号小于新主版本号被切为 slave。
在生产环境中实际操作了双中心演练,具体流程如下:
1)14:30开始切域名,将流量切到一个机房(二中心)。三四分钟后,二中心的流量已超过一中心,一中心的流量趋近于零;
2)15:00左右,将流量回归双中心;
3)15:30左右,又将流量切回一中心。可以清晰地看到,在流量切到一中心时,二中心的消息生产趋近于0。
整体来看,双中心的演练较成功,实现了消息的生产跟着流量走。
简单总结下,双中心方案为跨机房建立了全局MQ集群,生产与消费都遵守优先就近原则,配置一主二从,一主一从消息写成功即认为消息写入成功。Nameserver 通过 Raft 协议选主,选完主后会监控每一组里 broker 的 leader 节点。如果 broker 的 leader 节点出现故障,则会从这一组剩下的 slave 里选新的主节点。
03/平台治理
平台治理至关重要,可以让环境变得更加稳定可靠,出现异常时可以及时向使用方发出告警,出现故障时可以快速定位。MQ 的平台治理分为主题消费组治理、客户端治理以及服务端治理。
主题消费组的使用按照先申请后使用的原则,出现问题时可以根据主题与消费组的申请人找到该主题。MQ 环境分为很多种,可以一键申请所有环境或只限制生产环境的申请,将其他环境的申请放开。对于主题而言,我们给每一个主题限制了最大生产速度,防止单一主题生产过快从而影响其他主题的生产。
消息堆积到一定阈值时,可以向业务方发出告警,通知其处理;长时间不处理可以取消消费组的消费权限或重置消费进度,防止因消息大量堆积而影响生产与消费。若消费端节点掉线一定时间之后没有重新上线,可向业务方快速发布告警,通知其及时处理。
客户端治理主要执行一些统计与检测工作,会统计每一条消息的生产消费耗时、消息大小、重复消费的次数。如果生产/消费端版本过低或当前版本存在 bug ,也可以向业务端发出通知。
这一系列的统计和检测最终需要为消息的全链路追踪服务。统计和检测会记录消息相关信息,包括每一条消息在哪个时间点、从哪个业务IP与端口号发送到服务端的哪个节点、于什么时间被哪些服务的消费端在什么时间点消费,以及消费耗时、消费的重复次数等信息,可以很方便地排查所需信息。
服务端治理负责集群的自我保护、集群健康巡检、集群性能巡检和集群高可用。集群的自我保护主要针对生产与消费,尤其是生产的消息过快或有大量消息积压时;性能巡检可通过实时发送一批不同大小的消息来检测生产和消费的情况;集群的高可用指出现故障时,服务平台能及时发出通知。
通过几张图展示下实际的治理,在 MQ 服务平台上,可以申请 topic 和消费组的上线、下线以及权限。
上图展示了每个集群每分钟的消息生产消费以及堆积曲线。
MQ 平台还提供了集群监控的功能,可以查看当前集群 topic 、消费组织数量、消息的intps、outtps 以及 broker 的数量。同时,可以查看每一台 broker 消息生产排名以及消息积压排名,方便故障时的问题排查。
使用 Rocket MQ 的过程中,我们也踩了不少坑。
1)做双中心版本升级时,没有考虑到版本的向下兼容,队列的分配算法有问题,导致部分消息被重复消费多次,部分消息没有被消费;
2)某一台 broker上主题消费组数量过多时,会导致 Nameserver 注册耗时过长。如果很多 broker 上的主题消费组都很多,就会导致broker的内存 OOM;
3)由于 topic 长度判断不一致导致服务端重启时会丢失少量消息;
4)broker 进程会假死,后证实为os版本问题,升级os版本即可解决。
04/未来展望
同程旅行针对 RocketMQ 的未来规划分为以下三个方面:
第一,历史数据归档。很多业务方对数据的反查要求周期较长,而线上生产环境的消息实际的存储时间可能只有2-3天,我们将考虑从历史归档数据里查询;
第二,底层存储剥离,计算与存储分离。目前社区新版本已经支持该能力;
第三,期望利用沉淀的历史数据帮助业务完成更多数据预测,比如订单量、退改量等数据的预测可以更好地帮助业务解决问题,同时也可以为业务机器做扩缩容提供支持。
RocketMQ 在同程旅行的落地实践的更多相关文章
- 基于消息队列 RocketMQ 的大型分布式应用上云最佳实践
作者|绍舒 审核&校对:岁月.佳佳 编辑&排版:雯燕 前言 消息队列是分布式互联网架构的重要基础设施,在以下场景都有着重要的应用: 应用解耦 削峰填谷 异步通知 分布式事务 大数据处理 ...
- Dubbo Mesh 在闲鱼生产环境中的落地实践
本文作者至简曾在 2018 QCon 上海站以<Service Mesh 的本质.价值和应用探索>为题做了一次分享,其中谈到了 Dubbo Mesh 的整体发展思路是“借力开源.反哺开源” ...
- 滴滴出行基于RocketMQ构建企业级消息队列服务的实践
小结: 1. https://mp.weixin.qq.com/s/v6NM3UgX-qTI7yO1QPCJrw 滴滴出行基于RocketMQ构建企业级消息队列服务的实践 原创: 江海挺 阿里巴巴中间 ...
- [转载]DevOps在传统企业的落地实践及案例分享
内容来源:2017年6月10日,优维科技高级解决方案架构师黄星玲在“DevOps&SRE 超越传统运维之道”进行<DevOps在传统企业的落地实践及案例分享>演讲分享.IT 大咖说 ...
- DEVOPS落地实践分享
DEVOPS落地实践分享 转载本文需注明出处:微信公众号EAWorld,违者必究. 引言: DevOps的理念已经说了很多年,其带来的价值逐渐被接受,很多企业也逐渐引入了DevOps.目前普元DevO ...
- MOT大连站 | 卓越研发之路:前沿技术落地实践
还在讨论究竟哪种编程语言更容易深度学习?哪种编程语言更具有价值?如果你是资深技术人员又或者是团队负责人,在机器学习.微服务.Spring 5反应式编程等方面遇到了问题,不妨参加一场由msup和微软联合 ...
- python-编程从入门到实践
python-编程从入门到实践 1.python文件后缀名: .py 是Python的源码文件,由Python.exe解释. .pyc 是Python的编译文件.pyc 文件往往代替 py 文件发布: ...
- SpringCloud落地实践
这几年微服务架构越来越火.伴随着微服务概念的提示,越来越多的组织为了方便开发,结合实际提供很多微服务机构, 之前工作中一直使用dubbo作为微服务框架, dubbo只是专注于服务之间的通讯,所以更灵活 ...
- python coding style guide 的高速落地实践
python coding style guide 的高速落地实践 机器和人各有所长,如coding style检查这样的可自己主动化的工作理应交给机器去完毕,故发此文帮助你在几分钟内实现coding ...
- python coding style guide 的快速落地实践——业内python 编码风格就pep8和谷歌可以认作标准
python coding style guide 的快速落地实践 机器和人各有所长,如coding style检查这种可自动化的工作理应交给机器去完成,故发此文帮助你在几分钟内实现coding st ...
随机推荐
- django_day01
内容回顾 django处理浏览器的请求流程: 请求发送到wsgi wsgi封装了请求的相关数据(request) django去匹配路径 根据路径判断要执行哪个函数 执行函数 函数执行具体的业务逻辑 ...
- 第十篇:vue.js for循环语句(大作业进行时)
Vue.js 循环语句 <div id="app"> <ol> <li v-for="site in sites"> /*f ...
- vim编辑器使用详解
Linux之vim编辑器使用 vim三种模式:命令模式,插入模式,退出模式 移动光标操作 左移动一个字符: 按 h 键 右移动一个字符:按 l 键 下移动一行:按 j 键 上移动一行:按 k 键 移动 ...
- 利用userfaultfd + setxattr堆占位
利用userfaultfd + setxattr堆占位 很久之前便看到过这个技术的名字,但是由于自己的摆烂,一直没有管.今天终于找到时间好好看一下这个技术的利用方式.利用userfaultfd + s ...
- 怎么用vscode创建工程
以下内容为本人的学习笔记,如需要转载,请声明原文链接微信公众号「englyf」https://www.cnblogs.com/englyf/p/16685082.html vs code创建工程,以k ...
- OKR之剑(理念篇)01—— OKR带给我们的改变
作者:vivo互联网平台产品研发团队 一.前言 OKR即目标与关键成果法,起源于英特尔,在谷歌发扬光大.近几年在国内比较火,很多企业都相继引入了OKR的管理方式,小到2-3人的小微初创公司,大到十几万 ...
- Windows 10无法显示无线网络连接
最近刚刚升级了一下操作系统,升级到了1903版本.正好又有一个HP的打印机安装了一下.结果,发现居然无法管理无线网络了.如果看不到图,请点我. 右击选择连接,也无法显示SSID. 驱动是从这个官网下载 ...
- 使用Watchtower实现Docker容器自动更新
前言:通常情况下我们手动更新容器的步骤比较繁琐,需要四个步骤: 1.停止容器 2.删除容器 3.检查镜像更新情况,更新镜像 4.重新启动容器 容器少还无所谓,但要是需要更新大量的容器就会工作量巨大. ...
- k8s上安装安装 Ingress Controller &卸载
在 master 节点上执行 nginx-ingress.yaml文件内容 # 如果打算用于生产环境,请参考 https://github.com/nginxinc/kubernetes-ingres ...
- Fluent插件管理
官方文档地址:https://docs.fluentd.org/deployment/plugin-management 命令fluent-gem是Fluentd用来安装插件的,它是gem命令的包装器 ...