专栏首页黯羽轻扬消息队列为什么说它像漏斗?

消息队列为什么说它像漏斗?

写在前面

对于 Web 服务而言,提升可扩展性的主要途径是将耗时的同步工作改成异步处理,从而允许将这些工作“外包”给多个 Worker 去做,或者提前完成能够预知的部分

那么,异步机制与可扩展性有什么关系?

这要从(异步)并行处理的优势说起

一.串行、并发与并行

可扩展性,意味着能通过向系统添加资源的方式应对不断增加的工作量

对于多个任务,一般有 3 种执行策略:

  • 串行:一个接一个地同步执行,总耗时为所有任务之和
  • 并发:多 CPU/多核并发执行,总耗时取决于最慢的任务耗时
  • 并行:异步并行执行,总耗时同样取决于最慢的任务耗时

试想,如果工作量持续增长,串行模式的延迟将会越来越大,而且无法通过加资源来解决,可扩展性无从谈起

并发模式虽然可以通过加 CPU 来应对更多的工作量(即纵向扩展),但很快就会遭遇瓶颈,要么达到顶配,要么耗光预算,可扩展性也不是很好

并行模式下,由于任务能够异步执行,我们可以加任意多的 Worker 来分担工作量,可扩展性良好。并且,与并发模式相比,异步处理是非阻塞的(无需等待执行结果,单 CPU/单核就足够了),意味着在(Worker)执行任务的同时,系统仍然能够轻松响应用户请求

因此,相比之下异步(并行)可扩展性最高

二.异步的意义

除了可扩展性方面的优势外,异步更多的意义在于:

  • 可打断/可暂停:允许分片执行,而不必一次做完
  • 可调度:允许更细粒度的时间管理,比如闲时主动执行、甚至离线执行
  • 并行的可能性:异步返回结果,意味着可以交给别人、甚至交给一支军队来做
  • 解耦生产者和消费者:把 Worker 分离出去,使之能够独立扩展,比如只加 Woker 不加 Web Server,类似于分离 Web 层和应用层

所以,React 从同步的 Stack reconciler 改为 Fiber reconciler,也具有这些意义:

既然任务可拆分(只要最终得到完整 effect list 就行),那就允许并行执行(多个 Fiber reconciler + 多个 worker),首屏也更容易分块加载/渲染(vDOM 森林)

三.消息队列

实现上,最常见的异步机制当然是消息队列:

Message queues provide an asynchronous communications protocol, meaning that the sender and receiver of the message do not need to interact with the message queue at the same time.

由消息队列提供异步通信协议,消息的发送方和接收方不需要同时与消息队列进行交互

例如,邮件系统中,发件人将邮件发出之后,可以继续处理其他内容,而无需等待收件人响应:

在用户看来,任务是立即完成的,但实际上是在一段时间之后才真正完成(所谓异步)

消息队列的运作中有 3 个角色,消息的生产者、消费者以及经纪人(Broker)

  • 生产者:应用程序往队列里发布任务后,立即告知用户该任务的状态
  • 消费者:Worker 拿到任务并执行,完成之后通知
  • Broker:从队列里取出任务并分发给 Worker,并负责管理任务的完整性,包括失败重试、(根据 Worker 的实际状态)动态调整分发策略等

P.S.另外,有个非常相似的概念叫任务队列,区别在于消息队列只负责接收、传递消息,任务队列还跟踪执行并返回结果,可以看作特殊的消息队列

Tasks queues receive tasks and their related data, runs them, then delivers their results.

当然,实际的消息队列/任务队列的实现更复杂一些,需要考虑各种问题:

  • 消息可能会丢失:比如消费者挂了,甚至消息队列挂了
  • 消息可能会重发多次:比如消费者做完忘记发送完成回执(ack)了
  • 可能出现忙闲不均的情况:比如轮流分发的话,有些 Worker 接到的总是重活儿
  • 队列可能会溢出:比如 Worker 太少或太忙,导致消息迅速堆积

P.S.关于消息队列运作机制和使用场景的更多信息,见RabbitMQ Tutorials

四.漏斗模型

消息队列就像一个漏斗(把橄榄油倒进瓶子里),用来控制流量和流速

汹涌而至的消息从敞口流入,经过缩口以固定的流速输出给(消息的)消费者

如果生产速率始终低于消费速率,倒进来立即就流走了,那么就不需要漏斗(消息队列)

如果生产速率始终大于消费速率,就会在漏斗中累积,最终填满、溢出,导致消息丢失:

P.S.这种现象称为Back pressure(反向压力),下游消费速度限制了传输,此时可以限制队列大小,排满了就返回 503,稍后重试(比如采取指数退避策略,让重试间隔越来越长)

