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

Posted IT技术精选文摘

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了微信后台异步消息队列的优化升级实践分享相关的知识,希望对你有一定的参考价值。

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、本文总结


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

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

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

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


以上是关于微信后台异步消息队列的优化升级实践分享的主要内容,如果未能解决你的问题,请参考以下文章

Celery + Flower + FastAPI + RabbitMQ ,Python实现异步消息队列和监控

Celery + Flower + FastAPI + RabbitMQ ,Python实现异步消息队列和监控

系统学习消息队列分享(十) 如何实现高性能的异步网络传输?

高并发系统设计(十三):消息队列的三大作用:削峰填谷异步处理模块解耦

Android 异步消息处理机制

node事件循环和消息队列简单分析