GH GambleHub

Exactly-once语义

什么是exactly-once实际上是

"Exactly-once"通常被理解为两种不同的东西:
  • 交付:消息将恰好传递给消费者一次。
  • 处理:最终副作用(DB记录,平衡变化,其他事件的发射)将恰好发生一次,即使交付或尝试更大。

在分布式系统中,谈论处理语义更为可靠。交付完全难以提供(重复和重复是不可避免的),但是可以使最终状态等同于单个处理。


何时需要EOS,何时不需要

需要EOS,如果:
  • 现金交易和资产负债表:双重注销是不可接受的。
  • 许可证/配额核算,计费表。
  • 不可逆的外部调用(例如,一次性密钥激活)。
如果:
  • 效果是可逆的或可补偿的(传奇,回报)。
  • 允许在店面/徽标中临时重复。
  • 比将交易拖过整个路线便宜。

模型: 终端vs. hop-by-hop

Hop-by-hop EOS:每个部分(源→处理器→接收器)确保其操作正确应用一次。
终端EOS:整个链确保从"事实"到"侧面效应"的结果等同于单个处理。

实际上,通过在每个跳上结合事务和/或幂等来实现端到端。


基本构件

1.等效手术

在操作密钥上重复相同的请求会产生相同的结果。

Ключи: `idempotency_key`/`event_id`/`operation_id`.

实现:TTL的"所见"运算表≥输入日志的拒绝。

2."Read-process-write"交易)

在一个原子单元中,工作记录了副作用和阅读进展(正面/位置)。这消除了"鬼魂"在步骤之间的下降。

3.Version/SEQUENCE

对于单元,存储版本/计数器;仅当"expected_version"匹配时才应用更改。相同事件的重播不会一次增加版本→效果。

4.重复数据消除

索引通过"(consumer_id,event_id)"或自然的"business_id"操作。


实现模式

1)带有正交提交的Transactional Log+ Transactional sink

非常适合流处理。

我们从日志中阅读(仅确认记录)。
我们正在进行处理。

在一个事务中:
  • (a)将效果写成sink (DB/表),
  • (b)以"读到ofset N"(在同一DBD)记录。
  • Commit。在重新开始时,要么全部被埋葬(并且将移位),要么一无所有。

属性:重复执行不会伤害;效果上的"恰好一次",即使消息读了两次。

2) Outbox+偶数消费者

用于事务制作服务。

在一个DB事务中:我们修改域条目并在outbox中编写事件。
Republicator使用相同的"event_id"将事件传递到总线。
消费者平均应用事件("event_id"的前提)。

属性:制作人确保事实不会丢失;消费者保证一个效果。

3)Kafka/Flink样系统中的EOS(概念上)

相同的制作人:在发货回程时防止拍摄。
制作人交易:一组录音到拓扑+consumer移位在原子上进行;读者使用"read_committed"隔离。
处理方存储状态(state store)并将其与事务一起发布。

属性:重新启动托架/塔斯卡不会产生双重效果;复制的"不可见"下游。

4)通过upsert/merge进行异位的"siki"(sinks)

Sink接受"operation_id"/"event_id"并执行"UPSERT……WHERE NOT EXISTS`.

副作用(例如权重)在原子上执行,并检查"是否已应用"。

属性:便宜的EOS方法与存储边缘,没有分布式事务。


实现的关键细节

操作标识符

必须确定重播(不要在转发时生成新的UUID)。
具有稳定的可见性区域(每个消费者/每个单元/每个系统)。

重复数据消除表

Колонки: `consumer_id`, `operation_id`, `applied_at`, `ttl_expires_at`.

"(consumer_id,operation_id)"索引。
TTL ≥最大重播窗口(log retency+潜在延迟)。

乐观的竞争

在write模型中,存储单元版本。
当应用事件/命令时,请使用"WHERE版本=:expected";复制不会增加版本。

订单/顺序

EOS不等于"完全相同的顺序"。通过批次密钥(所有聚合事件→单个批次)和/或比较"序列"来确保一致性。

异位外部挑战

对于不安全的方法(例如HTTP webhooks到第三方服务),请添加"Idempotency-Key",并要求合作伙伴支持它。


频繁的陷阱

