☰
旧的 VERIFIED 又回来了:如何防止验证状态被迟到消息回滚?
2026/10/2 7:06:53 网站建设 项目流程

这个现象在直播/OTT 系统中并不罕见:验证平面(verification plane)与消费平面(consumption plane)之间存在时间差和传递延迟。当验证器判定当前观测不再支持正向评估时,权威方会发布UNKNOWN;但这条决定在传输链路上可能被延迟、乱序或重复投递,而消费端如果简单地“以最后到达的消息为准”,就会把已经失效的旧VERIFIED重新显示出来。本文要讨论的,正是这种“评估已形成、但传递和使用环节丢失了其含义”的问题。
平台已经发布了UNKNOWN:最近一次观测不再支持当前评估。但随后,一条携带旧VERIFIED的消息迟到,界面又显示“已验证”。

换句话说,问题不在“评估是否正确”,而在“评估结果如何被消费”。验证器、评估权威方和消费端是三个不同的逻辑角色:验证器负责观测并形成证据,评估权威方负责按契约发布决定,消费端负责把已发布的决定投影为当前可报告的状态。前两者可能都工作正常,但消费端如果缺少正确的投影规则,就会在传递延迟、乱序和重复投递面前做出错误判断。
验证器(verifier)的检查本身可能完全正确。平台也可能正确评估了结果,并及时取消了正向状态。错误发生在更下游——应用已发布状态的消费端(consumer)。

第一篇文章讨论了为什么一个仍在播放的频道,会失去当前VERIFIED的依据。现在的问题不同:已经形成的评估,在传递和使用过程中,如何不丢失原来的含义?

这两个约束分别回答两个不同的问题:“我该接受哪一条发布记录?”由修订号围栏回答;“我当前能否使用这条记录?”由时间适用性回答。前者管顺序,后者管时效。二者缺一不可,因为只管顺序会忽略“没有新消息时旧状态过期”的问题,而只管时效则无法阻止“旧消息覆盖新消息”的问题。
这里需要两个不同的约束:

  1. 修订号围栏(Revision fence)——限定已接受快照的顺序,不允许较旧的修订号对应的快照替换已经接受的较新快照。
  2. 时间适用性(Temporal eligibility)——判断当前能否使用正向评估的依据;新到达的消息或同一消息的重复投递,都不会更新原始观测时间。

最后到达的消息,不能替代其中任何一项检查。

1. 验证结果、已发布评估与当前状态

继续分析上一篇文章中的示例性直播/OTT 场景:验证平面降级,当前评估转为UNKNOWN。频道仍然处于PLAYING,源站/CDN 健康,QoE 正常。验证对象不变:

这里需要强调,S是验证对象的完整描述,它决定了“验证什么”。Q_match是一个二元属性:观测到的内容与预期节目一致(MATCH)或不一致(MISMATCH)。验证器在某个观测区间I内、对某个观测范围Ω执行检查,得到MATCH或MISMATCH的结果。这个结果连同其覆盖范围一起,构成证据E。
其中,C是频道,A_e是预期节目,e是配置版本,P是交付路径之后的检查点,R是选定的媒体版本(rendition)。验证属性Q_match表示:观测到的音频和视频,属于预期指定的节目。

这一点很重要:E_last = MATCH并不意味着“整个节目都验证通过了”,而只是说“在I_last这个区间内、Ω这个范围内,观测到的内容与预期一致”。区间之外的内容没有被检查,因此不能从E_last推出任何关于区间之外内容的结论。当新的证据E_new出现时,它有自己的区间I_new,可能比I_last更短或更长,但它不会自动扩大E_last的覆盖范围——每个证据只对其自身观测过的范围负责。
E_last = MATCH只针对实际观测到的范围Ω和区间I_last。后续会出现拥有自身区间I_new的E_new;它不会扩大此前观测的范围。

VERIFIED保留第一篇文章中的有限含义:根据最近一次仍被允许使用的观测,对节目一致性(programme match)作出的当前运行评估,并保留验证对象、覆盖范围和时间。它不是在说,后续每一帧都已经检查过。

为继续分析,先区分三个对象:

对象含义
E验证器形成的限定范围证据。MATCH是针对实际验证范围的结果。
U评估权威方(assessment authority)A发布的不可变完整评估快照,具有自己的修订号。
effective_c(t_u)消费端c在使用时刻t_u有依据报告的当前状态。

这里的评估权威方A只有一个。它是按契约F评估依据并发布决定的逻辑角色,不要求单独部署成一个服务。消费端保存已接受的最大修订号b_c,以及与之对应的快照stored_U_c。

