实时通讯系统的消息队列中间件选型对比

实时通讯系统的消息队列中间件选型,我是怎么思考的

去年有个朋友问我,他们公司要做实时通讯系统,消息队列中间件到底该怎么选。这问题把我问住了,因为市面上方案太多了,每个都说自己很厉害,但实际用起来完全是另一回事。我花了小半年时间研究,又跟业内几个朋友聊了不少,今天把我了解到的分享出来,希望能帮到正在纠结的你。

在实时通讯领域,消息队列就像整个系统的血管,消息能不能及时送达、能不能支撑高并发、出了问题好不好排查,都跟它有关。特别是像我们声网这种做全球实时音视频云服务的,每天要处理海量的消息,消息队列选错了,后续全是坑。

先搞明白你的业务需要什么

我见过太多团队一上来就问"哪个消息队列最好",其实这个问题本身就有问题。应该先问"我的业务场景是什么样子的"。

举个简单的例子,如果你是做即时通讯的,比如聊天工具,那消息的可靠性就是第一位,用户发的消息不能丢、不能乱序,要是同时支持已读未读状态,消息队列还得能记住每条消息的状态。这种场景下,消息的实时性要求反而不是极端的高,延迟个几百毫秒用户基本感知不到。

但如果你是做直播互动的,那就是另一回事了。直播间里观众发的弹幕、点赞、礼物特效,这些消息需要在极短时间内让所有人都看到。想象一下,你给主播刷了个火箭,结果其他观众半天才看到,这体验就太差了。这时候消息的低延迟高吞吐量比可靠性更重要,偶尔丢一条弹幕问题不大,但延迟高了立刻就被用户骂。

还有一种场景是社交1V1,比如视频交友应用。这里有个关键指标叫"秒接通",用户点了匹配,系统得在几百毫秒内把双方连上。这背后涉及到信令的快速传递,消息队列不仅要快,还要能支撑瞬间的高并发请求。两个人匹配成功的那一秒,可能同时有几十条消息要发出去,消息队列能不能扛住,直接影响用户会不会流失。

所以在选型之前,建议大家先回答这三个问题:第一,我的消息需不需要保证100%送达;第二,我预期的峰值并发量是多少;第三,我对延迟的容忍度是多少。把这三个问题想清楚了,选型的思路就清晰多了。

主流方案我挨个聊一聊

市面上常用的消息队列大概有五六种,我挑几个最主流的说说我的理解和实际使用感受。

Redis:轻量级选手

Redis严格来说不算完整的消息队列,但它自带Pub/Sub功能,很多小团队做即时通讯的时候首选它。优点太明显了,部署简单、性能超高,延迟能压到毫秒级以下,而且跟现有的缓存系统可以复用,不用单独维护一套东西。

但Redis的坑也不少。它的Pub/Sub模式没有消息持久化,一旦消费者下线,再上线就收不到之前发的消息了。还有就是它的数据结构导致的消息堆积问题,如果生产者发消息的速度比消费者快,内存很快就会被打爆。另外Redis是单线程架构,理论上单实例的吞吐量有上限,高并发场景下可能需要做集群,但集群版本的管理复杂度就上去了。

我的建议是,如果你的系统消息量不大、日活就几万用户,而且主要是点对点聊天,用Redis没问题,省心省力。但如果你的用户量到了百万级以上,或者有复杂的业务逻辑需要处理,还是考虑更专业的方案。

RabbitMQ:老牌选手

RabbitMQ在消息队列领域算是老前辈了,沉淀了很多年,文档丰富、社区活跃,有什么问题基本都能搜到答案。它最厉害的是路由功能,支持多种交换器类型,可以根据不同的规则把消息发到不同的队列,这在业务复杂的时候非常有用。

比如说,你的系统里有普通聊天消息、系统通知、用户状态变更消息,这三类消息的消费者完全不一样,用RabbitMQ的Topic交换器,一条消息可以同时发给多个消费者,互不干扰。再比如你需要保证消息的可靠传递,它支持消息确认机制,消费者没处理完消息就下线,消息会重新投递给其他消费者,不会丢失。

但RabbitMQ的性能就没那么亮眼了,特别是在高吞吐量场景下,单节点的QPS大概在几万级别,想提升吞吐量就得做集群和镜像队列,但集群版本的运维复杂度不低。而且它的消息堆积能力也一般,如果消费者突然全部宕机,消息很快就会把内存撑满。

如果你需要复杂的路由逻辑、可靠的消息传递,或者团队对RabbitMQ比较熟悉,用它是比较稳妥的选择。我们声网在一些需要可靠消息传递的业务场景下,也会用到RabbitMQ。

Kafka:性能怪兽

Kafka这些年越来越火,特别是在大数据领域几乎是标配。它最初是LinkedIn为了处理日志数据开发的,天生就适合高吞吐量的场景。官方说单机就能达到百万级TPS,虽然实际使用中可能要打点折扣,但这个数字已经让其他方案望尘莫及了。

