qinghuan
← 回到知识探索

后端现场 / 动手实验

日志里先收到、后发送,是时间倒流了吗?

机器时间、日志到达时间和事件之间的先后关系,需要用不同证据判断。

展开本文目录
  1. 先分清你排的是什么时间
  2. 逻辑时钟记录顺序,不记录毫秒
  3. 数字较小,不一定就是另一个事件的原因
  4. 用请求关系把日志连起来
  5. 记住这三点
  6. 别把例子用过头
  7. 自己试一小步
  8. 查原始资料
  9. 找一份资料继续练
开始前,会这些就够了
  • 知道两个服务可以互发请求
遇到不熟悉的词,先看这 1 个解释
日志与链路追踪
日志记录某处发生的事件;链路追踪把一次请求在多个组件中的操作及关联关系连接起来,帮助查清走过哪些步骤、哪里耗时,而不只看零散文字。
打开完整术语小抄 ↗

假设服务甲记录“发送订单请求:100 毫秒”,服务乙记录“收到请求:90 毫秒”。合并日志按时间排序,接收竟跑到发送前面。最先要检查的是两台机器的时钟和记录方式,而不是宣布网络产生了负延迟。这是一组假设时间值,不是真实机器测量。

先分清你排的是什么时间

日志可以带事件发生时的机器时间,也可以带日志平台收到它的时间。前者可能受机器之间时钟偏差影响;后者还受到缓冲、批量发送和网络延迟影响。一条记录先出现在搜索结果里,只能说明某种排序或接收顺序,不能直接证明业务先发生。

同一条消息的发送必然先于它被接收,这是消息关系提供的证据,不依赖两台机器显示的数字是否一致。Lamport 的 happened-before 关系还包含同一顺序进程内部的先后,以及这些关系的传递。没有这样的关系时,不能硬给两个事件编造业务依赖。

逻辑时钟记录顺序,不记录毫秒

一种简单做法是给事件记递增计数。发送时携带自己的数,接收方把计数推进到比自己和消息中的数都大。下面让甲发送时记一,乙收到后记二;即使假设墙上时钟分别显示一百和九十,计数仍尊重这条消息的先后关系。

程序只有一条已知消息,整数值不表示经过了多少时间。甲到乙的逻辑计数增加一,并不能推出耗时一毫秒;用来算本机持续时间时,需要选择适合测量时长的时钟接口,不能拿这些逻辑计数相减当作延迟。

小实验 · python
a_clock = 0
b_clock = 0
a_clock += 1
message_clock = a_clock
sent = {"event": "A send", "wall": 100, "logical": a_clock}
b_clock = max(b_clock, message_clock) + 1
received = {"event": "B receive", "wall": 90, "logical": b_clock}
events = [sent, received]
for key in ("wall", "logical"):
    print(key, [e["event"] for e in sorted(events, key=lambda e: e[key])])

怎样运行:Python 3.10+;保存为 clocks_demo.py,运行 python clocks_demo.py。

运行后对照结果
wall ['B receive', 'A send']
logical ['A send', 'B receive']

数字较小,不一定就是另一个事件的原因

正确维护的 Lamport 时钟保证:如果甲事件在这种关系上先于乙,甲的计数就更小。反过来却不成立。一个完全没和甲通信的服务,也可能因为自己做了很多事而记到一百;不能据此说甲引起了它的事件。排序可以给出一种排列,却不自动补出因果证据。

并行执行的两个操作可能没有可比较的先后关系。为了展示,把它们按机器名或编号打破平局是合理的界面决定,但应该标明这只是显示顺序。把所有日志强制排成一列,有时反而会让读者误以为每一行都依赖上一行。

记住这三点

  • 机器时间排序和日志收集顺序都不等于完整业务先后。
  • Lamport 时钟保持已知先后关系,但逻辑数值不是耗时。
  • 逻辑计数较小不能反向证明因果,需要消息或执行关系。

别把例子用过头

  • 示例是两事件模型,未实现分布式时钟、消息重试或追踪系统。
  • happened-before 表示可影响的顺序,不是对业务根因的自动证明。
  • 没有日志不等于事件没发生,采样与丢失都需要考虑。

自己试一小步

加入一个没有和甲乙通信的服务丙,能否只凭逻辑时钟把它放进这条因果链?

  1. 为丙构造两个独立事件,并设置递增计数。
  2. 分别按机器时间与逻辑计数展示所有事件。
  3. 只为确有消息或本地先后证据的事件画箭头。

做到这些,就算完成

  • 不把展示顺序当成因果关系。
  • 能说明逻辑计数无法计算网络耗时。
  • 明确哪些事件之间仍然无法确定先后。

查原始资料

想确认一个细节,先看这份资料对应的部分,不必从头读完所有文档。

  • Time, Clocks, and the Ordering of Events in a Distributed System (新标签页)↗Leslie Lamport 作者网站 · 英文

    1978 年论文第 2–3 页支持 happened-before 定义、消息先后、逻辑时钟条件,以及反向推断不成立。

    作者托管的公开英文 PDF,共 8 页;1978 年原论文,重点是事件先后关系与逻辑时钟。

  • Trace Context (新标签页)↗W3C · 英文

    支持 traceparent 的 trace-id、parent-id 与上下文传播;用于说明链路关联而非时钟同步。

    公开英文 W3C 标准;说明请求间如何携带链路关联信息,不负责校准机器时钟。

找一份资料继续练

先选一项,按下面的范围继续学;不必从头读完整门课程。