在选择要报告的当前状态之前,必须能从发布记录中确定评估权威方、S、Q_match、修订号、评估及其依据、证据的实际范围、t_obs和适用的F。这些信息是直接传递,还是通过可靠引用还原,属于实现选择。

本例中的发布记录确实来自该权威方,未被损坏,且一个修订号只对应一份确定的内容。S、配置e、验证范围的选择规则和F的版本保持不变。在E_new出现前,没有其他充分依据,也没有其他反证或使原依据失效的变更。这些是示例给定的条件,不能从传输链路没有消息推导出来。

2. 同一发布流,两种投递历史

评估权威方按r1 < r2 < r3的顺序形成三个决定:

U1 / VERIFIED → U2 / UNKNOWN → U3 / VERIFIED

这是针对同一验证对象的决定顺序,不是“真实性程度”不断提高。修订号不是媒体时间戳、配置纪元,也不是证据质量评分。

同一发布流有两个消费端。C_seen及时收到了 U2,而C_lag暂时没有收到。下面追踪正确投影逻辑应有的行为:

步骤评估权威方与验证器C_seenC_lag
T0基于仍可使用的 E_last 发布 U1/r1 = VERIFIED。接受 U1,报告有限含义的 VERIFIED。相同。
T1验证器不可用。没有新结果,但 F 仍允许使用 E_last。此前评估仍可使用。相同。
T2E_last 的使用期限已过,且不存在充分的替代依据。发布 U2/r2 = UNKNOWN。接受 U2,保存 r2,显示 UNKNOWN。U2 被延迟。仍保存 r1/U1,但 F 已不允许报告当前 VERIFIED。
T3验证器恢复响应,但还没有可用于当前评估的新证据。迟到的 U1 副本被投递。因 r1 < r2 而拒绝应用 U1,保持 UNKNOWN。这是 U1 的重复投递。观测没有更新,当前状态仍为 UNKNOWN。
T4基于新的、满足适用条件的 E_new 发布 U3/r3 = VERIFIED。U3 已送达,且在使用时仍满足适用条件。接受 r3,报告有限含义的 VERIFIED。无需先收到 U2,直接接受 r3,报告有限含义的 VERIFIED。
T5旧的 U2 = UNKNOWN 在 U3 之后到达。U3 的依据仍可使用。因 r2 < r3 而拒绝应用 U2,不发生回退。相同。

频道和节目在这里都没有改变。传输只对发布记录产生了延迟、乱序和重复投递。这本身不证明传输系统有故障;这些行为已足以构成本例的条件。

有问题的消费端规则很简单:

最后到达的消息替换当前状态;正向状态一直保持到下一条消息到达。

前半句允许 U1 覆盖 U2。后半句允许C_lag一直显示旧的VERIFIED,即使此后没有任何新消息到达。仅有修订号围栏,或者只在新消息到达时检查适用性,都不足以满足上述过程中的要求。

3. 第一个约束:修订号围栏

首先检查发布记录是否属于同一评估权威方、验证对象、属性和上下文,然后才比较修订号。接受第一个快照之前,b_c = ⊥;它只表示初始时尚无已保存状态,不是允许清空已保存修订号的规则。

收到的发布记录操作
r_i < b_c不替换stored_U_c。
r_i = b_c,且为同一个 U不改变已保存的二元组;这是重复投递。
r_i > b_c将二元组原子替换为(r_i, U_i)。

同一个修订号携带不同内容,不是合法的重复投递。它违反了一份发布记录内容唯一的初始条件;选择“最后到达的那个”并不能解决这个冲突。

用版本号防止迟到状态覆盖较新状态,可以在 AWS IoT Device Shadow 等系统中看到。其 Message order 小节把丢弃旧版本的做法,与示例消息中状态内容的累积性联系起来。这不是对任意命令都可以跳过的通用许可。[1, Message order]

本例允许跳过 U2,有一个具体原因:U3 是完整快照,不是增量。无需执行 U2,就能获得 U3 的评估及其依据。因此,C_lag可以从r1 → r3。只有一个更大的编号,并不能说明可以跳过增量操作或带副作用的操作。

比较与写入是一个动作

在选定契约中,比较修订号并替换(b_c, stored_U_c)是一个逻辑上原子的动作;读取必须得到彼此一致的二元组,状态在整个过程中保持保存。

这些条件很重要。如果检查与写入分开,两个处理器可能都读到旧的b_c,并且都通过比较。若较大修订号写入之后,较小修订号的写入才完成,状态仍会回退。仅仅有一个version字段,并不能防止这个问题。