Kafka用的是顺序写盘的方式,再加上零拷贝技术,把消息从磁盘读到网络发送出去,中间只需要两次内存拷贝,这性能优化也是没谁了。而且它的消息持久化能力很强,消息存在磁盘上,几天几个月都不会丢,想回溯历史消息也很方便。

不过Kafka用起来没那么友好,它的配置参数特别多,什么副本因子、ISR、acks、retries,新手很容易懵。而且它的消息模型是追加写,消息一旦写入就不能修改,想删除消息只能等过期或者手动清理。另外它没有消息确认机制,消费者自己负责记录消费到哪了,这对于简单业务来说增加了复杂度。

高吞吐量场景下Kafka是首选,比如直播弹幕、实时数据采集、日志收集这些。但在即时通讯这种需要精确控制消息状态的场景,Kafka就不是那么顺手的工具了。

Pulsar:新兴力量

Pulsar是近几年冒出来的新选手,架构设计上有很多创新之处。它把消息存储和消息服务分开了,存储用BookKeeper,服务用Broker,这样扩容、故障恢复都更灵活。而且它支持多租户跨地域复制,这对大企业来说很有吸引力。

我特别欣赏Pulsar的消息保留策略过期删除机制,配置起来比Kafka简单很多,不用折腾那些复杂的参数。它还有函数计算的能力,可以在消息到达时直接做一些简单的处理,不用再单独起一个消费者服务。

不过Pulsar的社区毕竟比Kafka和RabbitMQ小一些,遇到问题可能没那么容易找到答案。而且它的Java客户端有些历史包袱,用起来稍微有点别扭。但总体来说,Pulsar是个很有潜力的选手,值得关注。

我做了什么选择

前面说了这么多方案,不是让你随便选一个就行,而是要根据自己的实际情况来。我们声网在全球有那么多开发者用户,场景也各不相同,自然不可能用一种方案打天下。

对于实时性要求极高、消息量极大的场景,比如直播互动、秀场直播里的弹幕和礼物特效,我们用的是Kafka。没办法,这种场景下TPS就是硬指标,撑不住就会出事故。延迟稍微高一点,用户立刻就能感知到。

对于需要可靠传递、路由复杂的场景,比如用户之间的即时消息、系统通知、已读未读状态管理,我们用的是RabbitMQ或者类似的方案。这种场景下消息不能丢,路由规则也复杂,RabbitMQ的灵活性能派上用场。

还有一些轻量级的场景,比如用户上线状态变更、简单的指令下发,我们直接用Redis Pub/Sub就搞定了,简单高效,没必要搞得太重。

其实在选型这件事上,没有绝对的对错,只有合不合适。很多团队一开始用Redis,后来业务发展起来了再迁移到Kafka,这个过程虽然麻烦,但也是必须的。重要的是要了解每个方案的优缺点,知道什么时候该换方案,别一条道走到黑。

几个血泪教训

最后说几点我踩过的坑,希望大家能避开。

第一,别高估自己的运维能力。有些团队一看Kafka性能好,二话不说就上了,结果集群三天两头出问题,排查半天发现是配置没调好。技术选型要结合团队的实际能力,如果你们之前都没接触过Kafka,还是先用熟悉的方案过渡一下,别为了追求先进技术把自己逼到墙角。

第二,早期也要考虑扩展性。我见过一个团队,一开始用户量小,选了RabbitMQ,后来用户量翻了几倍,RabbitMQ撑不住了,想迁移到Kafka,结果发现数据结构不兼容,迁移成本特别高。所以在设计消息格式的时候,就要考虑以后可能要换方案,别把业务逻辑写死在某种消息队列的特性上。

第三,监控和告警一定要做好。消息队列出问题,往往是业务已经受到影响了才发现。如果你的消息队列没有完善的监控体系,不知道积压了多少消息、延迟有多高,等到用户投诉就晚了。我们声网在这方面吃过亏,后来把所有核心指标都接到了监控大屏上,有异常立刻告警,这个投入是值得的。

写在最后

选型这件事,说到底是要平衡。性能和可靠性要平衡,复杂度和易用性要平衡,团队现有能力和未来需求也要平衡。没有完美的方案,只有最适合当下阶段的方案。

如果你正在为消息队列选型发愁,不妨先想清楚自己的业务场景是什么,预期规模有多大,团队能驾驭什么样的技术。然后找个周末,把几个候选方案都搭起来跑跑压力测试,感受一下哪个用起来最顺手。实践出真知,看十篇评测文章,不如自己动手试一试。

希望这篇文章能给你一点参考。如果你有什么想法或者自己的经验分享,欢迎一起交流。

上一篇实时消息 SDK 的版本迭代周期是多久
下一篇 实时消息 SDK 的性能优化建议有哪些

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱:

工作时间:周一至周五,9:00-17:30,节假日休息
关注微信
微信扫一扫关注我们

微信扫一扫关注我们

手机访问
手机扫一扫打开网站

手机扫一扫打开网站