所以,只有生产速率在短期内大于(而不是始终大于)消费速率的情况下,漏斗才有意义——用来吸收暂时的超量生产量

The message queue provides temporary message storage when the destination program is busy or not connected.

五.利特尔法则

另外,排队理论中一个有名的定理叫利特尔法则(Little’s law):

L = λW

L: average number of items in the queuing system
W: average waiting time in the system for an item
A: average number of items arriving per unit time

适用于任何稳定运转的排队系统

A “queuing system” consists of discrete objects we shall call “items” that “arrive” at some rate to the “system.” Within the system the items may form one or more queues and eventually receive “service” and exit.

P.S.“稳定运转”,是指不包括系统启动、退出等过渡状态

一些 item 以某种速度到达系统,开始排队,最终排到服务并从队列中退出:

到达 -> 排队 -> 离开

L = λW就是说:

队伍的平均长度 = 平均到达速度 \* (每一项的)平均等待时间

例如:

  • 酒窖:偶尔买一瓶放进去,平均每个月买 8 瓶,朋友聚会时候喝掉一些,但多数时候窖里都有 160 瓶,那么,就可以知道取出来喝的时候,每瓶酒在酒窖里平均存放了 1.67 年(W = 160 / (8 * 12)),离陈酿还有一段距离
  • 邮箱:平均每天收到 50 封新邮件,邮箱里多数时候有 150 封未读邮件,那么平均每 3 天(W = 150 / 50)处理一封邮件,可以作为邮件处理效率的衡量标准
  • 工厂:每天平均加工 1000 份原材料,在制品(WIP, work-in-process)数量平均有 45000 个,那么每件产品的加工周期是 45 天(W = 45000 / 1000),周期比较长
  • 医院:某地区平均每天诞生 5 名新生儿,待产妈妈平均会在产房待 2.5 天,那么,产房通常住有 12.5 位(L = 5 * 2.5)待产妈妈,也就是说,产房床位不能少于 13 张,对应的医护人员也不能太少

三项中,只要知道两个(易知的)就能粗略得出另一个(难算的),这就是利特尔法则的意义

参考资料

  • Why is asynchronous architecture required for achieving scalability? Can you please provide a real life application/example?
  • Queueing Theory for Dummies:以及完整版Queueing Theory for Embedded Systems Designers
  • Little’s Law:利特尔法则最清楚的解释
  • Module 4: Queuing Models and Little’s Law
  • What is message queuing?
  • Work Queues
  • Remote procedure call (RPC)

本文分享自微信公众号 - 前端向后(backward-fe),作者:黯羽轻扬

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-04-12

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

我来说两句

0 条评论
登录 后参与评论

相关文章

  • ES Module

    惟一作用是让浏览代码变得容易一些,迅速找到指定模块,根本原因是单文件内容太长,已经遇到了维护的麻烦,所以手动插入一些锚点供快速跳转

    ayqy贾杰
  • JSX_TypeScript笔记17

    TypeScript 也支持JSX,除了能够像Babel一样把 JSX 编译成 JavaScript 外,还提供了类型检查

    ayqy贾杰
  • web_bash笔记5

    上例中不带www的地址会返回301,wget会自动追过去,下载index.html并保存到当前目录,默认文件名相同,已存在的话自动添后缀

    ayqy贾杰
  • hdu---(Tell me the area)(几何/三角形面积以及圆面积的一些知识)

    Tell me the area Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65536/3...

    Gxjun
  • 公交车到站预测1----python处理csv文件

    之前处理csv一直用pandas,今天发现,pandas虽然强大,但是灵活度少了很多,有时候想实现一些简单的功能可能要花很大的代价。大道至简,返璞归真。就像这几...

    钱塘小甲子
  • 人群计数--Single-Image Crowd Counting via Multi-Column Convolutional Neural Network

    Single-Image Crowd Counting via Multi-Column Convolutional Neural Network CVPR...

    用户1148525
  • 如何才能准确测量 APP 的功耗?

    引言:电量消耗控制一直是困扰所有APP开发者的一大难题,其中又以Android平台尤甚。业界同行为此做了非常多的研究与尝试,腾讯自然也不例外。本周大讲堂继续推出...

    腾讯大讲堂
  • Spark Streaming写出文件自定义文件名

    通过重写MultipleOutputFormat来自定义文件名

    俺也想起舞
  • 刚出炉的一个MySQL故障

    说说我的"丰功伟绩"吧,事情是这样的(真实IP地址我使用192.168段的IP代替):

    AsiaYe
  • 《Experiment with MATLAB》读书笔记(九)

    读书笔记(九) %% 复数的极坐标形式 z = 3 + 4i r = abs(z) %极径 phi = angle(z) %幅角 ...

    万木逢春

扫码关注云+社区

领取腾讯云代金券