故事

宣统二年,北方各省推行"均田令"。朝廷派下来的办法很老派:每县把地册报上去,户部核对,批文下来,才能丈量分地。一县一县串着办,三年过去了,直隶才办完两个府——后面还排着二十三个府、一百多个州。

有个候补道员叫周维新的,在保定府试了一种新办法。他把"均田令"拆成两条规矩:

第一条,先画押,后分田。 各村各乡不必等地册齐全,先把"我要哪块地"的诉求写成条子,投进县衙门口的铜箱。每天酉时开箱,当众念一遍,按投进来的先后顺序排成号簿。号簿一旦写定,任何人不能再改——这就是"画押"。第二天,差役们照着号簿上的顺序,挨家挨户去丈量、立界、发契。丈量可以并行,十几组差役同时出动,但号簿上的顺序是铁打的。

第二条,同号不冲突。 如果两家乡亲投了同一块地,号簿上排在前面的得,排在后面的改分别的地——规矩事先贴在大门口,人人看得见。差役们不用当场吵架定输赢,照着号簿办就行。

周维新管这叫"先序后行"。

头一个月,保定府就办了过去半年的量。老派官员骂他"乱了章法":地册还没核完,怎么敢先分?周维新说:地册核三年,核完地都荒了。我的号簿就是地册——谁要了哪块、谁先谁后,全在簿上,将来户部要查,翻开就看。

最妙的是"无冲突并行"。十几组差役同时出动,但号簿已经消掉了所有可能的争抢——差役甲在东村量张家的地,差役乙在西村量李家的地,两人永远碰不上面,因为同一块地只会出现在一个号上。老办法里,差役们得互相通气"你量了这块告诉我",现在连通气都省了。

但也有难处。号簿一旦写定,就不能反悔。 有家乡亲投了条子才发现,自己要的河滩地汛期会被淹,想改投对岸的坡地——不行,号簿已画押,改就是掀了整个顺序。周维新只能让他"等下一轮",或者"找排在前面的商量换"。这就是"先序"的代价:灵活性换确定性。

还有个更隐蔽的问题:号簿本身怎么定? 酉时开箱,如果两家乡亲同时把条子塞进箱口,谁先谁后?周维新在县衙门口摆了一面大鼓,鼓响为号——鼓响前投的算今日,鼓响后投的算明日。鼓响那一瞬间的争议,由县丞当场裁断。这就是整个系统里唯一需要"吵一架"的地方:定序的那一刻。一旦序定了,后面全是机械执行。

后来这套办法被总督衙门看中,推广到全省。有人加了改进:号簿不再由县丞手写,而是各村推举的"保正"们共同抄录,每人抄一份,互相核对——这就是号簿的复制与共识。但只要号簿一致,后面的执行仍然可以各自并行。

概念解析

Calvin(Thomson–Abadi, 2012) 是一种确定性数据库架构,核心思想是先全局定序,再并行执行。它把传统数据库"先锁后判"的模式倒过来:在事务触及任何数据之前,先用一个独立的定序层(sequencer)把所有事务排成全局唯一的顺序;执行层拿到这个顺序后,可以无锁并行地跑,因为所有可能的冲突已经在定序阶段被消解。

与 2PC 的对比。 2PC([✓#20 悬心])是"先执行,再协调"——各节点先本地操作,再投票决定提交还是回滚。Calvin 是"先协调,再执行"——全局顺序定好之后,执行是确定性的,不需要两阶段投票。代价是事务不能读取当前执行结果再做决定(没有"交互式事务"),因为定序时执行还没开始。

与 Paxos/Raft 的对比。 共识协议([✓#6 传灯人]、[✓#3 守夜人])解决的是"多个节点就同一个值达成一致"。Calvin 的定序层确实可以用共识协议实现(比如 Paxos 组维护一个全局日志),但它解决的是更高一层的问题:如何让数据库事务在分布式环境下既保证一致性、又充分并行。共识是工具,Calvin 是用这个工具搭建的完整数据库架构。

确定性执行。 传统数据库需要锁,是因为同一时刻多个事务可能读写同一行数据,执行结果取决于它们的交错方式。Calvin 的洞察是:如果事先知道全部事务的输入(读哪些键、写哪些键),就可以预判冲突、排好顺序;执行时每个事务看到的状态,和单机串行执行时完全一样——这就是"确定性"的含义。

现代继承者。 FaunaDB 继承了 Calvin 的架构思想;CockroachDB 和 YugabyteDB 的"串行化默认"也吸收了先定序后执行的思路,但保留了更多交互灵活性(代价是更复杂的冲突重试)。Google 的 Spanner([TrueTime])走另一条路:用硬件时钟给事务打时间戳,靠"等一等"来保证外部一致性,而非 Calvin 式的纯逻辑定序。

代价与边界。 Calvin 的刚性定序牺牲了交互式事务(事务里不能先读、根据结果再决定写哪些键),也牺牲了低延迟(定序层本身有网络往返)。它最适合的场景是事务模式预先可知、吞吐量要求高、延迟要求相对宽松的系统——比如金融清算、游戏状态同步、供应链追踪。这些场景里,"先画押后分田"的确定性,比"边谈边改"的灵活性更有价值。