EOS只在一个地方:如果sink是偶然的,但是您会在没有偶然性的情况下发布次要事件,则将获得"完全多次"下游。
两种commites:首先在DB中,然后在经纪人中商量ofset-它们之间的下降会产生重复的效果。
原始CDC向外:DB计划的改变打破了消费者的平均水平。
不稳定的键:"operation_id"取决于时间/随机,并在转发时更改。


成本和权衡

潜伏期:交易/孤立阅读→ p95/p99增长。
跨存储:重复数据消除表、状态存储、事务日志。
操作难度:交易定时,线程重组,"折叠"会话。
诊断:更多状态("kamite","显示为read_committed","滚动")。

逐点选择EOS:用于关键聚合和效果;其余的则由等效性和补偿性覆盖。


exactly-once测试

1.断层喷射:步骤之间的过程下降"记录了效果"和"记录了正交"。
2.重复:将相同的消息抽出2-5次,确保一个效果。
3.重新启动和重新调整:停止/重新启动窃贼,检查是否存在双重处理。
4.Network flappy:在事务中间的时间间隔,commit重播。
5.负载测试:队列增长→是否降级为"永久事务"。


迷你模板(伪版)

具有正交固定功能的Idempotent sink

pseudo begin tx if not exists(select 1 from dedup where consumer_id=:c and op_id=:id)
then apply_effect(...)    -- upsert / merge / add_one_time_action insert into dedup(c, id, applied_at) values(:c,:id, now)
end if update offsets set pos=:pos where consumer_id=:c commit

具有聚合版本的命令

pseudo begin tx update account set balance = balance +:delta,
version = version + 1 where id=:account_id and version=:expected_version;
if row_count=0 then error CONCURRENT_MODIFICATION commit

安全和合规性

PII/PCI在重复数据消除表中:存储最小值,使用令牌代替"原始"数据。
审计:编写"operation_id","trace_id",结果(APPLIED/ALREADY_APPLIED)。

保留策略: TTL在dedup表上,归档期权/log.


反模式

"真正的exactly-once交付":试图消除传输协议级别的双打,而没有效果的幂等。
全局分布式事务到所有:通过所有服务的XA/2PC是脆弱和缓慢的。
混合非偶数小袋(例如,电子邮件发送到ofset commit)。
缺少操作密钥:重视有效载荷的"唯一性"。


生产支票清单

  • 在每个关键效应上都有等效键。
  • Ofset/读取位置被固定在一个具有效果的事务中。
  • 已对重复数据消除表进行索引;TTL ≥博客的关注。
  • 对于单元,包括乐观的竞争(版本/序列)。
  • 流/拓扑以"仅加密"模式(如果可用)读取。
  • CI/CD中存在重复和下降测试。
  • Dashbords:重播、交易失败、锁定时间、滞后率。
  • 关于"Idempotency-Keu"/重复/时间表的集成商文档。

FAQ

无需事务即可提供EOS?

通常,是的-通过sink's(upsert/merge)的幂等性和单元的旋转。交易简化了保修,但增加了成本。

每个人都需要一个"exactly-once"吗?
没有。他是道路。在无法补偿的地方/道路上逐点应用。

如何将电子邮件/webhooks链接到EOS?

将通知缓冲到commit,在提交效果后发送;保存"notification_id"并使发送具有等效性。

更重要的是-交付或处理?

处理。交货可能会重复;最终状态必须正确且唯一。


结果

Exactly-once是关于效果的正确性,而不是关于布线中缺少配音。它通过相容性,原子锁定效果和阅读进展,合理分期和考试纪律的结合来实现。将EOS应用到错误成本不可接受的地方,并通过跌倒和双打测试检查其现实-不相信运输。

Contact

联系我们

如需任何咨询或支持,请随时联系我们。我们随时准备提供帮助!

开始集成

Email — 必填。Telegram 或 WhatsApp — 可选

您的姓名 可选
Email 可选
主题 可选
消息内容 可选
Telegram 可选
@
如果填写 Telegram,我们也会在 Telegram 回复您。
WhatsApp 可选
格式:+国家代码 + 号码(例如:+86XXXXXXXXX)。

点击按钮即表示您同意数据处理。