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、金融 缓存、会话、计数器
我的个人习惯: 核心交易用MySQL(生态成熟,运维简单),复杂报表和地理空间数据用PostgreSQL,热点数据加速用Redis。别想着一个库打天下。

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;
注意: 半同步复制不是100%不丢数据。如果主库在等待从库确认时崩溃,且从库还没收到binlog,数据还是会丢。但相比异步复制,风险已经降低了90%。

另外,主从延迟监控一定要做。我习惯用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。
我建议: 如果缓存数据量小于50GB,用哨兵模式就够了。超过50GB,或者需要水平扩展,再考虑Cluster。别为了「技术炫酷」而过度设计。

4.5 高可用架构核心:脑裂与防脑裂

无论你用哪种数据库,高可用架构里最怕的就是脑裂——两个节点都认为自己是主库,同时写入数据,最后数据乱成一锅粥。

为什么会这样?网络抖动导致心跳超时,备库以为主库挂了,自己升为主库。等网络恢复,两个主库同时存在。

防脑裂的常见手段:

  • 仲裁节点: 比如Redis哨兵、MongoDB的投票节点,需要多数派同意才能切换。
  • STONITH(Shoot The Other Node In The Head): 强制关掉旧主库的电源或网络。这在物理机时代很常见,云上可以用API调用来实现。
  • Lease机制: 主库定期续租,租约过期后,备库才能接管。

我曾经在MySQL MHA架构里遇到过脑裂。两个备库同时检测到主库超时,都把自己升为主库,结果业务写入被分散到两个节点,数据对不上了。从那以后,我坚持在MHA里加上master_ip_failover_script,切换时强制关闭旧主库的VIP。

4.6 知识体系总览

下面这张图,是我对数据库选型与高可用架构的总结。你可以把它当作一个「决策地图」。

数据库选型与高可用架构决策地图 业务需求分析 关系型数据库 缓存数据库 MySQL 半同步复制 PostgreSQL 流复制+归档 Redis哨兵 数据量<50GB Redis Cluster 数据量>50GB 高可用核心:防脑裂 仲裁节点 / STONITH / Lease 💡 核心原则 选型看场景,部署看冗余,切换看防脑裂。没有完美的数据库,只有合适的架构。

4.7 部署检查清单

最后,分享一份我每次部署数据库都会过一遍的检查清单。别嫌麻烦,线上出一次故障,省下的时间全得赔回去。

检查项 MySQL PostgreSQL Redis
复制模式 半同步 同步提交 哨兵/Cluster
备份策略 全量+binlog 全量+WAL归档 RDB+AOF
监控指标 主从延迟、QPS 复制槽、WAL生成量 内存、命中率
故障切换 MHA/Orchestrator Patroni/Repmgr 哨兵自动切换
防脑裂 VIP+STONITH DCS(etcd/consul) 多数派投票
最后一句忠告: 数据库部署完成后,一定要做混沌工程测试。拔网线、杀进程、模拟磁盘满,看看你的高可用架构是不是真的能扛住。我见过太多「看起来完美」的架构,一测试就原形毕露。