题外话:

笔者就职于某上市游戏发行公司,主导整个发行业务线从双 IDC 到腾讯云的搬迁。在此过程中踩了不少坑,便以文章的形式记录下来。

如有错漏之处,敬请指正。

我先简单介绍下我自己:

我是业务开发出身,负责渠道登录/支付业务,熟悉前端,研究后台开发框架后,逐步往运维方向摸索。

业务除了登录/支付业务,也做过风控系统、聊天监控系统,主要是一些防刷保护、敏感词判别、垃圾信息过滤等等。

本系列篇幅较长,共有 7 篇文章,本文是第 6 篇。文章列表:

某上市游戏公司从 IDC 上腾讯云的落地经验(1)——上云必要性与方案设计
某上市游戏公司从 IDC 上腾讯云的落地经验(2)——方案实施之接入层上云
某上市游戏公司从 IDC 上腾讯云的落地经验(3)——方案实施之应用层上云
某上市游戏公司从 IDC 上腾讯云的落地经验(4)——方案实施之缓存层上云
某上市游戏公司从 IDC 上腾讯云的落地经验(5)——方案实施之数据层上云
某上市游戏公司从 IDC 上腾讯云的落地经验(6)——方案实施之中间件上云
某上市游戏公司从 IDC 上腾讯云的落地经验(7)——总结与回顾

中间件上云

中间件这块,我们的 Kafka 没有搬迁,属于大数据业务,目前依然在 IDC 机房。

Elasticsearch 是其他同事跟进,应该也是有同步工具并做 DNS 切换,业务无损。

而 RabbitMQ 这块是我负责上云的。我对它真的是又爱又恨——

  • 爱:RabbitMQ 非常稳定,几乎不需要运维,跑了很久基本不出问题,PHP / Go 都非常友好,用起来比较方便;具备完善的 API 接口和管理界面,方便自己编写脚本实现某些操作的自动化
  • 恨:性能堪忧,腾讯云的 CVM 自建 32 核 64 G内存 HDD * 2 台实例 + 4 层负载均衡,队列开启持久化吞吐量大概在 3 万消息每秒(主备模式);镜像模式下,单队列没有水平扩展的能力,即使关闭持久化,依然存在硬件上的性能瓶颈。

众所周知,RabbitMQ 支持主备模式、镜像队列两种主流的用法。

image-主备模式与镜像模式对比

这两种模式的优缺点如下:

主备模式:架构简单,但节点故障时非常难受,需要手工切换灾备节点(队列元数据需要声明才行,不然会丢数据),一般业务会开启持久化,不做切换时取决于节点何时恢复,不具备高可用的能力。

镜像模式:队列双副本 + 关闭持久化,同样配置吞吐量在 6 万消息每秒,但不具备水平扩展的能力,理论上换 SSD 磁盘会更快,但确实没办法再快了,和 Kafka 没法比。

镜像模式非常好,但是由于公司业务队列非常多,改造需要较长时间。

切换镜像模式需要开发修改其代码和队列声明,特别是持久化这块需要关闭,不然会引发流控

镜像的节点太多,也会导致复制流量巨大,急剧影响集群性能,一定要注意复制的副本数量

思考再三,我最终选择了主备模式。而新业务推动开发使用自建 Kafka(大数据),或者 CKafka(云产品)。

方案也确定下来了:使用两套消息队列,IDC 保留不动,腾讯云再搭建一套主备模式的 RabbitMQ,生产者、消费者两地部署(RabbitMQ 的 API 好用就在这里,根据 API 可以确定生产、消费部署情况),两套 MQ 数据不同步

机房故障时,比如 IDC 故障时可以停止 IDC 机房解析,此时所有流量都在腾讯云,也就是说仅需操作接入层的 DNS 解析即可。

既然说到镜像模式,再说说我对它的看法——

如果是 IDC 和腾讯云跨数据中心的镜像模式,此时生产者、消费者多数是机房单点的,机房故障发生时数据会堆积在 RabbitMQ 里,但是业务不能正常服务。

除非是各个机房都采用独立的集群,每个集群使用镜像模式,每个机房各部署生产、消费者,方能万无一失。

镜像模式的高可用理论上可以满足大部分场景的需求。

但是,极端情况下,业务可能会有消费到重复消息的情况,业务需要保证消息幂等性。

举个例子,A1 和 A2 为镜像队列 A 的两个节点,当 A1 推送到消费者 C 时,此时 A1 发生故障。

C 处理完消息 ACK 到达不了 A1,缺乏重试或者超时也到达不了 A2,A2 无法确定该消息是已经推送了还是 ACK 收不到。

为了保证不丢失消息,A2 会选择再次推送给 C,此时 C 会收到了两次消息——本质上这是 CAP 定理,保证高可用和分区网络的同时,无法做到数据的一致性!

我司由于一些历史原因,业务未能迁移到镜像模式。压测数据出来后,大家还是决定放弃 RabbitMQ 转投 Kafka,而广告业务逐步也往 Java 靠拢,不再使用 PHP 了。

至此,整个上云的过程基本完结,下周再写一篇总结,感谢您的阅读。:)

暂无评论