微信后台异步消息队列的优化升级实践分享

1、引言

MQ 异步消息队列是微信后台自研的重要组件,广泛应用在各种业务场景中,为业务提供解耦、缓冲、异步化等能力。本文分享了该组件2.0版本的功能特点及优化实践,希望能为类似业务(比如移动端IM系统等)的消息队列设计提供一定的参考。

2、背景介绍

微信后台给件 MQ 1.0 发布之初,基本满足了一般业务场景的异步化需求,实现了单机下高性能的任务持久化和消费调度。

MQ 1.0 的基本框架如下图所示:

可以看到,其主要分为 MQ 和 Worker 两部分。MQ 是任务的持久化和调度框架,Worker 是任务的处理框架。

下面对各个优化点详细讲解。

3、需要实现更优的任务调度

1现状分析

iOS消息通知功能,是MQ组件的一个典型应用场景。微信的后台具有多IDC分布的特点,不同IDC与苹果推送服务(APNs)之间的网络质量参差不齐,部分链路故障频发。

由于MQ 1.0 的任务只能本机消费,网络质量的下降将直接导致 Worker 消费能力的下降,进而产生积压,最终使消息服务质量受损。 为此,我们提出了跨机消费模式。其目标是实现一个去中心化、自适应的弹性消费网络,以解决系统中出现的局部积压问题。

2任务调度是跨机消费的核心问题

下面逐一进行讨论。

3拉任务还是推任务

MQ 1.0 下,MQ 可以准确观察到本机 Worker 的负载状态,并由其将任务推送给空闲的 Worker 进行处理。推送的方式可以将任务的处理延时做到极低。 扩展到跨机消费后,Worker 可以消费任意 MQ 的任务。对 MQ 而言,已经难以精确地维护全网每个 Worker 的状态了。若继续沿用推任务的方式,很可能会出现 Worker 接收到超过其处理能力的任务量,从而产生积压。

4Worker 如何感知 MQ 的积压

前面提到,系统应该在任务出现积压时,才产生跨机消费。因此,MQ 在产生积压时,应该要能以某种形式通知 Worker。 同时,积压量的变化是很快的,通知的方式应该做到以下几方面的高效:

  • 速度:尽可能地快;
  • 精度:尽可能少地发送通知,减少无效通知的发送。

为此,我们实现了广播模式,将 MQ 产生的积压量信息作为一个消息,广播给 多个Worker。

它在实现上如何满足高效的积压通知要求呢?

  • 速度:使用长连接将积压量信息推送到 Worker 端;
  • 精度:通过灵活的订阅过滤器,实现对本机、跨机、跨IDC的分级的广播。

通过广播模式,我们高效地解决了 MQ 积压的感知问题。

5Worker 如何消除 MQ 的积压

通过广播模式,每个Worker 都可以观察到所有它感兴趣的 MQ 的积压情况,并以此构建出整个系统的积压分布统计。拿到这些信息后,Worker 如何决定拉取哪个 MQ 的任务呢? 还是回到我们的原始诉求,尽量做到本机消费。所以我们的策略是说,Worker 应该优先消除本机的积压,当它有余力的时候,才去帮助其它Worker。

通过分优先级地拉取,既可在队列系统正常时大量降低跨机消费,同时也可以在故障发生时,有效地消除局部积压。

6负载均衡分析

跨机消费模式,从整个系统角度来看,是完全去中心化的,任意一个 MQ 和 Worker 个体都可以独立、自由地加入或退出系统。

在这个竞争式的消费系统里,根据具体的部署情况、不同机型消费能力不同等因素,无法达到完全的负载均衡状态。但在系统产生局部过载时,则可以自适应调节,达到相对的均衡。

6小结

4、需要实现更高效的任务处理

1现状分析

微信发布已有6年多的时间,后台的业务逻辑演化至今,往往是非常的复杂,我们来看一个比较极端的例子 —— 群聊批量并行化投递。

上图是群消息投递业务的简化流程示意。随着微信群消息体量的高速膨胀,其带来的成本压力越来越大,业务同学提出了批量并行化的优化方式。简单来说,就是将每个步骤中产生的 RPC 访问按实际访问机器聚合成一系列的批量操作,然后并行化执行。 通常来说,单次的批量并行化并不难写,一般而言,业务同学可能会选择裸写。但如果涉及多次的批量并行化,其中还存在嵌套的话,事情就不那么简单了。最终代码将变得异常复杂,业务开发的同学苦不堪言。MQ 能否从框架上解决这类问题?

2类 MapReduce 任务处理框架

其实,深入分析群消息投递的优化需求,可以看到:

  • 一次批量并行化操作本质上是一次 MapReduce 过程;
  • 整个群消息投递的处理过程是多次 MapReduce 过程的串联和并联。

所以,为了从根本上解决这一类问题,MQ 为业务提供了类 MapReduce 任务处理框架。

该框架提供封装了通用的 MapReduce 过程,以及并发的调度过程,同时提供并发池隔离能力,解决了并发池饿死的问题。让业务同学可以从冗繁的代码中解放出来,将更多的精力投入到实际业务中。

3流式任务处理框架

除了批量并行化的需求,业务经常提到的一个需求是,任务处理时会产生一些新的任务需要加到队列中。一般来说是走一次 RPC 来执行任务入队。在 MQ 2.0 下,流式任务可以帮忙完成这个事情。 所谓流式任务,就是在任务处理结束时,除了返回任务结果,还可以返回一系列新的任务。这些任务通过 MQ 内部框架流转入队,更轻量,事务性更强。

