读写分离的坑:读到旧数据的场景
发布时间:2025-10-30 10:46       
更新时间:2025-10-31 05:11
刚改完昵称,刷新一下又变回旧值——读写分离环境里这种"改了像没改"的反馈,多数是读到了从库的旧数据。这不是随机 Bug,是主从复制的异步特性撞上了"写后立读"。
为什么会读到旧数据
写入落在主库,提交后由复制线程异步同步到从库,中间有延迟:正常毫秒级,主库高峰、大事务、从库机器配置差时会拉长到秒级甚至更久。写完立刻读,读请求被路由到还没同步完的从库,看到的就是旧值。延迟多大可以在从库执行 show slave status 看 Seconds_Behind_Master,平时记个基准值,异常时才有对照。
哪些读必须走主库
判断标准一条:这次读的结果会不会立刻影响用户的下一步操作。改完资料马上回显、下单后查订单状态、支付后查余额,这类写后立读必须走主库。浏览列表、搜索、推荐位这类读,晚一两秒没人在意,安心留在从库。
会话粘滞怎么做
常用方案是"会话粘滞":用户发生写入后给他打个短时标记(存会话或 Redis,比如 3 秒),标记有效期内该用户的读全部走主库,过期后恢复分流。封装在数据源路由层大致是:
if (recentlyWrite(userId)) { routeToMaster(); } else { routeToSlave(); }
粒度可以更细:只对"刚写过的那张表"的读走主库,粘滞时间更短,主库压力也更小。标记的时机也有讲究:要在写请求提交时就打上,因为读请求可能紧随其后已经在路上,宁可多粘滞一会儿。
业务容忍度设计
有些场景反过来设计更顺:提交后先进入"处理中"状态页,几秒后再展示结果,把不可避免的延迟藏进流程里,技术上就不用强制走主库。读写分离的正确姿势不是消灭延迟,而是让业务流程和路由规则都承认延迟存在——该走主库的走主库,能等从库的等从库。