十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

大考阅卷系统数据库架构平滑演进实践

大考阅卷系统数据库架构平滑演进实践 大考阅卷这类业务平时看起来流量平稳真正考验系统的是那几天固定的“高峰”全市考生同一时段集中提交、阅卷老师集中批改、分数导出与复核并发读写。早年架构往往是一套单体应用加一个核心数据库硬扛等并发真的起来时数据库连接被打满、慢查询堆积、锁等待飙升应用层再扩容也无济于事。本文以大考阅卷业务为背景梳理一套数据库架构从单体走向高可用、高并发支撑的平滑演进思路重点讲清楚演进原则、读写分离、分库分表、缓存异步化和灰度回归适合正在做系统改造的后端开发、DBA 以及架构初阶同学参考看完之后能建立起一套可落地的演进路线。先说清楚一个容易被忽略的事实数据库架构演进最难的不是选型而是如何在业务不停止、数据不丢失、响应不发散的前提下完成迁移。很多团队死磕中间件选型最后却栽在执行顺序上。所以本文会围绕“平滑演进”四个字展开每一步都保留回滚余地和灰度开关。1. 业务背景大考阅卷的并发压力从哪来1.1 阅卷业务的流量特征大考阅卷系统与传统电商业务有明显的流量差异。电商是持续平稳的高并发阅卷则是“脉冲式”并发。平时系统可能只有几千人在线但到规定答题卡上传时间、阅卷任务开放时间、成绩查询时间流量会在半小时内冲到峰值。这种流量模型对数据库的压力尤其集中答题卡图片上传与任务拆分会写入大量小题块数据。阅卷老师批量加载试卷时会有大量试卷明细查询请求。成绩合成、复核、导出时会触发多表关联和聚合查询。班主任、学校管理员同时查看班级成绩报表产生高频只读请求。如果业务层没有做缓冲和分流这些请求会直接落到数据库。而数据库的扩展性不如应用层单纯靠扩容应用节点很难解决问题。1.2 数据库压力模型从数据库视角看压力集中在三个维度维度表现常见原因连接数应用报连接池满、获取连接超时请求并发量超过连接池上限慢 SQL 占用连接时间过长锁等待更新成绩时出现锁等待事务耗时变长高频更新同一批学生成绩行锁竞争严重IO 压力磁盘读写延迟升高查询变慢大量聚合查询扫描数据页缓存命中率下降这里要特别注意的是“慢 SQL 会挤占连接资源”。一条查询如果执行时间从 50ms 涨到 500ms应用层为了等待结果会一直占着连接连接池一旦耗尽新的请求全部排队最终表现为整个服务不可用。所以数据库治理的第一步往往不是分库分表而是先解决慢查询和连接池问题。1.3 技术演进的目标在开始改造之前需要先明确目标。大考阅卷数据库架构的演进目标可以拆成四层支撑高并发读多写少的场景通过读写分离分流写多的场景通过分片分散热点。保证数据一致迁移过程中不丢数据、不多数据切换时有校验机制兜底。保持平滑可控每一次变更都可以灰度、监控、回滚不影响正在进行的阅卷任务。降低运维成本架构复杂度提升的同时监控和运维工具要同步跟上。这四层目标决定了整个演进路径先做应用侧防护再做读写分离然后分库分表最后完善高可用和观测能力。2. 演进前的数据库架构与核心瓶颈2.1 单体数据库架构早期大考阅卷系统通常采用“单体应用 单库单表”的架构。所有试题、答题、阅卷、成绩数据都保存在一个 MySQL 实例中通过业务主键关联。这种架构在数据量小、并发低的阶段完全够用开发简单事务一致性好。但随着考试规模扩大单库会遇到以下问题单表数据量从百万级增长到千万级甚至亿级普通索引失效查询性能下降。数据库连接数受实例配置限制应用扩容后连接数成为新瓶颈。主库承担所有读和写负载过高时主从延迟和稳定性问题都会暴露。某个慢查询或大事务可能拖垮整个库影响所有业务模块。在阅卷场景中最危险的是“大事务”。比如一次成绩合成操作更新几千条记录事务长时间持有行锁后面的阅卷提交全部阻塞最终引起系统雪崩。2.2 瓶颈的定量分析方法演进不能凭感觉。需要先通过监控数据找出真正的瓶颈。推荐从以下指标入手数据库 CPU 使用率、IOPS、磁盘吞吐。慢查询数量 TOP 10 的 SQL 语句。活跃连接数、等待事件。缓冲池命中率。主从复制延迟时间。举个例子如果监控发现大部分慢查询都是成绩查询接口产生的大范围LIKE查询或未走索引的排序查询那么第一步优化应该是调整 SQL 和索引而不是急于分库分表。只有确认单纯索引优化已经无法解决性能瓶颈时才需要考虑架构级改造。2.3 为什么不直接“推倒重来”很多团队在改造时容易走极端直接引入分布式中间件把表拆成几十个分片同步上线缓存集群。这种做法的风险很高新架构与旧业务同时并存数据一致性校验难度大。分片键选择一旦错误后续查询全部需要全分片扫描。一次性切换失败后回滚成本极高。团队对新技术栈不熟悉问题排查效率低。平滑演进的核心思想是“每次只变一个变量”。数据库架构演进应该像手术一样先做局部麻醉确定没有排异反应后再进行下一步。这不是保守而是对线上业务负责。3. 平滑演进的总体原则与架构设计3.1 四条基本原则结合大考阅卷业务的特殊性我们把平滑演进的原则归纳为四条第一可回滚优先。任何一步改造都必须有回滚方案。比如读写分离切换失败要能快速切回单库写入分片迁移校验不一致要能停止双写并保留原始数据。第二灰度发布。先让一个阅卷小组或一个学校进入新链路观察数据库指标和业务指标确认稳定后再放大流量。不要一次性把所有流量切到新架构。第三兼容双写。数据迁移阶段采用双写机制新旧两套存储同时写入通过比对任务校验数据一致性直到数据追平并稳定后再切换读流量。第四读写分离与分片解耦。读写分离解决的是连接数和读压力问题分库分表解决的是数据容量和写热点问题。它们可以独立演进不必绑定在一次变更里。3.2 目标架构的分层演进完成后的数据库架构可以分成四层接入层通过数据库中间件或代理层统一管理路由规则屏蔽底层分片信息。缓存层使用 Redis 缓存热数据降低数据库读压力。存储层业务库按照拆分键进行水平分片每个分片采用主从高可用结构。异步层通过消息队列把非核心写操作异步化削峰填谷。这里要强调目标架构不是越复杂越好。小规模阅卷场景可能只需要读写分离加缓存就能解决问题只有数据容量和写入并发都达到一定规模后才需要分库分表。3.3 分阶段路线图从单体到高可用架构建议按下面五个阶段推进阶段目标关键动作阶段一应用防护与慢查询治理优化 SQL、增加索引、设置连接池和超时阶段二读写分离搭建只读从库改造数据源路由阶段三分库分表确定拆分键部署分片中间件完成历史数据迁移阶段四缓存与异步化热点数据缓存非核心写操作异步化阶段五高可用与容灾主从切换、备份恢复、限流熔断、监控告警每个阶段都有独立的交付物和验证标准也都有回滚方案。下面重点展开几个关键阶段。4. 高并发读写拆分读写分离与连接治理4.1 读写分离的思路在阅卷业务中读请求的占比远高于写请求。比如成绩查询、试卷加载、报表统计都是典型的读操作。如果把读流量全部打到主库主库的连接数和 IO 压力会很高而写入成绩、保存阅卷记录等操作又需要主库保证实时一致性。读写分离的核心思路是主库只处理写请求保证事务一致性和数据权威性。从库承担读请求通过主从复制获取最新数据。应用层通过数据源路由动态选择主库或从库。需要注意的是读写分离会引入主从延迟问题。阅卷场景中成绩保存后立刻查询可能因为从库延迟读不到最新数据。因此延迟敏感的业务比如刚提交的答案校验需要强制走主库而延迟容忍度高的业务如历史成绩统计可以走从库。4.2 基于 Spring 的动态数据源实现假设应用基于 Spring Boot 和 MyBatis可以在抽象数据源层实现读写路由。下面是一个最简单的动态数据源思路。首先定义数据源路由标识// 文件路径com/example/exam/datasource/DataSourceType.java public enum DataSourceType { MASTER, SLAVE }通过 ThreadLocal 保存当前线程的数据源类型// 文件路径com/example/exam/datasource/DataSourceContextHolder.java public class DataSourceContextHolder { private static final ThreadLocalDataSourceType CONTEXT new ThreadLocal(); public static void set(DataSourceType type) { CONTEXT.set(type); } public static DataSourceType get() { return CONTEXT.get(); } public static void clear() { CONTEXT.remove(); } }继承 Spring 的AbstractRoutingDataSource实现动态路由// 文件路径com/example/exam/datasource/RoutingDataSource.java import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; public class RoutingDataSource extends AbstractRoutingDataSource { Override protected Object determineCurrentLookupKey() { return DataSourceContextHolder.get(); } }在 Spring 配置中将多个数据源注册到路由数据源中。这个示例没有绑定框架版本具体依赖需要根据项目实际版本调整# 文件路径src/main/resources/application.yml spring: datasource: dynamic: primary: master datasource: master: url: jdbc:mysql://localhost:3306/exam_master username: exam_rw password: change_me driver-class-name: com.mysql.cj.jdbc.Driver slave: url: jdbc:mysql://localhost:3306/exam_slave username: exam_read password: change_me driver-class-name: com.mysql.cj.jdbc.Driver如果使用 MyBatis可以借助拦截器在 SQL 执行前自动判断读写类型。也可以用一个更轻量的方式在 Service 层方法上增加自定义注解通过 AOP 设置路由标识。4.3 常见误区与一致性处理读写分离落地时最容易踩的坑是“从库延迟导致数据可见性问题”。阅卷系统中阅卷老师提交某一题分数后页面往往要立刻显示最新的平均分。如果该请求走了从库就可能出现分数“回跳”的错觉。解决方案通常有三种强制关键读走主库。把“刚写入立刻读取”的链路标记为MASTER从库只服务非实时查询。业务兜底。如果发现从库数据版本落后可以通过版本号或时间戳触发重新查询主库。延迟容忍。报表类查询允许分钟级延迟通过从库计算降低主库压力。我建议优先采用第一种方案。强制关键读走主库逻辑简单不会引入额外判断大部分读流量仍然可以走从库主库压力已经大幅下降。5. 分库分表从单库到数据分片5.1 拆分键选择当单表数据量过大或者单库写入达到瓶颈时分库分表是绕不开的课题。分库分表的关键是选择拆分键拆分键选错整个架构都会很难受。在大考阅卷场景中比较自然的拆分键有考生 ID适合存储考生答题数据、成绩数据查询维度清晰。阅卷任务 ID适合存储阅卷明细、打分记录但跨考生查询需要聚合。学校 ID适合按学校维度做报表统计但热点学校会产生数据倾斜。选择拆分键时要从业务查询出发。阅卷系统最常见的查询是“某个考生的答案和成绩”“某个任务的得分明细”所以以考生 ID 作为拆分键比较合适。如果还需要按阅卷任务维度汇总可以再维护一份任务与分片的映射表或者建立二级索引表。5.2 基于 ShardingSphere 的分片配置示例这里以 Apache ShardingSphere 的分片思路为例演示配置核心逻辑。实际使用时要根据你选择的中间件版本调整这里主要展示思路。假设成绩表exam_score按照student_id分成 8 张表分布在 2 个库中。分片策略可以配置为# 文件路径sharding.yaml核心片段 rules: - !SHARDING tables: exam_score: actualDataNodes: ds$-{0..1}.exam_score_$-{0..3} databaseStrategy: standard: shardingColumn: student_id shardingAlgorithmName: db_hash tableStrategy: standard: shardingColumn: student_id shardingAlgorithmName: table_hash shardingAlgorithms: db_hash: type: HASH_MOD props: sharding-count: 2 table_hash: type: HASH_MOD props: sharding-count: 4上面的配置中student_id是拆分键数据库按哈希取模分成 2 个库每个库内再分成 4 张表。应用层不需要感知分片细节直接操作逻辑表exam_score即可。5.3 平滑迁移双写、校验与灰度切换分库分表最怕的不是配置复杂而是数据迁移过程中老库和新库数据不一致。这里给出一个通用的平滑迁移流程第一步建立映射关系。在分片中间件中配置逻辑表与实际表的映射确保新旧数据可以同时读写。第二步开启双写。应用写入时同时写入旧表和新分片表。新表的写入失败不影响旧表主流程但要记录失败日志方便后续补偿。第三步历史数据迁移。通过迁移任务把旧表中的历史数据按student_id计算分片批量写入新分片表。可以使用类似下面的思路-- 分批获取需要迁移的数据 SELECT * FROM exam_score WHERE id #{lastId} ORDER BY id LIMIT 5000;然后对每批数据计算目标分片并写入新表。注意先跑全量再跑增量补偿最后做数据校验。第四步比对校验。对同一主键的记录在旧表和新表中查询 MD5 结果确认数据一致。校验可以通过脚本任务执行建议多轮比对# 示例对比某张分片表的记录数和内容摘要 SELECT COUNT(*) FROM exam_score_0; SELECT COUNT(*) FROM exam_score_old WHERE MOD(student_id, 4) 0;第五步灰度切换读流量。先切 10% 的读请求到新分片观察慢查询数量和业务成功率。稳定后切 50%最后全量切换。写流量可以在读流量全量稳定后再逐步切到新库。第六步保留回滚窗口。切换后保留旧表数据至少一个考试周期防止线上问题需要回溯。5.4 分片后的查询与事务问题分库分表会带来两个直接问题跨分片查询和跨库事务。跨分片查询比如按阅卷任务 ID 汇总所有考生的成绩如果任务和考生不在一个分片中就需要中间件做聚合或者应用层并发查询多个分片再合并。这种查询的性能通常低于单库查询所以要尽量按拆分键设计查询条件。跨库事务则不建议用强分布式事务。阅卷打分可以接受最终一致性保存打分记录后发送消息异步更新成绩汇总表通过消息重试保证最终一致。如果必须强一致需要引入分布式事务中间件但代价较高通常在阅卷场景中不划算。6. 引入缓存与异步化降低数据库压力6.1 缓存设计原则读写分离和分库分表解决的是“数据容量”和“读连接”问题但热点数据的高频访问仍然会打到数据库。比如全校师生同时查询一个班级的成绩如果所有请求都穿透到数据库即使有从库也扛不住。缓存设计要围绕“热点”和“读多写少”两个特征。适合缓存的典型数据包括考生基础信息变化频率低。成绩单报表短时间内有大量重复查询。阅卷任务统计信息如总阅卷数、已阅卷数。系统配置项如阅卷规则、评分标准。缓存 key 的设计建议是业务前缀:类型:业务ID比如exam:score:202506:10086。设置合理的过期时间避免永不过期导致数据长期不一致。6.2 缓存穿透、击穿与雪崩的防御缓存穿透查询不存在的 key每次都打到数据库。可以使用布隆过滤器拦截或者将空结果也缓存一段时间。缓存击穿某个热点 key 过期瞬间大量请求同时打到数据库。可以使用互斥锁或者设置热点 key 不过期。缓存雪崩大量 key 同时失效数据库瞬间被压垮。可以在过期时间上增加随机扰动避免同一时刻集体失效。下面是一段带互斥锁的缓存读取伪代码核心思路是控制重建缓存的并发public ListScoreVO getScores(String examId, String classId) { String key exam:score: examId : classId; String cacheValue redisTemplate.opsForValue().get(key); if (cacheValue ! null) { return JSON.parseArray(cacheValue, ScoreVO.class); } // 加锁防止缓存击穿 String lockKey lock: key; boolean locked redisTemplate.opsForValue().setIfAbsent(lockKey, 1, Duration.ofSeconds(5)); if (!locked) { // 短暂自旋后再次查询缓存 Thread.sleep(100); cacheValue redisTemplate.opsForValue().get(key); if (cacheValue ! null) { return JSON.parseArray(cacheValue, ScoreVO.class); } } try { ListScoreVO scores scoreMapper.selectByClassId(examId, classId); redisTemplate.opsForValue().set(key, JSON.toJSONString(scores), Duration.ofSeconds(300)); return scores; } finally { redisTemplate.delete(lockKey); } }这段伪代码演示了“读取缓存 → 未命中加锁 → 查询数据库 → 回填缓存”的流程。实际项目中还要考虑锁的自动续期、异常兜底和监控日志。6.3 异步化削峰阅卷场景中有很多非实时写操作比如阅卷日志、操作审计、成绩消息通知。这些操作对实时性要求不高但峰值时频率很高可以直接通过消息队列异步化。典型流程是应用层发送消息到 MQ。异步消费者批量消费写入数据库。通过重试和死信队列处理失败消息。这样做的好处是写入峰值被 MQ 缓冲数据库不再直接承受瞬时写并发同时批量写入能显著减少事务次数降低数据库压力。7. 高可用与容灾数据库侧保障7.1 主从高可用读写分离之后主库和从库本身也需要高可用保障。常见方案是搭建主从复制架构并引入故障自动切换能力。当主库发生故障时从库提升为新主库应用通过新的连接地址继续读写。这里的关键点是切换不能只是数据库层的事情应用层要具备快速切换数据源的能力。如果中间件或配置中心支持动态数据源可以在主库故障后更新配置并通知应用重连。阅卷业务中有明确的高峰期所以在大考期间建议执行一次主从切换演练确认切换时间、数据补偿逻辑和业务影响范围。不要等到线上故障时才第一次尝试切换。7.2 备份与恢复数据库架构越复杂备份策略越要提前设计。分库分表后的备份不再是简单的单库mysqldump就能覆盖的必须按分片分别备份并且保证跨分片的数据一致时间点。在实际操作中建议开启 MySQL binlog用于增量备份和数据恢复。每天执行全量备份保留至少 7 份。大考阅卷关键周期内增加备份频率。定期做恢复演练确认备份可以真正恢复出可用数据。这里必须强调备份的目的不是“有备份”而是“能恢复”。建议每季度做一次恢复演练把备份文件恢复到测试环境核对数据量和关键业务数据。7.3 限流与熔断当数据库确实扛不住流量时架构上要有兜底手段。应用层应为核心数据库操作设置超时时间比如连接超时 500ms读超时 1s。超过阈值的请求快速失败而不是继续堆积占用连接。同时可以引入熔断机制当数据库错误率或响应时间超过阈值时熔断器打开后续请求直接走降级逻辑。阅卷场景的降级策略可以包括成绩查询降级为从库只读模式不保证最新数据。报表统计降级为缓存数据返回延迟数据并提示稍后刷新。非核心能力关闭比如日志上报暂时丢弃优先保证打分提交链路。限流和熔断不是为了一直打开而是在极端流量下保护数据库不被打挂保证主干业务可用。8. 灰度发布、监控与回滚机制8.1 灰度发布策略数据库架构演进必须配合灰度发布。灰度不是简单的 A/B 测试而是分阶段、可观测、可回滚的流量切换。常见的灰度维度包括按用户维度选择少量考生或阅卷老师的请求走新链路。按业务模块维度只对成绩查询模块进行读写分离打分提交模块保持原链路。按流量比例维度把 10% 的读流量切到新架构逐步提升到 100%。灰度期间要同时关注技术指标和业务指标。技术指标包括数据库 CPU、连接数、慢查询数、主从延迟业务指标包括接口成功率、响应时间、用户投诉率。只要有一项异常立即停止灰度并回滚。8.2 核心监控指标为了支撑灰度决策需要建立一套清晰的数据库监控面板。推荐至少包含以下指标类别指标作用资源CPU、内存、磁盘 IO、网络吞吐判断数据库资源是否饱和会话活跃连接数、等待数、死锁数判断连接池和锁竞争状态性能慢查询数、平均查询耗时、事务耗时判断 SQL 和事务效率复制主从延迟时间、复制错误判断读写分离一致性风险应用接口成功率、超时数、熔断次数判断架构改造对业务的影响监控告警要分级。对于大考阅卷业务来说主从延迟超过 5 秒、活跃连接数超过阈值、慢查询数量突增都应该触发即时告警。告警消息要包含问题范围、影响面和初步排查指引而不是只给一个“数据库异常”的标题。8.3 应急预案与回滚路径每次数据库架构变更前要提前写好应急预案。应急预案至少包含以下内容变更的详细步骤和时间窗口。每一步的风险点和责任人。异常的判定标准和升级路径。回滚到上一版本的具体操作步骤。回滚后的数据校验和补偿方案。以读写分离为例如果切换从库后出现严重主从延迟导致用户查询成绩异常回滚方案就是修改数据源配置把读流量全部切回主库同时保留从库只读。操作本身应该在几分钟内完成且不能影响正在进行的写入。回滚操作结束后不要马上再次灰度。要先分析问题原因确认修复后再重新走小流量验证流程。9. 常见问题与排查清单数据库架构演进过程中很多问题其实有共同规律。这里整理一份高频问题排查表方便你在现场快速定位。问题现象常见原因解决思路应用启动报“连接池获取连接超时”数据库活跃连接数被打满先查慢 SQL再扩大连接池上限并增加应用层超时从库查询结果和主库不一致主从复制延迟判断业务是否能容忍延迟敏感查询强制走主库分片表查询变慢查询条件没有包含拆分键根据拆分键重建查询或增加分片映射表迁移后数据条数不一致增量数据未全部补偿重新跑增量补偿任务再执行 MD5 比对缓存命中率低key 设计不合理或过期时间太短调整缓存粒度统计热点 key合理设置过期时间压测时数据库 CPU 先被打满索引缺失或 SQL 扫描行数过大用 EXPLAIN 分析慢查询补充联合索引大事务导致锁等待严重一次更新数据量过大拆分事务分批提交减少锁持有时间灰度切换后接口错误率飙升新链路未正确配置数据源或权限检查中间件配置、账号权限和网络连通性如果你遇到类似问题建议按“先定位范围、再分析日志、后验证假设”的顺序排查。不要急着改配置先确认是连接问题、SQL 问题还是数据一致性问题再动手。10. 最佳实践与工程建议10.1 数据库账号与权限最小化无论架构怎么演进数据库账号都应该遵循最小权限原则主库写入账号只具备 INSERT、UPDATE、DELETE、SELECT 权限。从库读账号只具备 SELECT 权限。迁移账号单独创建迁移完成立即回收。禁止在应用配置中明文保存数据库密码通过配置中心托管。在生产环境中尽量做到“应用账号不可删除数据”。结构化数据删除操作应通过专门的运维流程执行而不是让应用代码直接执行DROP或TRUNCATE。10.2 重要操作前必须备份任何涉及数据变更的操作比如历史数据迁移、批量更新成绩、删除重复数据操作前都要完成备份。备份不只是导出文件还要确认备份文件可用、恢复流程可行。建议所有批量更新先写查询条件再执行SELECT COUNT(*)确认影响行数最后在事务中执行更新。比如-- 更新前先确认影响范围 SELECT COUNT(*) FROM exam_score WHERE exam_id 202506 AND score IS NULL; -- 开启事务执行更新 BEGIN; UPDATE exam_score SET score 0 WHERE exam_id 202506 AND score IS NULL; COMMIT;10.3 配置变更走配置中心数据库连接串、分片规则、开关配置不要写在应用代码里。建议统一放到配置中心管理这样灰度切换时不需要重新发布应用也方便紧急回滚。配置变更要记录日志保留版本历史方便回溯。10.4 测试环境尽量模拟生产分库分表和读写分离的验证不能只靠生产环境的小流量。测试环境应尽量模拟生产的分片规则、数据量级和并发模型。尤其是分片中间件要提前跑一遍全链路压测确认 SQL 路由结果符合预期避免上线后才发现某个查询路由到了错误的分片。10.5 大考窗口期的变更纪律对于阅卷业务而言大考期间是绝对不能做高风险变更的。建议明确变更窗口规则大考阅卷前一周冻结数据库架构变更。核心变更必须提前在测试环境和预发环境验证通过。上线窗口预留足够时间避免压到业务高峰。变更完成后安排至少 24 小时监控观察期。这些看起来是流程上的约束实际上是对系统和团队的双重保护。很多线上事故都发生在“顺手改一下”的场景里流程纪律能挡住大部分风险。10.6 保留演进演进空间数据库架构演进不是一劳永逸的。分片数量、缓存策略、连接池参数都需要根据业务增长持续调整。建议在架构设计之初就预留水平扩展能力比如分片键要支持后续扩分片配置项要支持动态调整监控数据要能够回放历史趋势。同时不要过早引入复杂组件。如果当前数据量只有几百万强行分库分表只会增加查询复杂度和运维成本。架构演进要匹配业务阶段先解决眼前最痛的问题再考虑下一阶段的布局。回到大考阅卷这个场景数据库架构的每一步演进本质上都是在“业务可用性”“数据一致性”和“团队运维成本”之间寻找平衡。读写分离能解决读压力分库分表能解决容量压力缓存和异步化能解决流量峰值压力但它们都不是银弹。真正让架构稳定运行的关键是一套可灰度、可监控、可回滚、有备份的工程体系。希望这篇文章能帮你在规划数据库架构演进时少走一些弯路。如果你正在做类似的改造可以先把业务流量特征和监控指标梳理清楚再决定从哪一步开始。
返回列表