大促期间商品评价接口必须做读写分离,用只读副本扛住查询流量,让主库专心处理写入,否则评价列表一旦被秒杀级流量打穿,整个交易链路都会跟着雪崩。
商品评价接口看起来简单,无非是查评价、写评价、统计评分,可大促场景下,它的压力曲线和平时完全不同:用户疯狂刷新评价列表、下单后集中提交评价、运营后台批量推送优质评价,三种流量叠加,一个普通单库单表架构根本撑不住,很多团队把精力放在商品详情页和库存上,结果评价接口成了压垮系统的最后一根稻草,今天咱们就聊聊大促评价接口的读写分离实战,不扯虚的,全是能落地的方案。
大促评价接口为什么普遍扛不住读流量
评价接口的读流量和写流量比例在大促期间能拉到几十比一,用户进入商品详情页,第一件事就是往下滑看评价,评价列表接口被高频触发,用户还会按图筛选、按标签筛选、按时间排序,每一种操作都对应一次查询,更麻烦的是,评价数据往往会带上用户头像、昵称、追评图片等关联信息,一次查询要join多张表,数据库压力成倍上涨。
读放大的三个典型场景
- 列表页翻页:用户连续滑动加载更多,每滑一次触发一次分页查询,深度翻页时
offset越来越大,数据库需要扫描并丢弃大量行。 - 聚合统计:商品评分、好评率、各星级占比,这些数据每次页面加载都要实时计算,大促前如果没做预聚合,查询代价很高。
- 多维筛选:按“有图”“追评”“当前商品”等条件组合筛选,索引设计不合理时直接全表扫描。
行业共识认为,评价接口的读流量在大促期间会呈脉冲式增长,峰值可能是平日的几十倍,而写流量只会涨几倍,所以读写分离的核心思路,就是让读流量走只读副本,把主库从繁重的查询中解放出来。
商品评价接口读写分离架构怎么落地
这里说的读写分离,不是简单搞一个主从复制就完事,评价业务有它的特殊性:写入后必须在很短时间内能被读到自己刚提交的内容,否则用户感觉“评价没发出去”,所以架构设计必须围绕“读已提交”和“最终一致”之间的平衡来做。
基础分层:主库写,从库读
- 主库只处理评价提交、审核状态变更、删除操作。
- 从库挂多个只读节点,所有列表查询、详情查询、聚合统计都走从库。
- 中间加一层透明路由,根据SQL类型自动区分读写操作,推荐使用ShardingSphere或者MyCat,也可以自己在DAO层用
注解做动态数据源切换。
@ReadOnly
具体操作路径:在Spring中配置两个数据源,主库master和从库slave,用AbstractRoutingDataSource实现动态切换,写操作强制走master,读操作默认走slave,需要注意事务内必须保持同一数据源,否则刚写入的数据在事务里读不到。
同步延迟:评价接口读写分离最大的坑
主从复制默认是异步的,大促期间主库写入压力一大,从库同步延迟可能从毫秒级飙到秒级,用户提交评价后立刻刷新,评价消失,投诉就来了,解决思路有三层:
- 路由兜底:根据用户ID做哈希,同一用户的写后读请求强制路由到主库,比如用户提交评价后的5秒内,该用户的读取都走主库,实现上可以用ThreadLocal记录最近写入时间,配合一个简单的
UserReadRouter。 - 缓存补偿:把刚写入的评价直接塞进Redis缓存,key设计为
eval:new:{userId},设置5分钟过期,读取时先查这个短时缓存,命中就直接返回,不查从库。 - 半同步复制:如果团队对数据一致性要求高,可以开启半同步复制,确保至少一个从库收到binlog后才提交主库事务,代价是写入RT略有提升,大促期间建议关闭,改用前两种方案更划算。
评价聚合统计的读写分离特殊处理
评价接口里最容易被忽视的是评分聚合,每次商品详情页打开都要显示“4.8分 2000+评价”,如果实时count和avg,从库也扛不住,正确做法是:
- 后台任务定期从主库导出增量评价数据,计算聚合结果写入Redis或单独统计表。
- 读接口直接查缓存,缓存过期时间为1到5分钟,大促期间接受轻微延迟,换的是接口RT从50ms降到5ms。
- 如果用户对“评价后评分立刻变化”有强需求,可以在写主库时同步更新一个内存态评分,然后异步广播到所有从节点的本地缓存。
大促评价接口读写分离的高可用和降级策略
光有读写分离还不够,大促流量峰值来时,从库照样可能被打满,评价接口必须设计多层降级,每一层都保证核心体验不崩。
从库过载时如何优雅降级
- 第一层降级:关闭非核心筛选条件,有图筛选”“追评筛选”直接不生效,只返回基础评价列表。
- 第二层降级:评价列表返回缓存数据,用Redis缓存每个商品的前10页评价ID列表,再按ID批量查评价详情,缓存可以提前在大促前预热。
- 第三层降级:合并请求,同一商品的评价查询,在网关层做一个短时间窗口合并,500ms内的请求只发一条SQL到从库,结果广播给所有等待请求。