相比常规的同步处理模型,它提供了一种轻量的逻辑异步化模型。一个冗长的逻辑可以切分为很多小的功能块进行串联和复用,每一级之间都有 MQ 去充当缓冲和调度。虽然这种处理模式并不适用于所有逻辑,但作为组件功能的一部分,它提供了一种新的解决问题的能力。

4小结

MQ 2.0 提供的类 MapReduce任务处理框架和流式任务处理框架,为业务的实现提供了便利的支持。

5、需要实现更强的过载保护

1现状分析

MQ的重要作用是充当系统中的缓冲节点,流量控制的能力是非常关键的。在 MQ 1.0 下,只能通过配置队列的任务出队速度来实现流量控制。 其问题有几个:

  • 配置需要人工调整,难以估算对后端的实际访问;
  • 后端处于过载状态时无法自适应调整;
  • 自己处于过载状态时无法自适应调整。

2问题分析

从需求来看,MQ 的过载保护需求有两个方面,一是保护自己不过载,二是保护后端不过载。

下面分别讨论两种策略。

3前向限速

基于 CPU 使用率的流控: 该限速策略很好理解,就是在 CPU 使用率过高时,降低任务处理速度,以将 CPU 资源优先用于保证队列的缓存能力。

基于任务成功率的流控: 后端模块故障时,往往会导致队列任务出现大量的失败和重试,这些重试的量级往往会远超该后端模块设计的有效输出,给故障恢复带来很大的困难。该流控策略的通过收集任务执行的成功率信息,评估后端的有效输出,并通过反馈计算限制任务重试的速度。

4后向限速

MQ 实现了通用的后向限速能力,业务通过特定接口往 MQ 回传控制量,达到速度调控的目的。 基于后端 RPC 访问量的流控: 我们经常会遇到一些业务在处理任务时,存在不同程度的对后端的扩散访问。仅对任务处理速度进行限制,无法准确限制对后端产生的实际调用量。该策略通过收集业务对后端产生的实际调用量,反向调节任务处理的速度。

5小结

MQ 2.0 通过分析流控需求,在前向和后向分别提供了有效的流控手段,并且为后续更精细的流控策略预留了拓展的能力,增强了过载保护的能力。

6、本文总结

微信的队列组件,与业界其他队列相比,其突出的特点是更贴近实际业务场景,极大地解放了业务同学的生产力。

后续,将在任务持久化容灾和调度性能上,对该组件进行持续的优化。

原文发布于微信公众号 - IT技术精选文摘(ITHK01)

原文发表时间:2018-05-13

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏IT技术精选文摘

当代码变更遇上精准测试的总结

敏捷模式下迭代频繁,回归测试时总是不知道变动的范围。Devlop 有的时候也不知道他改了哪些东西,影响到哪些节点,或者是很多人改的,彼此不知道。遇到有代码洁癖的...

1725
来自专栏杨建荣的学习笔记

时间序列数据库InfluxDB初探(r12笔记第74天)

性能监控中的很多数据都是根据时间维度来生成的,就算是很少的几台服务器,如果设置了大量的监控项,每天的数据量也是很客观的,再加上是成千上万的服务器,这个量级就...

3527
来自专栏纯洁的微笑

微服务架构—服务降级

什么是服务降级?当服务器压力剧增的情况下,根据实际业务情况及流量,对一些服务和页面有策略的不处理或换种简单的方式处理,从而释放服务器资源以保证核心交易正常运作或...

2072
来自专栏不止思考

架构设计之「服务隔离」

那什么是「服务隔离」呢? 顾名思义,它是指将系统按照一定的原则划分为若干个服务模块,各个模块之间相对独立,无强依赖。当有故障发生时,能将问题和影响隔离在某个模块...

1513
来自专栏Golang语言社区

Go1.7改善了编译速度并且会生成更快的代码

Go1.7的开发周期正在接近它的下一个里程碑,Go的提交者Dave Cheney报告了子即将发布的版本中,团队成员在语言工具链上的努力。 Cheney称,基于当...

3599
来自专栏aCloudDeveloper

DPDK 全面分析

高性能网络技术 随着云计算产业的异军突起,网络技术的不断创新,越来越多的网络设备基础架构逐步向基于通用处理器平台的架构方向融合,从传统的物理网络到虚拟网络,从扁...

1.1K4
来自专栏SEO

如何新建一个对百度友好的移动端站点

37210
来自专栏Python中文社区

你真的了解网络爬虫吗?

Google 与 Yahoo 等网站的背后,都有一个强大的网页收集程序,可以将全世界的网页通通抓回去储存以便提供搜寻之用,这个程式就称为 "爬虫...

2459
来自专栏精细化测试

当代码变更遇上精准测试的总结

敏捷模式下迭代频繁,回归测试时总是不知道变动的范围。Devlop 有的时候也不知道他改了哪些东西,影响到哪些节点,或者是很多人改的,彼此不知道。

4854
来自专栏Java后端技术栈

推荐一款GitHub超实用的可视化代码树插件:Octotree

大家在GitHub查看代码的时候,是不是会经常跳转搜索代码!过一段时间就不知道自己跑到哪里了!有了这款工具,再也不用担心找不到位置了!

1554

扫码关注云+社区

领取腾讯云代金券