数据存储与一致性考量
一、关系型与 NoSQL 的选型
关系型数据库(如 MySQL、PostgreSQL):结构化表、SQL、ACID 事务、外键与约束。适合强一致、多表关联、复杂查询、报表。单机或主从扩展,垂直扩展为主。
NoSQL 是一类非关系型存储的统称,常见几类:键值(Redis、DynamoDB)——简单 get/set、缓存与会话;文档(MongoDB、Couchbase)——JSON 文档、灵活 schema、适合读多写少与嵌套结构;列式(HBase、Cassandra)——按列存储、适合分析与大宽表;图(Neo4j)——节点与边、适合关系与路径查询。选型看访问模式、一致性要求、扩展方式与团队能力;不少系统是「关系型主库 + NoSQL 缓存/检索」的混合架构。
二、事务与一致性:ACID、CAP、最终一致性
ACID:Atomicity 原子性(要么全成功要么全回滚)、Consistency 一致性(业务约束在事务前后成立)、Isolation 隔离性(并发事务互不干扰)、Durability 持久性(提交后落盘不丢)。关系型单机事务通常提供 ACID;跨库或跨服务则难以用「一个事务」兜住,需要 saga、补偿、最终一致等模式。
CAP:在分布式系统中,Consistency(所有节点看到同一份最新数据)、Availability(每个请求都能得到响应)、Partition tolerance(网络分区时系统仍能工作)三者不能同时满足。实践中 P 常必须接受(网络会分区),于是多在 CP(强一致、允许不可用)与 AP(高可用、接受最终一致)之间取舍。例如 CP 型:强一致数据库主节点;AP 型:多副本最终一致、冲突用版本或业务规则解决。
最终一致性:不要求每次读都拿到「刚写完」的结果,允许短暂不一致,通过异步复制与重试在一段时间后达到一致。适合读多写少、可接受延迟一致的场景;要配合幂等、补偿与对账,避免脏读导致业务错误。
ACID 简记
- Atomicity:事务内全部成功或全部回滚
- Consistency:事务前后业务约束成立
- Isolation:并发事务互不干扰
- Durability:提交后持久化不丢
CAP 与选型
分区容错(P)通常无法放弃,因此实际在 CP(强一致、可能不可用)与 AP(高可用、最终一致)间选。强一致主库选 CP;多活、缓存、最终一致存储选 AP,用幂等与补偿保证业务正确。
三、读写分离、分库分表入门
读写分离:主库负责写,从库(副本)负责读,通过主从复制同步。写少读多时能显著减轻主库压力、提高读吞吐。注意从库有复制延迟,读到的可能是稍旧数据,适合可接受短暂滞后的场景;强一致读仍要走主库或带主库位点的读。
分库分表:当单库单表成为瓶颈时,按规则把数据拆到多个库/表。分表:同一库内多表(如按用户 ID 取模);分库:多库,每库可再分表。拆分维度常见有按范围、按 hash/取模;要避免热点、考虑跨库 join 与事务(尽量同库完成或用应用层拼装)。分库分表后,路由、扩容与迁移都会变复杂,需提前设计好键与路由策略。
四、数据迁移与版本管理
Schema 变更:加列、加索引、改类型等要有可回滚方案。加列尽量先可空或带默认值,再 backfill;删列先废弃、再停用、最后删。大表加索引可在线进行(不同数据库支持不同)或低峰执行,避免锁表过久。
数据迁移:大批量数据迁移(换库、拆库、归档)常用双写 + 同步 + 校验 + 切流:先双写新旧两处,再同步历史、对账一致,最后读切到新处、停旧写。迁移脚本要可重试、幂等,并有回滚预案。版本管理:用迁移工具(如 Flyway、Liquibase、Alembic)把 schema 变更写成版本化的脚本,在部署时按顺序执行,便于追溯与回滚。
迁移与版本要点
- Schema 变更:加列可空/默认、删列先废弃再删;大表索引注意锁与时长
- 数据迁移:双写 → 同步历史 → 对账 → 切读/停旧写;脚本幂等、可回滚
- 版本化迁移脚本(Flyway/Liquibase 等),部署时按序执行,可追溯
一句话: 关系型强一致与复杂查询,NoSQL按访问模式选键值/文档/列/图,常与关系型混合。ACID 单机强一致,CAP 下多选 CP 或 AP,最终一致性配幂等与补偿。读写分离扩读,分库分表扩写与容量;迁移与版本要可回滚、可追溯。
五、小结
存储选型:关系型与 NoSQL(键值/文档/列/图)按场景与访问模式选,可混合。一致性:ACID 单机、CAP 取舍、最终一致与补偿。扩展:读写分离扩读、分库分表扩写与容量,注意延迟与路由。迁移与版本:Schema 变更可回滚、数据迁移双写对账切流、版本化脚本可追溯。下一章讲可扩展性、高可用与性能设计,把扩展方式、高可用手段与性能设计思路串起来。