政策快报平台上线第一天,数据库只有一台RDS,8核16G,存储500G。
政策数据量大约10万条,日请求量1万左右。一台RDS完全够用。
3年后,政策数据量超过1亿条,日请求量500万左右。
数据库从1台变成了:主库1台、从库4台、历史库1台、缓存集群1套。
这3年里,我们做了3次大的数据库重构。今天复盘每次重构的原因和选择。
3次重构
第一次:读写分离(日请求量10万→100万)
触发原因:某个工作日早上,数据库CPU突然飙升到100%,所有查询都超时,系统瘫了半小时。
查日志发现原因:爬虫在批量写入新数据,同时用户在大量读取。写入和读取抢同一个数据库连接池,谁也拿不到足够的连接。
当时的决定:读写分离。主库负责写入,从库负责读取,两个连接池分开,互不影响。
实施后效果:同样的问题再也没出现过。这个阶段持续了大约一年半。
第二次:缓存引入(日请求量100万→300万)
触发原因:读写分离之后,从库的压力也在持续增长。每天新增的政策数据让查询越来越慢,列表页和详情页的响应时间明显上升。
当时的决定:引入Redis缓存。热点数据缓存在Redis里,查询先走缓存,没命中再查数据库。
具体做法:政策详情按ID缓存,24小时失效。列表页缓存5分钟(政策更新频率不高,5分钟可以接受)。
实施后效果:缓存命中率稳定在70%以上,数据库查询量下降了60%以上。这个方案又撑了一段时间。
第三次:分库分表(日请求量300万→500万)
触发原因:主表数据量突破1亿条,即使走了索引,部分查询也开始变慢。特别是按地区、按时间范围筛选的查询,响应时间越来越长。
当时的决定:按年份分表。2023年之前的数据归档到历史表,2024年及之后的数据留在主表。分表之后,主表数据量从1亿降到了3000万左右,查询速度恢复正常。
这个方案解决了当前的问题,但不是长久之计。目前我们正在设计按省份分库的方案,把不同省份的数据分到不同的物理库,进一步分散读写压力。
选型决策的几个原则
回头看这3次重构,有几个决策原则是清晰的:
第一,不到万不得已不做大重构。读写分离撑了一年半,缓存又撑了一年,直到数据量过亿才开始考虑分库分表。早做没必要,晚做来不及。
第二,先用最简单的方案解决问题。按年份分表,这个方案技术含量不高,但它能解决当前80%的问题。做复杂的分库分表方案,可能解决90%的问题,但成本是前者的10倍。
第三,每一步都要考虑可回滚性。每次重构都预留了回滚方案,万一新方案出问题能快速切回去。
结尾
数据库架构没有"一步到位"这回事。数据量变了、请求量变了、业务场景变了,架构就得跟着变。
分库分表不是终点,未来可能还会有新的架构调整,到时候再说。