写抖动怎么隔离
大促期间用户集中提交评价,主库写入也可能积压,建议把评价写入拆成两步:先写消息队列,后台消费者批量落库,用户看到的是“提交成功”,实际数据在几百毫秒内写入主库,这样可以削峰填谷,还能避免数据库连接被写操作占满而导致读操作拿不到连接。
对比:读写分离与其他评价接口优化方案
| 方案 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| 主从读写分离 | 读流量远大于写流量,能容忍秒级延迟 | 实现相对简单,成本低 | 延迟难根治,从库扩容需要运维支持 |
| 缓存+异步队列 | 评价写入量大,查询要求高 | 抗峰值能力强,用户体验好 | 需要处理数据一致性,架构复杂度高 |
| 分库分表 | 单库数据量超过千万级 | 解决数据存储瓶颈 | 读写分离和分库分表叠加后运维成本大增 |
| 纯缓存查询 | 评价实时性要求不高,比如只看热门评价 | RT极低 | 无法支持多维筛选,数据可能过期 |
从实践经验来看,大促评价接口最稳妥的组合是“主从读写分离+Redis缓存聚合统计+写操作异步化”,如果团队预算有限,至少要做读写分离和缓存预热,这两项就能扛住绝大多数峰值流量。
部署读写分离时常见的三个细节坑
事务内读写不一致
很多同学在@Transactional方法里执行了写操作,随后又在该事务内调用了读接口,由于读接口走了从库,主库刚写入的数据还没同步过来,事务内自读会出现空结果,解决办法:在事务注解上强制使用主库,或者把读写操作拆到不同方法,避免事务跨越数据源。
从库负载均衡策略
多个从库时,轮询和随机都可能让热点商品打爆其中一台,建议采用基于商品ID的哈希路由,同一个商品的读请求固定到同一台从库,这样可以充分利用本地缓存,同时减少数据同步压力。
监控和告警的指标
大促前必须盯住几个指标:从库的Seconds_Behind_Master

(同步延迟)、主库的Threads_running、从库的QPS和CPU,建议设置阈值告警:同步延迟超过3秒就自动把部分读流量切到主库,主库CPU超过80%就触发降级。
评价接口读写分离方案怎么估算成本
大促前评估读写分离的硬件成本,不能只看QPS,得看数据量级,假设单商品评价平均2KB,一个爆款商品有10万条评价,一次列表查询返回20条,加上分页扫描,读一次大概要消耗数据库1MB的IO能力,一台8核16G的从库(按市场价大概每月几百块,地域不同价格有差异比如北京和上海机房会比西部城市贵一些)能支撑几千QPS的简单查询,如果用云数据库的只读实例,费用通常是主库的50%到70%,这是比较划算的投入。
预算有限的团队可以不用加机器,直接把评价列表改成Redis存储,评价本体可以精简字段(只存用户ID、内容、时间戳、评分),图片信息走CDN,这样读写分离从数据库层面上升到缓存层面,成本更低,但要注意缓存淘汰策略。
大促结束后读写分离架构要回滚吗
不需要,读写分离架构不是临时补丁,平时也能降低主库压力,大促结束后要做的是整理同步延迟数据和QPS峰值,调整从库节点数量,比如平时两个从库够用,大促时可以临时扩容到五个,活动结束后释放三个,云厂商的只读实例按小时计费,用完就删,不浪费。
关于商品评价接口在大促的读写分离,常问的几个问题
评价接口读写分离后,用户刚发的评价自己看不到怎么办
采用写后读路由,用户提交成功后的5秒内,该用户的所有评价读取直接走主库,实现方式是在拦截器里判断当前用户是否有最近写入记录,有则动态设置数据源为master,如果5秒后主从同步还没完成(一般不会发生),从库也能读到,因为同步延迟通常远小于5秒。
读写分离能不能解决大促评价接口的全部性能问题
不能,读写分离解决的是数据库层面的读压力,但评价接口还涉及网络带宽、序列化、逻辑处理等环节,如果接口RT还是高,需要进一步做静态化、CDN缓存、甚至边缘计算,读写分离是基础,不是万能药。
评价接口的读写分离和分库分表应该先做哪个
评价数据量在千万以内时,先做读写分离即可,数据量超过两千万或者单表查询已经出现明显性能下降时,再考虑分库分表,分库分表应该基于评价的归属维度(比如商品ID或店铺ID)拆分,拆分后读写分离依然保留,两者不冲突,只是运维复杂度会上升。