队列是一件用来买时间的工具
一句话总结
Q不会提高处理速度。将接收请求的速度和处理速度分开, 瞬间狂奔被吸收为时间。
为什么需要这个?
假设有图像上传API。保存原件,制作三个缩略图, 提取元数据,放入搜索索引中。全部以动机为前提的话,需要4秒钟才能回复。 平时可以忍受。但是促销日上传量增加一倍的话,4秒的请求 积攒了十倍,步行线程全部被绑定,甚至连健康检查都失败了。
插入队列后,API只会保存原始数据,并回复“已接收”。200ms。其余的 Worker以自己的速度处理。即使发生暴涨,API也会继续以200ms的响应速度,只有队列深度 会增加。增加的深度会导致处理延迟——原本需要4秒的时间可能需要3分钟。 有。但系统不会死。
这次交换就是全部。接受延迟,享受可用性。
稳定条件只有一个不等式
有三个条件可以使用队列。第一,工作不需要立即结束吗?第二,请求 速度是否可以比处理速度瞬间更快。第三,失败时以后再 可以做吗?如果三个都对,那么Q就对了。
相反,也有明确的应该不插入队列的情况。用户必须立即看到结果的查询, 而且平均流入量大于平均处理能力的情况。误解后者的人 很多。Q可以吸收冲击,但无法解决慢性过度负荷。
λ = 초당 유입 건수 μ = 워커 하나의 초당 처리 건수 × 워커 수
λ < μ → 큐 깊이가 0 근처로 돌아온다 (안정)
λ = μ → 깊이가 무작위로 떠돈다 (경계 — 운영하면 안 되는 지점)
λ > μ → 깊이가 선형으로 자란다 (터진다)
从数字上看很清楚。μ = 100/s,λ平时是60/s,30分钟内变为90/s。 如果是的话,在这个区间中每秒消失的余地是10个。30分钟的话,剩下的队列是 没有,而且很容易吸收。但是λ上升到110/s的话,每秒积累10件,30分钟就积累18,000件。 可以。如果这个状态没有结束,内存或磁盘都会用完然后爆炸。
如果λ > μ持续的话,需要的不是队列,而是增加工作者或限制流入。
延迟与利用率不成正比
这里人们经常忽略的一个点是,等待时间与利用率(ρ = λ/μ)成正比。 不会增加,而是非线性地爆炸。用大概的感官来说就是这样。
| 利用率ρ | 等待时间排泄率(1/(1−ρ)) | 意思 |
|---|---|---|
| 0.5 | 2倍 | 宽裕 |
| 0.8 | 5倍 | 渐渐露出了痕迹 |
| 0.9 | 10倍 | 再涨一点就会急剧变差 |
| 0.95 | 20倍 | 难以运营 |
| 0.99 | 100倍 | 实际上障碍 |
所以不能把步行者容量“刚好适合平均流入”来控制。以利用率70~80%为目标 抓住,上面接受自动扩展或流入限制。
在现场相遇的样子
加入队列后会产生新的运营指标。队列深度和消费者延迟(consumer lag) 是。如果把这两个放在仪表板上,**Q就会变成一个安静的黑洞。**用户 举报说上传了但没有显示出来,API仪表板都是绿色的。问题是 堆积在API后面。
光看深度是不够的。深度1000是否严重取决于处理速度。 不同。深度÷处理率=耗尽时间要一起看才能判断。每秒100件 处理的话是10秒,每秒1件的话是17分钟。警报也是以这个值设置的。
再加一个警报。**深度从0不动的也是异常信号。**消费者全部 死了,如果没有人拿出来的话,就只能堆积流入量,如果连生产者都死了的话,深度从0开始 平坦。如果处理完成件数为0,深度为0,那么整个管道就会停止。
而且,如果放入队列的话,还需要用户体验设计。如何处理“已接受”的状态。 会不会给我看,要等多久,如果失败了该怎么通知。不确定这个,就只排队。 输入后,用户会看到消失的请求。至少要确定三个。
- 立即退还工作ID—用户以后应该可以询问状态。
- 创建查询状态的路径 —
GET /jobs/{id}查看pending·running·failed。 - 通知失败——用完重试的作业,发送到死讯信队列,让别人看到。
在选择Q之前要回答的四个问题
选择工具是最后一步。在前面,首先要确定四个特性,把这个 不确定就选择Redis或Kafka的话,以后都会重新制作全部。
保证传递。至少一次(at-least-once)是基本条件。准确地说一次是队列给的 不是,而是消费者公平地获得的。记录处理的作业ID。 如果同样的东西再次出现,我会绕过。
**顺序。**遵守顺序的队列不能并行处理。在实际工作中,通常以键单位 顺序就足够了——只要同一个用户的工作按顺序进行,与其他用户的工作顺序 没关系。如果将分区键设置为用户ID,就会得到这个。
**重新尝试和放弃。**尝试几次,决定间隔如何增加,什么时候放弃。 如果在指数百折扣中不加入震动,失败的工作会在同一时间集中起来重新尝试。
**死去的信队列(DLQ)。**是写完再试的作业的地方。如果没有DLQ,那个作业是 永远循环或安静消失。DLQ中积累的数量一定会发出警报—— 这里堆积的是人们应该看到的。
将在下面的测验中确认
这个模块只涉及概念。从下一个模块开始,直接用Redis列表和流创建队列。 制作后,逐一再现顺序、重复、丢失在哪里发生的。