08.03 复制的目标与代价:确认到哪一层才可读
返回第八卷 · 部分失败前置:08.01 · 时间前置:08.02 · 数据库复制前置:06.11
08.03 复制的目标与代价:确认到哪一层才可读
DeepTutor 八节初稿经技术与教学审阅后的静态课程。P、R1、R2、毫秒数、日志/回放位置和 1 KiB 账本都是虚构教学模型;没有运行 PostgreSQL、MongoDB、Go、故障切换、压测或站点,也不声称 OpenIM 使用该拓扑。当前 S2 的
200 accepted_in_memory仍只保证进程内受理;S3 v2stored_in_teaching_db仅为未来教学合同提议。
一、再复制一份,是为谁解决什么问题?
06.11 已看到:c-a 的 seq=9 在主库提交,不等于读副本立即看得见。08.01 又说明节点与链路可局部失败,08.02 说明不能拿多机墙钟代替事件顺序。本章固定三节点:P 是当前权威写主库,R1/R2 是它的两个副本。会话已有 seq=1..8;A 新发 m-9,P 给它 seq=9。为了分清复制里程碑,我们只讨论一个未来教学数据库提交情景,不改写现有 S2 HTTP 语义。
复制可能服务三个不同目标:P 故障时另有节点可接管;把允许陈旧的历史读分担到副本;在另一地点保存额外数据副本。目标不同,所需确认点、可接受陈旧、RPO/RTO也不同。副本不能自动代替备份:一次误删或错误更新可能照样传到副本;若要找回误删之前的历史,仍要备份、日志归档与恢复演练。PostgreSQL 高可用与复制
| 第一遍 | 第二遍 | 交付物 |
|---|---|---|
| 主/副本、接收/持久/回放、读可见 | 同步确认、切换选择、成本、跨引擎口径 | P/R1/R2 时间线、一张确认矩阵、一份业务读写取舍 |
二、每份副本要花什么:空间、网络、写等待与读旧值
多一份副本会用额外存储、网络带宽和回放 CPU,也需要监控滞后、日志保留、重建与切换。若用独立纸上单位假设一条已编码的记录占 1 KiB,在 P/R1/R2 各保一份,光这条记录的三份数据就是 3 KiB;还没算索引、WAL/oplog、副本元数据或备份。这个 1 KiB 与本项目 HTTP 练习中的消息正文最多 6 B是两种不同口径,不能拿“3×6 B”冒充存储成本。
写入确认若要等远端,正常路径可能增加网络与副本刷写/回放等待;副本不可用时还可能使请求等待或不能达成所选确认。读流量分到副本可能减轻 P 压力,却带来旧数据、回放冲突和选错副本的风险。把“复制提升可用性”和“复制使所有读取一致”合成一句话会掩盖代价;需要先决定哪类 IM 操作允许读旧值。PostgreSQL Streaming Replication · MongoDB Replication
可交付的成本账至少列:每秒新增消息与变更字节、每副本接收/回放速率、主库保留日志空间、远端确认增加的写入 P95/P99、读请求中必须写后读的比例、可接受复制延迟和故障切换目标。这里没有任何真实数值,不能凭玩具 3 KiB 推出线上机器数或性能收益。
三、P/R1/R2 手算:日志已在 R1,不等于 R1 查询可见
固定单条消息的纸上时刻,均相对于同一次请求起点;不是从三台机器各自墙钟读出来的实测时间。表中“读 R1”都假定当时新建的查询快照,不代表已开始的长事务会自动换快照:
| 时刻 | P | R1 | R2 | 读 R1 最新历史 |
|---|---|---|---|---|
| t=0 | c-a 已有 1..8 | 已回放 1..8 | 已回放 1..8 | 8、7、6 |
| t=10 ms | 本地 WAL 按本题假设持久,seq=9 已提交 | 尚未确认 9 | 仍只到 8 | 8、7、6 |
| t=40 ms | 已提交 9 | 日志已持久到 9,但尚未回放 | 仍只到 8 | 仍可能是 8、7、6 |
| t=70 ms | 已提交 9 | 已回放 9,新查询快照可见 | 仍只到 8 | 9、8、7 |
副本进度要分接收/写入、持久 flush、回放 apply、该次查询可见。R1 的日志在 t=40 已安全,不表示热备表/索引状态已回放到 9;R2 到 t=70 仍只能按自身旧状态回答。读 P 在其已知提交后可看 9,但仍须核对会话权限和查询游标;若条件是 seq<7,即使 R1/P 状态不同,也都可能返回 6、5、4。PostgreSQL 的复制位置可用 WAL LSN 观察,c-a.seq=9 不等于某个 LSN 数字。PostgreSQL 流复制与监控
P 本机提交 9 (t10) ──> R1 日志持久 9 (t40) ──> R1 回放可见 9 (t70)
└────────────────────────────> R2 仍停在 8四、同步确认要写出“等到哪里”,不能只写“同步了”
仍用上述时刻,比较纸上候选确认条件:只等 P 的本地持久边界,最早对应 t=10;若配置要求R1 作为选定同步备库且等它持久日志,最早对应 t=40;若要求 R1 回放可见,最早对应 t=70。三种等待越向后,给客户端的承诺越强,正常写入等待也越长。实际时间不固定,不应把 10/40/70 ms 当系统参数或测试结果。
| 候选承诺 | 本题最早可答时刻 | 答复时仍不能推出 |
|---|---|---|
| P 本机同步持久 | t=10 | R1/R2 已收到或可读 |
| 所选 R1 远端持久 | t=40 | R1 已回放;R2 可读 |
| 所选 R1 远端回放 | t=70 | 所有副本都可读;B 设备已收到 |
PostgreSQL 的具体选项必须和同步备库配置一起读。没有同步备库时,synchronous_commit=on 的本地持久确认不等于某个 R1/R2 已回放;配置了同步备库后,remote_write、on 所等待的远端持久、remote_apply 所等待的远端回放是不同里程碑。remote_write 还不等于远端 OS 崩溃后必然持久。remote_apply 只能说明被要求确认的同步备库达到回放点,不能推到其他异步副本。PostgreSQL WAL 同步模式 · PostgreSQL 同步复制
若等待远端时连接断开或超时,客户端仍可能不知道最终提交结果;“没收到成功”不是“P 必未写”。确认策略需要连同 A 的状态查询、稳定 message_id 与 08.01 的部分失败模型审阅。当前 S2 accepted_in_memory 是另一种较早的进程内承诺;未来 v2 stored_in_teaching_db 也须写清本机 WAL、远端确认和故障范围,不能只靠一句状态字符串宣称任意副本已可读。
五、切换时不能只挑“还活着”的副本
在 t=40,P 与 R1 已持久拥有 seq=9 的日志,R2 仍只到 8。若 P 失联,恰好 R1 也不可用,系统为了尽快恢复写入而盲目提升 R2,新权威可能缺 9。即使原先已有两份持久副本,也不意味着“任意幸存节点都能安全接管”。候选需要核对安全日志/回放位置,旧主还须被隔离防止它恢复后继续写;可用性和已确认数据的 RPO 有真实取舍。PostgreSQL Failover
两份存储不是多数共识协议的替代品。 是否能避免已确认提交丢失,取决于确认集合、选举/提升规则、持久性、成员故障和旧主 fencing 是否匹配;后续 08.06 才推导交集与任期。本章不由 P/R1/R2 纸上表宣称“2/3 已确认就永不丢”。如果实际提升了只到 8 的 R2,A 的 m-9 可能从新权威历史消失,必须以稳定 ID 与原 P/R1 的残余证据对账,按原合同告知未知或恢复中,不能简单换新 ID 重发。06.11 已单独处理迁移与回退窗口。
RPO 问可接受丢多少已确认或未确认数据,RTO 问多久恢复服务。提升较落后的 R2 可能缩短等待却扩大丢失窗口;坚持等 R1 恢复可能保留更多已确认消息但让服务停更久。实际产品要先定目标和失败政策,不存在无条件“又最快又零丢”的纸上答案。副本还不能代替备份:误删、错误权限更新也可能被忠实复制。
六、历史读扩展要按业务选择一致性边界
在 t=40,A 发完 m-9 立刻刷新“最新三条”:读 P 可能得到 9、8、7,读 R1 或 R2 可能只得到 8、7、6。到 t=70,R1 回放后新查询快照可给 9、8、7,R2 仍可能只给 8、7、6;既有长事务快照还须按隔离级别另判。若产品向 A 承诺“确认发送后立刻在历史中可见”,可以把这次读路由到权威节点,或携带可核对的提交位置等待目标副本回放到位后再读;不能只因连接到了“某台副本”便认为可见。等待也需要期限与降级政策。PostgreSQL Hot Standby
读取早期历史若允许短暂陈旧,可评估从副本分担流量,但要明确最大陈旧、路由、重试和回放指标。授权读写不能偷用旧成员副本决定最新发送资格:退群已在 P 生效,R2 仍显示活跃时,应用若凭 R2 放行新写,会违反 06.07–06.08 的业务顺序。查询历史也要按当前可见范围核对权限,不能把“副本可读”当成“谁都可读”。
read scaling 本身还会消耗副本 CPU/内存,长期查询可能影响回放或与清理冲突;它不是免费容量。测量时把 P 写入 P95、各 R 的接收/持久/回放差、历史读 P95、返回旧结果的比例与回退到 P 的数量放在同一窗口;不要把“副本多”直接报作用户体验已改善。
七、MongoDB:写关注与读偏好必须各说各的
MongoDB 副本集的次节点异步应用主节点 oplog。w:1 请求主节点确认,切换前未复制的写可能回滚;w:"majority" 要求按该副本集版本/拓扑的多数写关注条件确认,不表示每个 secondary 都已应用到可读状态。j:true 关注所要求成员的 journal 持久确认,单独的 journal 条件并不保证旧主切换后写一定保留;wtimeout 到时返回写关注错误,不会撤销已经完成的修改。所有口径都要按实际部署配置核对。MongoDB Write Concern · MongoDB Replication
读取侧再看 readPreference/readConcern:非 primary 的读偏好可选落后副本,可能看到旧历史;写关注更强,也不能推出任意一次副本读必见刚写内容。若有因果会话/指定读关注,它们的前提和范围必须另审。不能把 PostgreSQL 的 remote_apply、WAL LSN 或热备语法直接套成 MongoDB 的参数。MongoDB Read Preference · MongoDB Read Concern
八、交付确认矩阵与代价说明
交付 P/R1/R2 的 t=0/10/40/70 时间线、一张本地/远端持久/远端回放的确认矩阵、一份“若只剩 R2 是否提升”的取舍记录,以及 A 写后读路由/等待方案。每项都写清业务结果、故障模型、权威证据与用户可能看到什么;不凭玩具时间和副本数给真实 SLO 结论。
分层练习与反馈
1–8 先练复制词汇,9–16 推演水位与确认,17–22 面向 IM 的切换与成本评审。先预测,再展开答案。
1. P、R1、R2 在本题分别是什么?
P 是当前权威写主库,R1/R2 是复制它变化的两个副本。
2. 主库本机提交 `seq=9`,能直接证明 R2 可读 9 吗?
不能。R2 可能尚未收到、持久或回放该变化。
3. “R1 已持久日志”与“R1 热备查询看见 9”一样吗?
不一样。R1 在 t=40 已持久日志但未回放,查询仍可能只见到 8。
4. 会话 `seq=9` 能直接当 PostgreSQL WAL LSN 比较吗?
不能。前者是会话内业务顺序,后者是数据库日志位置。
5. 多一份副本是否等于多一份可回到误删前的备份?
不等于。误删/错误更新可能被复制,仍需要独立备份与恢复点。
6. 本题 1 KiB×3=3 KiB 是完整存储成本吗?
不是。它只数三份玩具记录数据,未算 WAL、索引、元数据、备份、网络与运维。
7. 1 KiB 玩具记录与当前正文 6 B 上限是同一单位对象吗?
不是。6 B 是教学 HTTP 消息正文限额,1 KiB 是本题另设的已编码记录成本单位。
8. 有三台节点,就能把每次历史读均分且永不读旧值吗?
不能。副本可能滞后,且读负载也会影响其资源/回放;须按业务一致性要求路由。
9. t=10 时谁已按本题假设持久 9?
只有 P;R1 尚未确认 9,R2 停在 8。
10. t=40 时 R1 的日志与查询各到哪里?
日志已持久到 9,但未回放,查询仍可能只见到 8。
11. t=70 时 R1、R2 各自最新历史三条是什么?
R1 已回放 9,得 9、8、7;R2 仍到 8,得 8、7、6。
12. 本题只要求 P 本地持久,最早对应哪个时刻?
t=10 ms。它不代表任何副本可读。
13. 若要求所选 R1 的日志持久,最早对应哪个时刻?
t=40 ms;仍未保证 R1 热备查询看到 9。
14. 若要求所选 R1 回放可读,最早对应哪个时刻?
t=70 ms;不能外推到仍停在 8 的 R2。
15. PostgreSQL 没有配置同步备库时,`synchronous_commit=on` 意味所有副本回放了吗?
不是。其本地同步边界不能直接变成远端回放承诺。
16. `remote_write` 与远端持久 flush、`remote_apply` 是同一条件吗?
不是。它们分别处于远端写入、远端持久和远端回放的不同里程碑;须结合同步备库配置。
17. t=40 P 与 R1 有 9,盲目提升只到 8 的 R2 有什么风险?
新权威可能缺失已在 P/R1 持久的 9;两份存储不等于任意选主都安全。
18. R1 不可用而 R2 落后,等 R1 与提升 R2 各牺牲什么?
等待可能增加恢复时间/降低可用性;提升 R2 可能扩大数据丢失窗口。需按 RPO/RTO 与确认合同决定。
19. A 发完后必须立刻见到 9,读路径怎样设计?
路由权威节点,或等选定副本回放到该提交可见位置后再读;同时设等待期限和失败策略。
20. `w:"majority"` 能保证 MongoDB 任意 secondary 立刻可读吗?
不能。写关注与副本实际应用、读偏好/读关注是不同条件。
21. MongoDB `wtimeout` 后,能认定先前写入已撤销吗?
不能。写关注超时不撤销已完成的数据修改,结果需按稳定 ID 和权威状态核对。
22. 为什么发送资格不能只从落后副本读取?
退群可能已在 P 生效而副本仍显示活跃;凭旧资格放行会违反发送/退群的业务先后规则。
本章完成标准与下一步
不看答案时,能手算 t=10/40/70 的 P/R1/R2 日志与可读状态,区分本地、远端持久和远端回放确认,说明为何 t=40 提升 R2 可能丢 9;还能写出发送后必见的读路径与复制成本范围,才算完成第一轮。第二轮由学习者在隔离环境保存真实配置、复制位置、故障和读结果;本章没有代替运行。
按学习路线,下一章08.04 一致性模型将把“写后应看见什么、换设备后能否倒退、哪些并发操作可观察”写成明确的一致性模型,再进入第七卷。