4、环境准备篇:数据库选型与高可用架构,MySQL、PostgreSQL、Redis的主从与集群部署避坑
数据库选型这事儿,说白了就是一场「取舍游戏」。我见过太多团队,上来就拍脑袋选MySQL,结果业务量上来后,发现JSON字段查询慢得要命,又急着往PostgreSQL迁移。也见过迷信Redis万能,把核心订单数据往里塞,最后丢数据的惨案。
这一章,咱们就聊聊生产环境里,MySQL、PostgreSQL、Redis到底该怎么选,主从和集群怎么搭才不踩坑。嗯,这里要注意,我讲的都是我在线上环境里「真金白银」换来的教训。
4.1 数据库选型:别只看热度,要看业务场景
选数据库,先问自己三个问题:
- 数据一致性要求有多高? 银行转账和用户点赞,要求完全不同。
- 读写比例是多少? 写多读少,还是读多写少?
- 数据结构会变吗? 固定字段还是灵活Schema?
| 特性 | MySQL | PostgreSQL | Redis |
|---|---|---|---|
| 事务支持 | 强(InnoDB) | 极强(MVCC) | 弱(Lua脚本模拟) |
| 复杂查询 | 一般 | 优秀(CTE、窗口函数) | 不支持 |
| JSON支持 | 有(性能一般) | 极强(索引、函数) | 有(但非核心) |
| 扩展方式 | 主从、分片 | 主从、逻辑复制 | 主从、集群 |
| 典型场景 | OLTP、电商 | OLAP、GIS、金融 | 缓存、会话、计数器 |
4.2 MySQL主从部署:半同步复制是底线
MySQL主从,很多人觉得简单——配个binlog,change master to就完事了。但线上出问题的,往往就是这种「想当然」。
我曾经遇到过,主库宕机后,从库数据落后了10分钟,结果切换上去,用户订单状态全乱了。为什么?因为默认的异步复制,主库提交事务后,根本不等从库确认。
所以,生产环境我强烈建议用半同步复制。
-- 主库配置
INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';
SET GLOBAL rpl_semi_sync_master_enabled = 1;
SET GLOBAL rpl_semi_sync_master_timeout = 1000; -- 1秒超时
-- 从库配置
INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';
SET GLOBAL rpl_semi_sync_slave_enabled = 1;
另外,主从延迟监控一定要做。我习惯用pt-heartbeat,精度到秒级,比SHOW SLAVE STATUS里的Seconds_Behind_Master靠谱多了。
4.3 PostgreSQL主从:流复制与备份策略
PostgreSQL的主从,核心是流复制。配置起来比MySQL稍微复杂一点,但一旦跑稳了,非常省心。
你想想看,PG的流复制是物理级别的,直接传输WAL日志,延迟通常比MySQL的binlog复制要低。
-- 主库 postgresql.conf
wal_level = replica
max_wal_senders = 5
wal_keep_size = 1024 -- 保留1GB WAL
-- 从库 recovery.conf
standby_mode = on
primary_conninfo = 'host=主库IP port=5432 user=repl password=xxx'
trigger_file = '/tmp/pg_failover.trigger'
我在项目中遇到过一个坑:WAL日志堆积。主库写入量大,从库网络抖动,WAL sender跟不上,结果主库磁盘被WAL撑爆。解决方案是设置wal_keep_size上限,同时用pg_receivewal做归档。
避坑指南: 永远不要依赖从库作为唯一备份。我曾经见过从库硬件故障,数据全丢的案例。主库全量备份 + WAL归档,才是正道。
4.4 Redis主从与集群:别让缓存变成「数据黑洞」
Redis部署,最常见的误区就是「主从复制自动故障切换」。默认的Redis主从,主库挂了,从库不会自动上位。你需要哨兵模式或者Redis Cluster。
哨兵模式,说白了就是三个「监工」盯着你的Redis主库。主库挂了,监工们投票选一个新主库出来。
# sentinel.conf
sentinel monitor mymaster 127.0.0.1 6379 2
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 60000
注意: 哨兵节点至少3个,且部署在不同机器上。2个哨兵的话,如果其中一个挂了,就达不到投票多数,无法完成故障切换。
再说Redis Cluster。它解决了单机内存上限的问题,把数据分片到多个节点上。但坑也不少。
- 跨槽位操作不支持: 比如MGET、MSET,如果key不在同一个槽位,会报错。你需要用Hash Tag强制把相关key放到同一个槽位。
- 批量操作性能差: Cluster模式下,pipeline只能针对同一个节点,跨节点需要客户端自己聚合。
- 数据迁移期间有性能抖动: 扩容或缩容时,reshard会占用带宽和CPU。
4.5 高可用架构核心:脑裂与防脑裂
无论你用哪种数据库,高可用架构里最怕的就是脑裂——两个节点都认为自己是主库,同时写入数据,最后数据乱成一锅粥。
为什么会这样?网络抖动导致心跳超时,备库以为主库挂了,自己升为主库。等网络恢复,两个主库同时存在。
防脑裂的常见手段:
- 仲裁节点: 比如Redis哨兵、MongoDB的投票节点,需要多数派同意才能切换。
- STONITH(Shoot The Other Node In The Head): 强制关掉旧主库的电源或网络。这在物理机时代很常见,云上可以用API调用来实现。
- Lease机制: 主库定期续租,租约过期后,备库才能接管。
我曾经在MySQL MHA架构里遇到过脑裂。两个备库同时检测到主库超时,都把自己升为主库,结果业务写入被分散到两个节点,数据对不上了。从那以后,我坚持在MHA里加上master_ip_failover_script,切换时强制关闭旧主库的VIP。
4.6 知识体系总览
下面这张图,是我对数据库选型与高可用架构的总结。你可以把它当作一个「决策地图」。
4.7 部署检查清单
最后,分享一份我每次部署数据库都会过一遍的检查清单。别嫌麻烦,线上出一次故障,省下的时间全得赔回去。
| 检查项 | MySQL | PostgreSQL | Redis |
|---|---|---|---|
| 复制模式 | 半同步 | 同步提交 | 哨兵/Cluster |
| 备份策略 | 全量+binlog | 全量+WAL归档 | RDB+AOF |
| 监控指标 | 主从延迟、QPS | 复制槽、WAL生成量 | 内存、命中率 |
| 故障切换 | MHA/Orchestrator | Patroni/Repmgr | 哨兵自动切换 |
| 防脑裂 | VIP+STONITH | DCS(etcd/consul) | 多数派投票 |