双 11 即将来临,在我们开心“剁手”的背后,是电商万亿条消息的流量洪峰,那么电商平台是如何安全应对大促的呢?今天我们邀请到京东零售技术架构部任架构师李玥,以京东的消息中间件 JMQ 为例,剖析电商大促背后的 MQ 应对流量洪峰的秘诀。
2019 年“618”大促,京东的消息中间件 JMQ 集群,全天收发消息 1.5 万亿条,流量达到 1.2PB,相比去年的“11.11”,业务量增长一倍,而集群的服务器数量维持了去年的规模,没有增加一台服务器,并且这个流量还远没有达到我们预测的极限,JMQ 集群仍然维持原有集群规模,支撑今年“11.11”新一波的流量洪峰。
不可否认,足够强大的处理能力是支撑大促流量洪峰的基本要求。不过除此之外,在多次大促过程中,JMQ 团队仍然遇到并解决了一些实际问题,本文我将为大家分享京东的消息团队应对大促过程中遇到的一些问题和解决方案。
1. 如何安全应对大促的流量洪峰?
核心关键词:预留资源的比率、超大规模集群
分片(Sharding)思想几乎是分布式系统应对海量数据的唯一法宝。很多消息中间件系统在面对海量数据的时候,也都是采用分片思想,整个大集群由多个互不相关的小集群组成,每个小集群承担一部分主题。但是,这种分片设计在面对大促这种场景的时候,它的资源利用率并不好。
为了能确保安全应对大促的流量洪峰,一般的做法是,事先依据历史数据和经验值,预估大促期间的峰值数据量,再预留一定的余量,用于应对流量突然增长和预估偏差。以这个数据量作为资源分配的依据。采用多个小集群的分片设计时,由于每个分片是完全独立的,并且这些预留资源无法共享,所以,每个分片都需要预留足够的资源。
面对大促这种场景,集群规模越大,预留资源的比率就可以做得越低。为什么呢?对于大集群来说,虽然预留的资源比率很低,但由于集群本身规模大,所以预留资源的绝对数量并不少。而且这些预留资源可以给集群内所有主题共享,相比于分片设计的每个小集群,预留的资源总量反而是更多了。考虑到实际大促期间,真正需要用到预留资源的主题毕竟是少数(但我们很难预测哪些主题会用到预留资源),所以集群规模越大,预留资源的比率就可以越低,资源的利用率也就更高。
JMQ 采用单个超大规模集群的设计,所有的主题都在同一个大集群中,大促期间,预留资源的比率可以做到 5% 左右。
2. 如何解决超大规模消息集群的热点问题?
核心关键词:去中心化
对于消息中间件,构建超大规模集群,主要面临的是 NameServer 的热点问题。所有的客户端在收发消息之前都需要连接 NameServer 寻址,所有的 Broker 也都需要连接 NameServer 读写集群元数据。当集群规模太大时,NameServer 本身就会成为一个系统瓶颈。
如何解决这个问题呢?在设计层面,JMQ 采用去中心化的设计来解决这个问题。在 JMQ 中,每一个 Server 节点都是对等的。Server 节点既是 Broker 也是 NameServer,所有的 NameServer 节点构成一个分布式的存储系统用于存储元数据。客户端可以连接任意一个 Server 节点获取路由数据,这样集群中就不再存在 NameServer 热点问题。
在实际应用中,没有必要让一个大集群的每个节点都来充当 NameServer,这样元数据过于分散,也不便于运维。只要 NameServer 节点的数量足够多,能够支撑所有客户端请求就可以了。
目前 JMQ 的集群约有 2000 多个 Server 节点,我们选择了分布在全国多个机房的 7 个节点兼做 NameServer,可以很好的解决大集群的热点问题。
3. 如何处理大促期间的积压消息?
核心关键词:扩容消费者集群、一次性转移积压消息
由于 JMQ 本身的性能远远超过使用 JMQ 的上下游业务系统,所以大促期间几乎不会发生由于 JMQ 本身的性能不够而导致的数据积压。比较常见的问题是,消费者消费消息的速度跟不上消息生产的速度,导致消息积压。
一般来说,消息积压不需要处理,因为 JMQ 本身就起到一个解耦上下游系统和削峰填谷的作用。但是,在大促期间,如果某个主题的积压数持续快速增长,就必须迅速人工干预,否则 Broker 的磁盘会被积压的消息占满。磁盘满导致的后果是:不仅积压主题对应的生产者发送消息会失败,还会影响到同 Broker 的其他主题。
要解决这个问题,一个可行的思路是给每个主题分配一个固定的磁盘配额,这样虽然可以避免某个主题占满磁盘而影响其他主题。但是,带来的问题和上面我们说的小集群是一样的:资源的利用率必然会下降,在资源利用率和隔离性之间,JMQ 选择了牺牲隔离性换取更高的资源利用率。
解决消息积压的常规手段是,对消费者集群进行扩容,同时主题的分区数也需要一并扩容,用更多的并发数量来提升消费者集群整体的处理能力,一般扩容之后,积压数就不再增长了。但是,新扩容的消费者实例对应着新扩容的分区,对于有消息积压的这些老分区来说,消费者的数量并没有增加,消费能力并没有提升,积压的消息并不会很快的被消化掉。
如果积压消息不能迅速消化掉,对于消费者来说会出现新旧分区冷热不均的问题。对于新生产的消息来说,如果打到新分区上就会被很快消费掉,如果打到旧分区的消息就要等很久才会被消费,这会在有些业务系统中导致一些奇怪的问题。
针对这个问题,JMQ 的解决方法是,把积压的消息一次性地转移到一个临时主题中去,消费方可以再临时启动一些消费者实例来消化这部分积压的消息。这样就可以迅速消化掉已经积压在 JMQ 中的这部分消息,不让这些积压消息影响后续的生产和消费。
很荣幸生在了如今这个技术空前繁荣的互联网时代。开放、分享和交流一直是技术圈儿所崇尚的精神。这使得我们可以站在无数技术前辈的肩膀上,来构建京东的消息中间件 JMQ。所以,作为这种分享精神的受益者,我们也非常愿意将这些应对大促的技术经验分享给所有人,希望你们能从中取得一些收获。