etcd v3.6 将 Txn 定义为带有比较条件和执行分支的原子条件操作。这是一个合适原语的例子,不证明任意两个客户端调用具有原子性,也不意味着本文为平台选用了 etcd。[2, Transaction; Compare; TxnRequest]

从上表可以直接得到局部单调性:较小的修订号,或相同修订号下的同一份发布记录,都保持原二元组不变;较大的修订号则把它替换成编号更大、内容对应的二元组。每个合法步骤之后,b_c都不会减小。它是已处理的合格发布记录中的最大修订号,不是A已经发布的所有决定中的最大修订号。

实践要点:应该比较的是发布记录的顺序,而不是状态是否“正向”。旧的 UNKNOWN 不能仅仅因为看起来比旧的 VERIFIED 更谨慎,就绕过围栏。

这里约束的是状态投影,不是用于外部共享资源写入的领导者 fencing token。整个示例始终处于同一个配置版本e内。

4. 第二个约束:使用时的适用性

T2 之后,C_lag已知的最大修订号仍是 r1。比较器正常工作,只是它没有收到更新的发布记录。这并不意味着 U1 的依据仍可使用。

契约F在t_u时刻应用:也就是 API 返回响应,或 UI 确定当前显示状态的时刻。它可能晚于权威方形成评估的时刻t_d。观测年龄从原始观测完成时间t_obs(E)起算:

age_obs(E, t_u) = t_u − t_obs(E) F 的时间条件:0 ≤ age_obs(E, t_u) ≤ Δ_F

示例的前提是时钟处于可比较的时间尺度;这里不能代入媒体偏移量。Δ_F仍是具体契约的参数;新鲜度不能替代验证对象的适用性和依据的充分性。消费端不重新执行节目匹配:权威方已经形成快照,消费端检查的是当前使用它的条件。

RFC 9334 的 Appendix A.1 单独讨论了已经评估过的证明结果(Attestation Result)的后续使用:初次评估不提供永久使用许可。对视频系统而言,这只是有限类比。本文的F仍然使用媒体的观测时间,不是 RFC 示例中结果的生成时间。[3, §§10–10.1; Appendix A.1]

RFC 9711 也区分了 EAT 令牌的生成时间与其中各项声明所依据数据的年龄。因此,容器有了新的时间戳,本身并不意味着原始数据也有了新时间;这里不要求采用 EAT 格式。[4, §4.3.1]

保存的是快照,报告的是当前状态

当F允许的使用期限结束,且没有充分的替代依据时,C_lag的状态如下:

已保存的发布记录:U1 / r1 / VERIFIED 原始观测: E_last / MATCH / Ω / I_last 可报告的当前状态:UNKNOWN 原因: F 不再允许使用 E_last; 没有其他充分依据

U1 没有被改写。历史 MATCH 没有变成错误结果,覆盖范围也没有变化。消费端不替权威方创建 r2,也不声称已经收到了 U2。它可以直接说明:“最近接受的修订号是 r1;按 F,其正向依据已不允许用于当前评估。”

没有新消息时,也需要执行这项检查。API 在响应前检查适用性。如果 UI 持续展示当前状态标识,那么使用期限一过,即使更新流保持沉默,也必须取消没有依据的VERIFIED。这里不指定计时器或读取路径的实现方式。

重复投递 U1 不会改变t_obs。去重处理可以不向存储写入任何内容,但这不会取消对当前使用条件的重新判断。对同一快照,在 F 的时间边界前后读取,可能得到不同响应:接收处理的幂等性,不等于状态不会随时间改变。

接受更大的修订号,也不保证当前结果为正向。如果 U3 到达时已经超过自身允许的使用期限,且没有替代依据,可以保存 r3/U3,但报告 UNKNOWN。围栏不会降低。无论是超出使用期限的正向快照,还是已保存的 U2 = UNKNOWN,都不允许选择旧 U1 来回退到正向状态。

5. 为什么两个约束缺一不可

C_lag单独说明了第一条边界:如果新修订号没有到达,仅靠快照顺序无法取消超出使用期限的状态标识。

再看 T5。消费端已经接受了仍可使用的 U3/r3 = VERIFIED,此时旧 U2/r2 = UNKNOWN 到达。如果仍按“最后一条消息替换快照”的规则处理,旧的不确定评估就会覆盖新评估。只检查正向证据的年龄,本身并不能阻止这种覆盖:收到的 U2 根本不是正向快照。

因此,仅测试 U2 之后到达的旧 U1 还不够:U1 既在修订号上更旧,又已经超出 F 的使用期限。在新的、仍可使用的 VERIFIED 之后到达旧 UNKNOWN,才能单独检验顺序保护。

两个约束由此共同发挥作用:

