故事
万历年间,苏州有个织造衙门,专管江南贡缎。一匹云锦要经线、纬线、配色、提花四道工序,原先一个师傅从头到尾做,十日一匹。
新来的堂官姓周,是个急性子,翻《考工记》看到「百工之事,皆圣人之作也」,觉得人多力量大。他下令把作坊改成流水线:经线工只管经线,纬线工只管纬线,配色、提花各设一棚。又立了一条规矩——每棚完工须敲梆为号,下一棚闻梆即接。
头一个月,产量果然翻到三倍。周堂官大喜,上疏请功,说「古法十日,今法三日」。
第二个月出了问题。配色棚的师傅老陈眼睛花了,辨错了一缕茜草红,整匹缎子废了。按规矩,这匹缎子要退回经线棚重做,但经线棚已经接了下一单,梭子上了新线。老陈的徒弟去理论,两棚吵起来,梆子敲乱了,后面几棚全接了错号,一上午废了七匹。
周堂官的应对是加人:每棚设副手一名,专管「接梆验货」;又设「巡棚」两名,往来传话。人加到原先的八倍,产量却跌回两匹半——那些副手和巡棚本身也要吃饭、也要走动,作坊里挤得梭子转不开身。
第三个月,周堂官亲自蹲棚。他发现一个怪现象:经线棚的梆子响后,纬线棚不是立刻接,要等——等巡棚跑过来确认「这梆是真的」,再等副手核对「上一棚没有退单」。这些等不是闲着,是互相等。经线工敲完梆子不能走,得等纬线工点头;纬线工点完头不能织,得等配色棚腾出手;配色棚腾出手了,还得等提花棚确认花样编号。
周堂官算了笔账:原先一个师傅十日,是十日的工;现在四棚三日,是十二人·日,已经亏了。加到八倍人,变成二十四人·日出两匹半,亏到骨子里。
他去找致仕的老堂官请教。老人听完,只说了一句:「你加的不是工,是话。」
—
周堂官没听懂,老堂官便拿筷子蘸酒,在桌上画了一道线。
「一棚一人,就像这根筷子,折它要十斤力。你换成十根筷子并在一起,照理该扛百斤——这是Amdahl算的,小孩子都懂。」
他又取十根筷子,不是并齐,而是交叉搭成一座小梁。
「但你做的是贡缎,不是扛木。十根筷子要成梁,得互相咬着劲——这根压那根,那根撑这根,咬劲的地方就是话。话少了,梁散;话多了,十根筷子一大半的力气花在互相咬上,没剩多少去扛东西。」
周堂官盯着那筷子梁,忽然明白:他加的副手、巡棚,全是「咬劲」——不是在做缎子,是在做做缎子的前提。这些前提会自我繁殖:副手要核对,核对需要记录,记录需要识字,识字需要先生,先生需要束脩……
老堂官把筷子一推:「Amdahl 只告诉你『有些事没法并行』,那是天生的瓶颈。但他没告诉你,并行之后还会长出后天的瓶颈——你加进去的人,自己就是瓶颈。」
—
周堂官回衙门,没再上人,反而减了两棚,改成「经纬合棚」「配色提花合棚」。人减到四倍,产量却稳在三匹——合棚内部省了「接梆」的话,两个师傅低头就能商量。
他又做了一件事:允许每棚缓存。原先规矩是「零库存,闻梆即接」,现在改成每棚备半匹的「活线」——上棚出问题时,下棚先用缓存撑着,不空等。这半匹缓存是浪费,但算下来,省下的「等」比浪费的线值钱。
周堂官后来把这套经验写进《百工堂记》,里头有一段:
「并工之初,速增;再并,速滞。滞非工惰,乃话壅——话者,工与工之交也。交少则隙,交多则淤。淤甚于隙。故并工之要,在减交而不在增口,在备荒而不在追流。」
「备荒」就是那半匹缓存。周堂官发现,人不是机器,机器可以「闻梆即接」零延迟,人不行——人需要容错余量,这余量本身就是成本,但省不得。
—
概念解析
Gene Amdahl 在 1967 年提出一个简单定律:如果一段任务里有比例 $p$ 无法并行,那么无论加多少核,加速比上限是 $1/(1-p)$。这是天生的瓶颈——就像云锦里总有几道手续没法同时做。
Neil Gunther 的 USL(Universal Scalability Law)在 Amdahl 基础上加了第二项:
$$\text{加速比} = \frac{N}{1 + \alpha(N-1) + \beta N(N-1)}$$
- $\alpha$ 是争用系数(Amdahl 的串行部分)
- $\beta$ 是协同系数——这才是 USL 的核心贡献
$\beta N(N-1)$ 描述的是协同成本。它不是某个固定的串行瓶颈,而是随规模二次增长的交互开销:每加一个节点,它要和所有已有节点交换状态、确认、心跳。周堂官的副手、巡棚、核对、记录,全是这个 $\beta$ 的具象。
为什么协同成本是 $N(N-1)$ 而不是 $N$。 因为交互是成对的。两个棚要说话,三个棚有三对话,十个棚有四十五对。周堂官加到八倍人时,交互对数是二十八,这些「话」把作坊塞满了。
USL 的残酷之处。 Amdahl 说「加速有上限」,但至少是单调增的——加人总有点用,只是越加越少。USL 说「加速会先升后降」:过了某个拐点,再加人反而倒跌,因为协同成本的二次曲线压过了并行收益的线性增长。周堂官的八倍人出两匹半,就是这个回归。
工程上的对应。 微服务的「话壅」是服务间调用;分布式数据库的「话壅」是共识轮次;MapReduce 的「话壅」是 shuffle 阶段的网络风暴。这些都不是某个固定瓶颈,是规模本身制造出来的瓶颈。
周堂官的「合棚」对应工程上的服务合并——减少交互边界,把 $\beta$ 的基数降下来。他的「缓存」对应异步解耦——用余量换时间,打断「互相等」的锁链。
USL 的真正教训不是「别加人」,是加人之前先算 $\beta$。很多系统在设计阶段只算 Amdahl 的 $\alpha$(串行比例),没算 $\beta$(交互密度),结果上线后规模一扩,协同成本爆炸,只能回头拆服务、加缓存、做异步——这些全是周堂官做过的事,只是晚了三年。