2.7 排队论
概述与动机
排队论是对等待队列的数学研究。这听起来与一本关于软件工程指标的书格格不入,直到你注意到交付流水线中有多大一部分其实就是一个队列:一份拉取请求在等待评审者,一次提交在等待CI运行器,一个工单在等待被领取,一条客户支持消息在等待回复。主题 2.4 已经介绍了流动负载与流动时间,并说明让一条价值流超负荷会使交付急剧放慢,主题 2.5 与主题 2.6 说明了大多数交付时间是等待时间,而不是工作时间。排队论正是解释所有这些为何为真的底层数学,而不只是一种被观察到的模式。
最有用的单一结果是利特尔法则,由运营研究学者约翰·利特尔于1961年证明的一条定理:一个稳定系统中项目的平均数量,等于项目到达的平均速率,乘以每个项目在系统中所花的平均时间。主题 2.4 已经在流动框架自己的术语下使用了这个结果:流动负载等于到达率乘以流动时间。在本书更广的词汇中,它也可以读作:在制品(主题 2.5)等于新工作的到达率乘以周期时间(主题 2.6)。这不是一条经验法则,也不是某些研究中观察到的相关性。它是一个对任何稳定队列都成立的证明,无论这个队列在处理什么,或者它如何决定接下来处理什么。
对大团队而言,这种普遍性正是关键所在。无论队列是一块看板、一个消息代理,还是一条共享CI流水线,利特尔法则都给你一个同样有效的合理性检验。如果你测得的在制品、到达率与周期时间大致不满足这个方程,说明你的三个数字中有一个是错的,通常是因为对什么算”进行中”或”已到达”的定义不一致。企业与政府组织同时运营着几十个这样的队列(共享代码评审池、共享测试环境、共享审批委员会),而利特尔法则是在一个错误的指标定义驱动出一个糟糕的人员配置或流程决策之前,就抓住它的最便宜的可用工具。
核心原则
- 利特尔法则是一个证明,而不是一条启发式规则。 对任何稳定队列而言,在制品等于到达率乘以周期时间,这是对你的交付指标是否内部一致的一次快速检验。
- 利用率与等待时间的关系不是线性缩放的。 随着一份共享资源接近满负荷利用率,排队延迟会急剧增长,而不是逐渐增长。一份以95%繁忙度运行的资源,等待时间往往是以80%运行的资源的许多倍,而不只是”稍微差一点”。
- 一个队列的平均值掩盖了它的最坏情况。 只报告平均等待时间,掩盖了接近容量上限时那条漫长、痛苦的长尾,这正是主题 1.6 所警告的、用百分位数而不是平均值的理由。
- 一个队列的定义方式,和任何其他指标一样容易被操纵。 什么算”已到达”、“进行中”或”已服务”,是一个选择,可以被调整来美化仪表盘,却不改变工作实际发生的情况。
- 一条流水线通常是一个由队列组成的队列。 一条交付流水线把几个阶段串联在一起,而无论其他阶段运行得多快,最慢的那个阶段决定了整条链条的节奏。
建议
在信任自己的数字之前,先用利特尔法则检验它们
拿出你团队测得的平均在制品、每周新项目的平均到达率,以及平均周期时间,检查在制品是否大致等于到达率乘以周期时间。当它不成立时,不要假定理论是错的。寻找真正的原因:一个计数不一致的阶段边界,处于”受阻”状态却仍被计为进行中的工作,或者到达率与周期时间是在不同的窗口上测量的。这一项单独的检查,比大多数团队用任何其他方式所能发现的,抓住了更多糟糕的埋点问题。
为每一份共享的、受容量约束的资源直接跟踪利用率
识别你的交付流水线中被许多团队共享的资源(一个代码评审池、一个CI集群、一个预发布环境),在计划让它接近极限运行之前,测量每一份资源作为其可用容量比例的繁忙程度。一个接近满容量运行的共享评审者小组,产生的评审队列等待时间,增长速度会远快于导致这一状况的需求的适度增长,这正是主题 2.9 建议把首次评审时间作为领先指标来关注背后的动态原理。
把到达率、成功率、失败率与跳过率分开
抵御把所有离开队列的事物都塌缩成一个单一”吞吐量”或”服务速率”数字的做法。分开跟踪四件事:工作到达的速度、其中有多少成功完成、有多少失败需要返工,以及有多少在任何人完成它之前就被放弃或悄悄丢弃了。一条因为跳过率悄悄攀升而看起来快的流水线,实际上并没有交付更多,而只有分开跟踪这四种速率,才能让你看清这一点。
把多阶段流水线建模为一个由队列组成的队列
把一条交付流水线,或任何多阶段流程(一次事故生命周期、一条招聘流水线),当作一条队列链,而不是一整团未加区分的”时间”来对待。整体到达率由第一个阶段设定,整体完成率由最后一个阶段设定,流水线的总错误数和跳过数,是每个阶段自身数字的总和。这种框架立刻告诉你哪个阶段值得投资:高利用率与高失败或跳过率组合最差的那一个,而不是碰巧最容易埋点的那一个。
设定人员配置和在制品限制时,把利用率而不只是吞吐量放在心上
当你决定一个团队需要多少评审者或CI运行器时,不要把容量正好设定为匹配平均到达率。一个平均以100%利用率运行的队列,在实践中实际上有无限的等待时间,因为真实的到达是不均匀的,而不是完全平滑的。刻意为余量做规划,把”我们的评审者几乎总是很忙”当作即将到来的等待时间的一个警示信号,而不是资源配置高效的证据。
权衡取舍:利与弊
| 方案 | 优点 | 缺点 |
|---|---|---|
| 没有正式排队模型,凭感觉配置人员 | 上手快;团队无需学习新词汇 | 持续低估等待时间在接近满容量时爆炸式增长的程度 |
| 用利特尔法则作为对现有指标的合理性检验 | 便宜,无需新工具,能快速抓住错误的定义 | 只检查一致性,本身不诊断原因 |
| 完整的排队仿真(到达分布、多服务器) | 对负载下等待时间行为的预测最准确 | 需要真正的统计技能,大多数团队维持不了 |
| 在共享资源上跟踪利用率,不做更深的建模 | 简单、可行动,能抓住等待时间失控的单一最大原因 | 对利用率为何高,或该如何处理底层原因,什么也没说 |
核心张力是严谨性与可采纳性之间的张力。完整的排队仿真给出最准确的答案,但几乎没有工程团队会构建并维护一个,而一个无人信任或更新的模型,比没有模型更糟。利特尔法则和基础的利用率跟踪放弃了一些精度,但不需要专门的统计技能,并直接契合团队已经为主题 2.4 到主题 2.6 收集的指标。默认使用这些便宜、可采纳的检查,把完整仿真留给罕见的情形:单一共享资源(一支大型CI车队、一个专门的评审池)的成本高到足以证明这项投资的合理性。
与团队讨论的问题
我们测得的在制品、到达率与周期时间,是否真的满足利特尔法则,如果不满足,为什么? 这是对一个错误指标定义而言最快的单一诊断方式。一起走一遍实际数字,如果方程大致不成立,把这种不匹配追溯到一个具体的定义不一致,而不是把这项检查打发掉。
我们交付流水线中的哪些共享资源正接近满负荷利用率运行,我们真的知道它们的利用率数字吗? 大多数团队能说出一个”总感觉很忙”的资源,却从未直接测量过它的利用率。识别出两三个最受约束的共享资源,为每一个获取一个真实数字。
我们是否把成功、失败与跳过混合成一个吞吐量数字,如果把它们拆开会看到什么? 一个单一的”已完成项目”计数,可能在质量下降或工作被悄悄放弃的同时依然上升。把最近一个周期的吞吐量重新计算为三个独立的数字,讨论一下这种拆分揭示了什么,而混合数字掩盖了什么。
我们流水线中真正的瓶颈在哪里?也就是决定了它下游一切节奏的那个最慢阶段? 团队常常投资于最容易改善的阶段,而不是真正约束总吞吐量的阶段。识别出高利用率与高失败或跳过率组合最差的那个阶段。
如果我们为最受约束的共享资源增加容量,等待时间会真的改善,还是需求会简单地膨胀来填满它? 这个问题把真正的容量短缺与需求问题区分开来,而答案决定了正确的修复方案是增加人手、设定在制品限制,还是改变工作进入队列前的优先级排序方式。
我们是否曾以一种让仪表盘看起来更好、却没有改变工作实际发生情况的方式,重新定义什么算”进行中”或”已到达”? 这值得用去年的真实例子诚实、具体地追问,而不是把它当作一个假设性的担忧来对待。
行业视角
初创公司。 人手寥寥时,大多数队列都短到正式的排队分析属于杀鸡用牛刀。有用的习惯规模更小:注意到某一个人,往往是最资深的工程师,已经变成一份事实上的共享资源,其他一切都在等待它,即便没有任何正式模型支撑,也要把这当作一个值得点名的利用率问题。
小型企业。 小型企业团队很少需要比跟踪其一两份真正共享的资源的利用率更复杂的东西,往往是单一的评审者或单一的部署流水线,并留意”通常可用”悄悄变成”通常是瓶颈”的那个节点。一份电子表格就够了;在这个规模上不需要专门的工具。
企业。 在企业规模上,共享资源会迅速增多:一个中央平台团队、一个共享安全评审委员会,一支服务几十个产品团队的共享CI车队。这些正是利用率跟踪最能发挥价值的资源,因为一份超负荷的共享资源,可能正在悄悄拖累每一个依赖它的团队的交付时间,而任何单个团队自己的指标都不会揭示这个存在于其自身流水线之外的原因。
政府。 多机构、多供应商的交付项目,常常把工作路由经过没有任何单一团队能控制或自行调整规模的共享审批委员会、共享安全认证流程与共享测试环境。对这些共享关卡(到达率、容量、利用率)的排队分析,往往是为增加容量、或改变工作在到达关卡前如何批处理提供商业理由所能获得的最清晰证据。
案例
企业。 一家云基础设施提供商的内部平台团队,注意到每一个依赖其共享CI车队的产品团队的变更交付周期(主题 2.10)都在悄悄攀升,即便没有任何一个团队自己改变过工作方式。一次利用率分析发现,该车队在核心时段的繁忙度超过90%,远远超过排队论所预测的等待时间开始急剧而非逐渐增长的那个点。该平台团队增加了CI容量,并引入了一个公平共享调度策略,这样任何单一团队的活动突增都无法垄断队列。中位数CI等待时间在一个月内下降了超过一半,这证明瓶颈自始至终都是一个共享的、不可见的队列。
政府。 一家国家许可机构的数字服务团队,两年来一直把申请处理跟踪为一个单一的”每周结案数”吞吐量数字,这个数字看起来很稳定。一次更仔细的分析,把这个数字拆分为已批准、已拒绝,以及在长时间延迟后被申请人放弃的案件,发现放弃率在同一时期几乎翻了三倍,而批准率保持平稳。把利特尔法则应用于案件处理人员队列,显示在制品的增长,远超出团队所声称的平均处理时间所暗示的程度,这意味着案件正在一种未被计为”等待”的状态中悄悄堆积。该机构重新构建了其案件跟踪定义,以诚实地计入每一份未结案件,并增加了案件处理人员容量,把利用率保持在85%以下,现在与吞吐量数字一起,被跟踪为一项常设的运营目标。
商业理由:动机、投资回报与总拥有成本
应用基础排队分析的回报,是它把”流水线感觉很慢”变成了一个具体、站得住脚的决定(给这份共享资源增加余量、把这个混合指标拆分为其真实的构成部分),而不是一句遗漏了真正原因的模糊呼吁,“更快地工作”。上面的云基础设施案例,通过容量和调度修复而不是改变任何个别团队的行为,把等待时间减半,正是这种分析稳定产出的模式:修复方案的成本几乎总是低于要求每一个下游团队围绕一个他们看不见的瓶颈加快速度。
采纳的总成本真正很低。利特尔法则和利用率跟踪,除了主题 2.4 到主题 2.6 已经要求你收集的东西(到达率、在制品与周期时间)之外,不需要任何新工具。这项投资主要是分析上的自律:互相核对数字,并在共享资源变成组织下一次无法解释的交付周期倒退之前,定期审查它们的利用率。
反模式与陷阱
- 把一份共享资源的容量正好设定为匹配其平均到达率: 只要需求哪怕短暂地不均匀,就必然导致高利用率和失控的等待时间。
- 只报告平均等待时间,从不报告百分位数: 隐藏了对等待中的人而言最重要的那条长尾。
- 把成功、失败与跳过混合成一个吞吐量数字: 本主题核心的操纵向量。一个处于压力之下的团队,可以通过悄悄让跳过率上升(被放弃的工单、被悄悄丢弃的请求、从未被计为失败的工作)来让吞吐量看起来健康。护栏是把到达率、成功率、失败率与跳过率跟踪为四个独立、可见的数字,这正是主题 1.2 对本书中每一个指标都要求的同一门自律,这样上升的跳过率就无法躲在一条平坦的吞吐量图表背后。
- 把”我们的人总是很忙”当作一句赞美: 这是高利用率的一个症状,是漫长、不可预测等待时间的主要原因。
- 重新定义”进行中”以悄悄缩小在制品: 把工作移入一个未被计入的状态(“受阻”、“暂停”),却不改变完成它实际需要多久,并打破了原本能抓住这一点的利特尔法则检查。
- 假定一个排队模型一旦建成就不需要维护: 到达模式和容量在不断变化,一个过时的模型会产出自信却错误的预测。
成熟度模型
- 第一级,启动: 没有任何队列被明确测量;等待时间只是被轶事性地讨论为”事情感觉很慢”。
- 第二级,发展: 至少为一条流水线跟踪了到达率、在制品与周期时间,但从未对照利特尔法则或共享资源的利用率进行检查。
- 第三级,标准化: 利特尔法则是跨交付流水线的常规一致性检查,最重要的共享资源的利用率被明确跟踪。
- 第四级,管理: 每一个重要队列的成功率、失败率与跳过率被分开跟踪,容量决策使用利用率目标,而不只是平均需求。
- 第五级,协奏: 组织把其主要流水线建模为一个由队列组成的队列,系统性地识别真正的瓶颈,并能指出因排队分析而做出的具体容量或流程变更,以及由此带来的可衡量的等待时间改善。
讨论思路
- 选择我们的一条交付流水线,检查它今天的数字是否满足利特尔法则。
- 说出我们组织中大多数人会同意”总是很忙”的那一份共享资源,找出它实际的利用率数字。
- 如果我们把上个季度的吞吐量图表拆分为成功率、失败率与跳过率,它会是什么样子?
- 如果我们今年必须为恰好一份共享资源增加容量,会是哪一份,什么证据能证明这一点合理?
要点回顾
- 利特尔法则(在制品等于到达率乘以周期时间)是一个证明,而不是一条启发式规则,是对你的交付指标是否内部一致而言最便宜的可用检查。
- 随着利用率逼近满容量,等待时间会急剧而不是逐渐增长。 把”总是很忙”当作一个警示信号,而不是一句赞美。
- 分开跟踪到达率、成功率、失败率与跳过率;把它们混合成一个吞吐量数字,是本主题核心的操纵向量。
- 把一条多阶段流水线建模为一个由队列组成的队列,投资于高利用率与高失败或跳过率组合最差的那个阶段,而不是最容易改善的那个。
- 优先选用便宜、可采纳的检查(利特尔法则与利用率跟踪),而不是大多数团队维持不了的完整排队仿真。
参考文献与延伸阅读
- Little, John D. C. “A Proof for the Queuing Formula: L = λW.” Operations Research, 1961.
- Kleinrock, Leonard. Queueing Systems, Volume 1: Theory. Wiley-Interscience, 1975.
- Wescott, Bob. The Every Computer Performance Book: How to Avoid and Solve Performance Problems on the Computer Systems You Work With. CreateSpace Independent Publishing Platform, 2013.
- Reinertsen, Donald G. The Principles of Product Development Flow: Second Generation Lean Product Development. Celeritas Publishing, 2009.
- Vacanti, Daniel S. Actionable Agile Metrics for Predictability. Actionable Agile Press, 2015.