本文是《执行缝隙》(The Execution Gap)的作者手记。 它不是书籍正文的摘要或重写,而是围绕本章问题、工程背景与写作之后的进一步思考。
做系统久了以后,“定位问题”几乎已经变成一种固定动作。遇到异常,先列出涉及的服务、模块、接口、节点,再沿着日志和调用链逐个检查。哪一个接口报错了,哪一个状态没有更新,哪一段代码走到了错误分支,哪一个实例在那个时间点出现了异常,通常都可以一点一点被缩小。
这种方法之所以成为工程师的本能,是因为它确实有效,而且现代软件系统本身就是按照这种方式被组织出来的。代码有模块,系统有服务,服务有实例,实例有指标和日志,每一个对象都有明确的名字和边界。监控系统天然围绕这些对象工作,事故复盘也天然围绕它们展开。
于是,当我们问“哪里出了问题”时,实际上早已经悄悄限定了答案可能出现的位置:问题应该在某一个已经被划出来的对象里面。
第三章真正让我开始警惕的,就是这个前提。
因为有一些执行偏差,在把所有组件逐个检查完以后,依然没有消失。
上游收到的输入可以是对的,中间系统按照自己的规则处理也没有异常,下游接收到的数据可以完整,执行端的状态也没有报错,甚至每一段都有日志能够证明当时到底发生了什么。可当这些材料全部放在一起时,最终现实结果仍然和最初已经成立的对象对不上。
这时候继续问“还有哪个组件没查到”,有时只是让我们在同一个搜索空间里不断提高分辨率,而不是改变问题本身。
我们能看见对象,却不一定能看见对象之间的东西
现代工程体系对“对象内部”已经非常擅长。
一个服务内部发生了什么,我们可以增加日志;一个调用到底耗时多久,可以加入 tracing;一个状态为什么变化,可以记录状态迁移;一个模块是否出现异常,可以增加指标、告警和更细粒度的观测。
这些手段都很重要,我从来不认为它们应该被削弱。
但有一个问题是,它们大多数仍然是在告诉我们:这个对象内部发生了什么。
假设上游产生了一个判断,下游接收了它,并继续完成执行。上游日志可以证明自己为什么做出这个判断,下游日志也可以证明自己接收到了什么并按照什么规则行动,可这两份日志放在一起,并不会天然证明一件事情:下游接收到的那个对象,是否仍然完整保留着上游判断成立时所依赖的含义和条件。
这就是我写这一章时越来越在意的地方。
我们很容易因为两边都没有报错,就默认中间的关系没有问题。
但“左边成立”和“右边成立”,只能证明两个端点分别成立,并不能自动证明把它们连接起来的那件事也成立。
这一点在软件里尤其容易被忽略,因为系统架构图已经替我们画好了那些连接。两个服务之间有一条箭头,一个 API 把它们连起来,一段消息进入队列以后被另一个消费者读取。从视觉上看,它们已经被连接,因此我们也很容易顺手认为那个连接所承载的意义也已经被建立。
可箭头只是表示数据从这里去了那里。
它不一定证明语义完整地过去了,也不一定证明原来成立的条件在另一个时刻仍然成立,更不证明两个系统所指向的对象始终是同一个对象。
这种差别在系统正常运行时并不显眼,因为大部分时候两端确实吻合。真正困难的是,一旦它们第一次分开,我们通常首先去检查两个端点,而不是检查那个从来没有被当成独立检查对象的“之间”。
有些东西是在传递过程中丢掉的
第三章里用了“转换、时差、接缝和关系”几个词,我当时很刻意地没有把它们做成新的故障分类。
因为如果把它们变成四个框,工程师很快又会得到另一张故障清单,然后继续问:这次属于转换问题,还是时差问题,还是接缝问题?
那样其实没有真正改变思维方式。
这几个词真正想表达的是同一件事情:有些偏差不是藏在一个对象内部,而是在两个分别成立的对象之间出现。
其中最容易理解的是转换。
一个对象从一个系统进入另一个系统时,通常不会原封不动地过去。业务意图会被变成参数,审批结果会被变成状态,策略判断会被变成 ALLOW 或 DENY,现实条件会被抽象成机器可以读取的字段。
转换本身不是错误,它恰恰是系统能够协作的基础。
问题在于,任何表示方式都有自己的边界。
上游的一个判断可能是在若干前提同时成立时得出的,可当这个判断继续向下传递时,下游真正收到的可能只剩一个最终结论。那个结论没有错,上游的判断也没有错,下游按照这个结论继续行动同样没有违反自己的规则,可原来让这个结论成立的某些条件已经没有一起过去。
这类问题很难被传统日志直接标成“错误”,因为没有任何一个字段一定非法,也没有任何一个组件一定异常。
它更像是一种意义在跨越边界时发生了变化。
时间会让这个问题更明显。
一个审批在上午十点成立,一个动作在下午三点才真正发生。上午十点时成立的现实条件,并没有承诺自己到了下午三点仍然保持不变。如果系统只记录“审批通过”这个结果,却没有继续关心它成立时依赖的状态,那么五个小时之后的执行仍然可能在形式上拥有一个完全有效的审批。
这时候审批系统没有错,执行系统也未必有错。
真正需要问的是:当初使这个审批成立的东西,在执行发生时是否仍然成立?
这个问题既不完全属于审批对象内部,也不完全属于执行对象内部。它存在于两者之间,而且跨越了时间。
我认为这也是“执行缝隙”这个词真正开始变得有意义的地方。所谓 gap,并不一定意味着中间有一个看得见的洞,也不一定意味着某个组件失效。它可能只是表示:两个端点仍然分别正确,而连接它们所依赖的那个条件已经没有继续成立。
更多日志不一定能够回答这个问题
这一点对工程直觉其实有些不友好。
当事故没有解释清楚时,最自然的动作就是增加观测。
日志不够,就加日志;trace 不够,就增加 span;服务太大,就继续拆;状态不清楚,就记录更多中间状态。
这些措施常常是必要的,但我后来越来越不愿意把“观测得更多”直接等同于“就能知道发生了什么”。
因为观测密度和问题类型是两件事。
如果问题真的藏在一个组件内部,那么提高内部观测能力当然会帮助我们找到它。但如果问题来自两个对象之间没有被明确建立的关系,那么两边日志都增加十倍,也可能只是让我们更加确定:左边确实成立,右边也确实成立。
至于为什么左边成立以后,右边却没有保持我们原本以为应该保持的含义,仍然没有被回答。
这让我想到一个在工程实践里很容易出现的错觉:只要数据足够多,事实就会自己浮现出来。
其实未必。
数据能够告诉我们已经被记录的对象发生了什么,但它不能替我们决定哪些对象之间原本应该保持什么关系。如果这条关系从来没有被定义过、检查过或者留下证据,那么再完整的对象内部日志,也只能让我们更加清楚地看见两个端点。
中间缺失的东西仍然缺失。
因此,第三章真正改变的并不是排查工具,而是排查对象。
过去我们主要问:
“哪个组件坏了?”
现在必须再增加一个问题:
“哪一个原本应该保持成立的关系,没有继续成立?”
这两个问题并不冲突。
组件当然会坏,服务会宕机,代码会写错,配置会错误,硬件也会失效。这些传统故障没有因为 Execution Gap 的出现而消失。真正需要补上的,是组件检查完成以后仍然无法解释结果时,我们还剩下什么语言继续往下查。
我不想把“关系”再变成一个新组件
写到这里其实还有一个很容易掉进去的坑。
既然关系这么重要,那是不是应该把“关系”本身做成一个新的正式对象,然后给它定义状态、字段、分类,再像检查组件一样检查关系?
我在这一章里没有这么做。
因为一旦这样处理,我们可能只是把原来的问题换了一层名字。
过去我们寻找一个坏掉的组件,现在改成寻找一个坏掉的“关系对象”;过去有组件清单,之后又会出现关系清单。看起来理论变复杂了,但搜索方式没有真正变化,我们仍然希望所有问题最终都能被压缩成一个明确的点。
而这一章真正想保留的恰恰是另一种可能性:
一次偏差未必只有一个唯一断点。
同一个现实失败里,可以同时存在多段关系变化。某个条件在转换时被压缩了一次,在等待过程中又因为现实状态变化而失效,进入下一系统时还可能再次经历一次重新解释。到最后,很难说“真正的问题就是这一点”。
第三章使用那十七个经过事实核验的案例,并不是为了证明理论,而是因为这些现实失败不断提醒我:现实系统中的偏差往往不像教科书里的单点故障那样干净。多个分析维度可以同时成立,同一个事故也未必能稳定收缩到一个唯一故障位置。
这并不意味着事故永远无法定位。
它只是意味着,定位不一定等于找到一个唯一的坏点。
有时候真正需要解释的是一段关系为什么没有继续成立,以及这种变化如何沿着多个系统逐步传播,最后变成现实结果。
到这里,问题反而开始变大
第一章拆掉了“每一环都对,所以整体也应该对”的推论;第二章又把“执行了”拆成了一组不能默认等同的对象。到了第三章,我们再往前走了一步:即使这些对象本身都分别成立,也仍然不能假设它们之间的关系天然成立。
这一步让我开始意识到一个更麻烦的问题。
如果我们把视线从对象内部移到对象之间,搜索空间会突然变得非常大。
一个复杂系统里有很多对象,理论上任意两个对象之间都可能存在某种联系。如果只是笼统地说“检查关系”,那实际上没有什么工程意义,因为我们最后会得到一个几乎无限扩张的关系网络。
所以“偏差可能存在于关系中”还不是答案。
它只是改变了我们应该往哪里看。
真正能够把这件事继续推进下去的,是下一步必须回答另一个更严格的问题:在一条从意图走向现实执行的链路里,究竟有哪些关系是真正承担必要条件的?哪些关系一旦不再成立,就会使上游已经成立的对象无法继续为下游执行提供依据?
只有这个问题被回答以后,“关系”才可能从一种观察方式变成真正可以用于工程判断的边界。
所以第三章写到最后,我并没有感觉我们已经找到了解决方案。
恰恰相反,我们只是第一次把排查范围从方框里面移到了方框之间。
而当所有方框都正常、所有日志都完整、所有组件都能够证明自己没有出错时,真正应该继续追问的,已经不再是:
“还有哪个地方没查到?”
而是:
在这些分别成立的对象之间,究竟有什么东西必须一直成立?
这也是《执行缝隙》接下来真正要进入的问题。
关于《执行缝隙》
《执行缝隙》(The Execution Gap)是 Execution Engineering Trilogy 第一卷。
本书讨论一个基础而关键的问题:
从人的意图,到机器最终改变现实世界,中间究竟发生了什么?
在线阅读
-
繁體中文版 執行縫隙 | Havenlon Research
-
English Edition The Execution Gap | Havenlon Research
-
Amazon Kindle https://www.amazon.com/dp/B0HKYLBK3B
-
Amazon Paperback The Execution Gap: The Structural Discontinuity Between Intent and Action (Execution Engineering Trilogy): Wang, Lin, Wu, Mengting, Zhang, Yong, Deng, Jiang: 9798177903347: Amazon.com: Books
© 2026 Lin Wang / Havenlon.
本文为作者手记,与《执行缝隙》正式书籍正文相互独立。 未经授权,请勿全文转载或用于商业再出版。 引用请注明作者及出处。
网硕互联帮助中心






评论前必须登录!
注册