故事
同治年间,扬州有个灯市,每年元宵前后开集三日。灯市规矩古怪:卖灯的、买灯的、评灯的,各在一巷,三巷之间隔了半里青石路。买灯的人付完银子,不能当场取灯——得等制灯匠把灯做好,再由跑腿的小厮送到"取灯巷"。评灯的老先生坐在巷尾高阁上,只看取灯巷里挂出来的成品,给每盏灯写评语。
这规矩带来一个麻烦:你刚花十两银子订了一盏走马灯,转身走到取灯巷,灯还没到。你问管事:我的灯呢?管事翻册子说,册上没登记。你急了,回制灯巷找匠人理论,匠人却指着墙上新糊的纸壳说:灯早做好了,小厮刚送出去。你再奔取灯巷,灯果然挂在那儿了,可评语栏空着——老先生还没看见。
三日灯市,这种"我买了却看不见、看见了却没评语"的纠纷不下百起。灯市主事请了个师爷来改规矩。师爷只添了四条,纠纷竟去了九成。
第一条:自己点的灯,自己先看见。 你刚订的灯,哪怕小厮还在路上,取灯巷的册子上也得先给你记一笔。你人到取灯巷,管事一查,"确有此灯,尚未送达",不会让你白跑。这叫读自己的写——自己的银子花出去,自己先得有账。
第二条:取灯巷的灯,按你来的顺序挂。 你上午订了走马灯,下午订了莲花灯,到取灯巷时,走马灯必定先挂出来,莲花灯后挂出来。哪怕小士脚程有快有慢,管事调度有先有后,你看见的次序不能乱。这叫单调读——你眼里的世界,时间箭头不能倒转。
第三条:你写评语之前,得先看见灯。 评灯老先生不能凭空给一盏还没挂出来的灯写评语;同理,你在取灯巷给某盏灯写了评语,回头再看,那盏灯必定还在。这叫单调写——落笔之前,对象得先存在;落笔之后,对象不能凭空消失。
第四条:你刚写完评语,自己再翻看时,评语得在。 有回一位盐商老爷写了半宿评语,次日来取灯巷找自己的墨宝,却发现评语栏空着——老先生的书童夜里抄漏了。盐商大怒,以为有人故意抹掉。从此规矩定下:你自己写的东西,你自己再读,必须立刻读到最新版本。这叫写后读——自己的笔墨,不能被别人时快时慢的抄工给吞掉。
师爷这四条,没动制灯匠的作坊,没加小厮的人手,没改老先生的评灯流程。他只是说:同一个人连续做的事,顺序不能乱。盐商上午订的灯、下午写的评语、夜里来查的账,这三件事在盐商自己的"会话"里是一条线,线上的因果不能断。至于另一位布商什么时候看见盐商的灯、什么时候读到盐商的评语,那可以慢,可以乱——那是别人的会话,不在这四条管辖之内。
灯市又开了二十年,直到电灯进了扬州城,这规矩才慢慢废掉。但老辈人还记得:那四条没让灯市变"快",只是让每个人在自己的一连串动作里不觉得被骗。你走三步,三步之间世界不能翻脸不认。
—
概念解析
会话保证(Session Guarantees, Terry et al., 1994)是分布式系统一致性模型中最贴近用户体感的一层。它不追求全局实时同步,只保证同一个客户端在连续交互中的一致性——自己刚做的事,自己立刻能感知到后果。
四条保证的原始名称是:Read Your Writes、Monotonic Reads、Monotonic Writes、Writes Follow Reads。它们共同构成一个"因果在会话内不中断"的契约,是 Bayou 系统在移动计算场景下提出的核心设计。手机断网、笔记本休眠、平板切换 Wi-Fi——这些"断断续续在线"的设备,恰恰最需要会话保证:用户不会接受自己刚发的消息、刚填的表单、刚拍的照,在下一秒刷新时凭空消失。
与更强的一致性模型相比,会话保证的关键特征是以客户端为中心而非以数据为中心。线性一致性要求"全系统对操作的实时顺序达成一致";顺序一致性要求"全系统对操作的全局顺序达成一致";因果一致性要求"有因果关系的事件顺序不被颠倒"。这三者都是"数据视角"——操作在系统层面的排序。会话保证则是"用户视角"——只保证同一个用户连续发出的操作,在其后续读取中按预期呈现。
这种以客户端为中心的视角,天然适合最终一致性系统的补偿设计。Cassandra 的轻量级事务、Amazon DynamoDB 的会话一致性读取、现代 CDN 的边缘缓存策略,都在不同程度上实现了这四条保证的子集。代价极小:不需要全局时钟,不需要全序广播,只需要在客户端与服务器之间维持一个会话上下文——通常是粘会话(sticky session)或客户端缓存的读写标记。
会话保证与因果一致性的关系值得细辨。因果一致性是偏序的:事件 A 导致事件 B,则全系统必须看见 A 在 B 之前。会话保证更弱:它只要求同一个客户端的读写序列内部因果不中断,不保证跨客户端的因果可见。用灯市的话说:盐商订灯和写评语的顺序不能乱,但布商什么时候看见盐商的灯,不受约束。这使得会话保证在实现上远比因果一致性轻量——不需要向量时钟,不需要追踪跨节点的依赖图。
Terry 等人在 1994 年的原始论文中,把会话保证定位为"弱一致性模型中的强子集":比最终一致性强,比因果一致性弱,但足够让终端用户建立对系统的信任。这个定位至今有效。现代移动应用的设计哲学——"乐观更新、本地优先、后台同步"——本质上就是会话保证的工程化:你在朋友圈刚发的照片,自己立刻看见(读自己的写);刷新后不会消失(写后读);按时间线往下翻,不会看到昨天的帖子跳到今天的上面(单调读);评论某条帖子之前,那条帖子必定先加载出来(单调写/写后读)。
这四条保证的独立性也值得注意。它们可以单独启用、组合启用,不必捆绑。一个只实现"读自己的写"的系统,已经能消除大量用户投诉;四者齐备,则构成一个完整的"单用户因果会话"。这种模块化正是会话保证的工程价值所在——按需付费,不必为全局一致性付出全局代价。
从一致性模型的阶梯来看,会话保证位于因果一致性之下、最终一致性之上,是连接"系统正确性"与"用户可感知正确性"的关键桥梁。它回答了一个被更强一致性模型忽略的问题:一致性的终极裁判是谁? 不是分布式协议的数学证明,而是凌晨两点还在刷新页面的那个具体的人——她刚点下的"提交",下一秒必须还在。