Revision fence → 已接受的快照不回退 Temporal eligibility → 正向状态不能超出 F 允许的使用期限

正向结果不只是“丢弃消息”。在 T4,权威方取得满足适用条件的新证据 E_new,完成检查并发布 U3。U3 确实被送达、被处理,而且在使用时仍满足适用条件。因此,两个消费端都可以恢复有限含义的 VERIFIED。

但围栏不会把缺失的信息送达。已接受的最大修订号,不一定是权威方最新发布的修订号:新的决定,包括负向决定,可能仍在传输途中。本文不承诺消费端立即知道这些决定。例如,etcd v3.6 分别说明了单个 watch 中事件的顺序,以及通知延迟没有既定上界。这体现的是消费端已知信息的边界,不是 etcd watch 内部乱序的例子。[5, APIs to consider; Watch APIs]

U3 没有送达时,不承诺恢复正向状态。如果已接受的 U3 后来超出 F,且没有充分替代依据,当前状态会变成 UNKNOWN,但 r3 保留。这不是在应用旧 U2。

上述结果依赖于一个确定的评估权威方、快照身份与内容一致、原子应用、状态保存,以及可比较的时间。消费端状态丢失后的恢复、权威方切换和全局收敛,都需要额外条件。本文没有为这些情况提供现成实现。

拒绝应用旧 U,并不禁止权威方重新评估已有原始证据,再发布新决定。但在没有新观测的情况下重新打包 E_last,不会改变t_obs,也绕不过 F。

投影逻辑也不发放新的播出许可。在 UNKNOWN 下继续交付,仍是第一篇文章中依据P_continuity作出的单独决定,并且需要满足其条件。

6. 两项实践检查

第一项:重排发布记录,包括旧 UNKNOWN

对同一个A/S/Q_match/F,先应用 U2,再投递 U1。预期保存的二元组仍为 r2/U2,当前状态为 UNKNOWN。

然后应用仍可使用的 U3,再投递旧 U2 和 U1。二元组应保持 r3/U3;有限含义的 VERIFIED 只能在 F 的条件仍然满足时保留。重复投递完全相同的 U3,不改变修订号、证据身份或t_obs。

不要只检查服务内部的编号,还要检查 UI 主状态和 API 响应。如果后端遵守围栏,而界面直接应用迟到事件中的 status,端到端检查仍然不通过。

第二项:没有新消息时的到期行为

让C_lag保持 U1/r1,并延迟 U2。在 F 的边界之前,且其他条件均满足时,可以报告有限含义的 VERIFIED。越过边界、且没有充分替代依据之后,应报告当前 UNKNOWN——既不改写 U1,也不虚构 r2。

再投递一次 U1:接收时间是新的,但t_obs和覆盖范围不变。正向状态标识不应重新出现。随后投递仍可使用的 U3:无需先收到 U2,就应能完成 r1 → r3。

检查时,对照最后接受的修订号、证据引用及其实际范围、t_obs、F、使用时刻和真正的 API/UI 输出。这些是给定预期结果、可复现的检查步骤,不是已经执行过的生产测试报告。

**带回自己系统的检查要点:**检查系统按什么选择最后接受的快照,以及新消息不再到来时,屏幕上还保留着什么。依据到期不应清空围栏;验证器恢复也不能替代新观测。

正确形成评估还不够。还必须保留其应用顺序,以及当前使用的边界。历史上发布过 VERIFIED 这一事实不变,但它不自动赋予现在继续显示 VERIFIED 的权利。


参考资料

[1]AWS IoT Device Shadow service.AWS IoT Core Developer Guide,持续更新的 HTML 文档。Message order:消息顺序与累积状态内容。所用内容已在 2026-09-28 的 Source Stage 中核查。

[2]etcd API, v3.6.Transaction;Compare;TxnRequest:原子比较及其条件分支中的操作。

[3]RFC 9334 — Remote ATtestation procedureS (RATS) Architecture.2023 年 1 月,Informational。§§10–10.1;Appendix A.1:新鲜度与已评估结果后续使用的限制。

[4]RFC 9711 — The Entity Attestation Token (EAT).2025 年 4 月,Standards Track。§4.3.1:令牌生成时间与各项声明所依据原始数据的年龄。

[5]etcd API guarantees, v3.6.APIs to consider;Watch APIs:通知顺序,以及通知延迟没有既定上界。Source Stage 核查的页面页脚日期为 2025-09-26。

本文的 F 和消费端契约由作者定义;外部示例只支持文中明确限定的区分和原语。它们不能证明具体部署的节目匹配准确率,也不能证明其时钟、原子性或 UI 机制实际正确工作。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询