读己之写是什么
读己之写(Read Your Writes)是一种会话级一致性保证:用户提交写入之后,自己发起的后续读取一定能看到这次写入的结果。它出现在读写分离与多副本架构里——写请求走主库、读请求走从库,当复制存在延迟时,刚提交的数据可能查不到。问题的表现非常具体:用户点完保存立刻刷新页面,看到的是旧内容,于是反复提交,反而制造更多脏数据。
基本信息
| 一致性层级 | 会话级保证,不是全局强一致 |
|---|---|
| 触发场景 | 写主库、读从库,或读请求被路由到不同副本 |
| 实现手段 | 会话粘性、写后读主、客户端携带版本号或时间戳 |
| 需要配套 | 复制延迟监控,延迟升高时自动放宽策略 |
| 产品侧缓解 | 提交成功后展示本地已确认数据,不立即回查服务端 |
典型使用场景
- 保存后跳转详情页:编辑完成立刻打开,必须看到刚提交的内容
- 下单后查看订单列表:新订单不能从列表里消失,否则用户重复下单
- 配置变更生效:管理端改完配置立即验证,读到的应是新值
- 多步骤表单:前一步的写入是后一步读取的前提,链路内不能读旧值
- 审核后查看状态:审核动作完成,自己看到的应已是新状态
- 跨端提醒:同账号在另一设备提交后,本机刷新需保持一致口径
写后读主示意(伪代码)
写后读主示意(伪代码)
# 写入成功后给会话打一个短期标记
on_write_success: session[user_id].read_master_until = now + 5s
# 读取时按标记决定路由
if now < session[user_id].read_master_until:
route = MASTER # 短期强制读主库
else:
route = REPLICA # 常规读从库,并校验版本
if replica.version < session[user_id].last_write_version:
route = MASTER # 版本落后时回退主库
# 版本号由写入返回,客户端在会话中携带实现手段对比
| 手段 | 做法 | 代价 |
|---|---|---|
| 会话粘性 | 同一会话固定走同一副本 | 副本故障时该会话体验中断,负载不均 |
| 写后读主 | 写入后一段时间内该会话读主库 | 主库压力上升,窗口长度需要按延迟标定 |
| 版本号校验 | 写返回版本,读时比对副本版本 | 需要副本暴露位点信息,实现成本高 |
| 客户端兜底 | 写成功后前端暂存结果并据此渲染 | 仅缓解观感,服务端数据仍可能不一致 |
策略窗口要与复制延迟监控联动:固定写死 5 秒在延迟升高时照样读到旧数据,延迟 30 秒时也只是把问题推后。
跨用户可见的数据(例如同事刚改的配置)不属于读己之写范畴,需要单独设计一致性策略,不要用同一个短窗口假设覆盖所有场景。