复制和事件一致性
复制和事件一致性
1)为什么要有意识的
当系统分布在区域/区域中时,同步记录会给网络故障带来高潜伏性和低可用性。Eventual consistency(EC)允许出于以下原因暂时对副本进行同步:- 低记录延迟(本地接收),
- 在网络分割时提供更好的可用性,
- 水平缩放。
关键问题是可控的非严格一致性:用户看到"足够新鲜"的数据,域不变性得以保留,冲突被检测并可以预测地解决。
2)一致性模型-我们向客户承诺什么
Strong: reading立即看到最后一个条目。
Bounded stale/read-not-older-than (RNOT):读取不会老化标记(LSN/版本/时间)。
Causal:保留了"因果关系"(A到B)。
阅读你的写作:客户看到他们最近的录音。
Monotonic Reads:以下每个读数不是"回滚"。
会议:一届会议的一套保障措施。
Eventual:如果没有新条目,所有副本都会收敛。
实践:结合关键路径上的Session+RNOT和店面/缓存上的Eventual。
3)复制: 力学与抗创作
同步(法定人数/RAFT):记录在N节点确认后被认为是成功的;最低RPO,高于p99。
异步: 领导者向本地推销,稍后分发日志;低潜伏期,RPO> 0.
物理(WAL/binlog):快速,均质。
逻辑/CDC:字符串/事件级别的更改流,灵活的路由,过滤器。
反灌木丛:周期性钻孔和修剪(Merkle树,哈希比较,背景重新同步)。
4)版本标识符和因果关系
单调版本:increment/LSN/epoch;简单但不编码并发。
Lamport timestamp:按逻辑时钟的部分顺序。
Vector clock:捕获平行分支并允许检测冲突升级(concurrent)。
Hybrid/TrueTime/Clock-SI:全球秩序的逻辑"不早于T"。
建议:对于CRDT/冲突升级-矢量时钟;对于"不老化"-LSN/GTID。
5)冲突: 检测和解决
类型情况:从两个区域写入同一对象。
策略:1.最后的写作-胜利(LWW)在时钟/逻辑模具上-很简单,但可能"丢失"升级。
2.域逻辑中的Merge函数:- 计数字段折叠(G-Conter/PN-Conter),
- 集合为"add-wins/remove-wins",
- 金额/余额-仅通过事务日志而不是通过简单的LWW。
- 3.CRDT(融合类型):G-Counter,OR-Set,LWW-Register,RGA用于列表。
- 4.操作转换(DB很少,编辑更常见)。
- 5.手动解决:"inbox"中的冲突,用户选择正确的版本。
规则:域不变量决定策略。对于金钱/余额-避免LWW;使用具有补偿的交易/事件。
6)记录保证和偶数
命令上的等效密钥(payment、withdraw、create) →重播是安全的。
通过偶数键/序列号在"输入"(inbox)和"输出"(outbox)上进行重复数据消除。
没有强大的先决条件,就无法实现仅Exactly。练习-least-once+等效性。
Outbox/Inbox模式:在DB中写入并发布atomarna事件(本地事务),收件人通过idempotency-key处理。
7)阅读"不老化X"(RNOT)
技术人员:- LSN/GTID门:客户端传输最小版本(来自记录响应),路由器/代理路由到赶上LSN ≥ X的副本,否则发送到领导者。
- Time-bound:"不要老化2秒"是没有版本的简单SLA。
- Session pinning:录制N秒后,我们只阅读领导者(Read-Your-Writes)。
8)更改流和缓存匹配
CDC →事件总线(Kafka/Pulsar)→消费者(缓存,索引,店面)。
缓存残疾:拓扑"invalidate:{ns}:{id}";idempotent处理。
Rebuild/Backfill:在同步时,从事件日志中重新设置投影。
9)传奇与补偿(服务间交易)
在EC世界中,长寿操作分为具有补偿作用的步骤:- 编排:协调员调用步骤及其补偿。
- 编舞:步骤响应事件并自行发布以下内容。
不变量(示例):"平衡≥ 0"-在步长边界上检查+拒绝时的补偿。
10)多区域与网络分离
本地write, async-replicate:写入本地区域+交付给其他(EC)。
Geo-fencing:数据被粘贴到区域(潜伏率低,冲突更少)。
CP数据的法定数据库(Raft);缓存/店面-AP/EC。
Split-brain计划:当通信丢失时,区域将继续在域限制(写入设置,配额)内运行,然后是重新连接。
11)可观察性和SLO
度量标准:- Replica lag: 时间/LSN距离/疏远(p50/p95/p99)。
- Staleness:超过阈值的响应比例(例如>2s或LSN
- 冲突率:冲突频率和成功交易。
- Convergence time:复制副本在峰值之后的收敛时间。
- Reconcile backlog:滞后部分的数量/时间。
- RPO/RTO按数据类别(CP/AP)。
- Lag>目标,冲突增加,"长"不相容窗口。
12)在EC下设计数据电路
每个条目中的显式版本/向量("version","vc"列)。
用于临界不变量(平衡,权重)的仅附录日志。
事件标识符(snowflake/ULID)用于顺序和重复数据消除。
具有可交换性质(计数器,集合)的字段→ CRDT的候选字段。
API设计:带有if-match/etag的PUT,带有precondition的PATCH。
13)存储和阅读模式
阅读模型/CQRS:写入"源",从投影读取(可能滞后→显示"更新"……)。
Stale-OK路线(目录/磁带)vs Strict(钱包/限制)。
查询中的sticky/Bounded样式标志(标题"x-read-consistency")。
14)实施清单(0-45天)
0-10天
分类数据:CP关键(金钱,订单)vs EU/stale-OK(目录,搜索索引)。
定义SLO steil(例如"不老化2s"),目标泻药。
在API中启用对象转换和idempotency-keys。
11-25天
引入CDC和outbox/inbox、缓存故障路由。
在记录关键路径上添加RNOT (LSN门)和session pinning。
实施最少一个merge策略(LWW/CRDT/域)和冲突日志。
26-45天
自动化anti-entropy(支架/支架)和steel报告。
玩游戏日:网络分离,冲突激增,恢复。
在dashbords上可视化:lag, staleness, conflict rate, convergence。
15)反模式
关键不变量的盲人LWW(金钱/分数损失)。
缺少idempotency →后退手术。
"强大"模型→ p99尾巴过多,故障时易碎。
没有RNOT/会话保证 → UX"闪烁",用户"看不到"他们的更改。
缓存和源的隐藏同步化(没有CDC/残疾)。
缺少reconcile/anti-entropy工具-"几个世纪"的数据存在分歧。
16)成熟度量
Replica lag p95 ≤目标(例如,该地区内≤ 500 ms,≤ 2 s跨区域)。
Staleness SLO ≥ 99%的"严格"路线请求执行。
Conflict resolution success ≥ 99.9%,平均分辨率时间≤ 1分钟。
高峰后的会议时间是几分钟,不是时钟。
100%的"现金"交易由idempotency密钥和outbox/inbox覆盖。
17)食谱(snippets)
If-Match/ETag (HTTP)
PUT /profile/42
If-Match: "v17"
Body: { "email": "new@example.com" }
如果版本更改为"412 Precondition Failed" →客户端将解决冲突。
请求"不老化LSN"(伪)
x-min-lsn: 16/B373F8D8
路由器选择带有"replay_lsn ≥ x-min-lsn"的副本,否则为领导者。
CRDT G-Counter(想法)
每个地区都有自己的柜台;结果-所有组成部分的总和;复制-操作是可交换的。
18)结论
Eventual consistency不是质量权衡,而是有意识的合同:在某些地方,我们为速度和可用性支付新鲜度,但通过域策略和工具保护关键不变性。输入版本、idempotency、RNOT/Session保修、CDC和防漏洞,测量lag/staleness/conflicts-您的分布式系统即使在故障和峰值负载下也能快速、稳定且可预测地收敛。