MySQL不支持连接层自动故障转移,需客户端或中间件实现;PostgreSQL 14+的libpq才支持host多地址自动切换,需配合connect_timeout等参数。
MySQL 连接失败时如何触发备用服务器切换
直接上结论:mysql 本身不支持连接层的自动故障转移,必须靠客户端或中间件实现。原生 mysql 命令、mysql.connector 或 pymysql 等驱动默认只连一个地址,连不上就报 connectionrefusederror 或 timeouterror,不会自己换地址重试。
常见错误现象是应用启动时卡住几秒后抛出 OperationalError: (2003, "Can't connect to MySQL server"),而不是静默切到备用库。
- 真正起作用的是客户端逻辑:比如在连接前手动轮询多个 host:port,逐个尝试,直到成功或耗尽列表
- 使用
mysql-connector-python时,可传入host为列表(但注意:仅限 8.0.23+,且需配合failover=True参数) - 老版本或
pymysql没有内置 failover 支持,必须自己写重试循环 + 异常捕获 - 不要依赖 DNS 轮询(如把多个 IP 绑定到同一个域名),MySQL 客户端通常只用第一个解析结果,且不刷新缓存
PostgreSQL 的 host 参数是否支持多地址自动切换
支持,但有严格限制:PostgreSQL 14+ 的 libpq(即 psycopg2 底层)才真正支持 host 传入逗号分隔的多个地址,并按顺序尝试连接,遇到超时或拒绝就自动跳下一个。
使用场景很明确——你用 psycopg2.connect() 或 pgbouncer 配置时想省掉客户端逻辑。
- 正确写法:
host='10.0.1.10,10.0.1.11,10.0.1.12',配合hostaddr可选(避免 DNS 延迟) - 参数
connect_timeout必须设小一点(比如5),否则单个失败节点会拖慢整体连接时间 - 旧版 PostgreSQL(psycopg2 会把逗号当非法字符,报错
invalid connection option "host" - 这个机制只管“连得上”,不管主从角色——如果备库只读,而你的 SQL 写了
INSERT,照样执行失败,不会二次跳转
Redis 连接池里怎么配置哨兵(Sentinel)实现自动故障转移
Redis 哨兵不是客户端自动发现机制,而是需要显式启用 Sentinel 支持。直接连 redis://localhost:6379 永远不会感知主节点变化。
核心是用 redis.sentinel.Sentinel 替代 redis.Redis,并确保哨兵进程已在运行且能互相通信。
- 初始化时传入哨兵地址列表:
Sentinel([('10.0.2.5', 26379), ('10.0.2.6', 26379)]) - 获取主节点连接必须调用
sentinel.master_for('mymaster'),其中mymaster是哨兵配置里的sentinel monitor名称 - 客户端不会实时监听哨兵事件,只有在每次获取连接时才会向哨兵查一次当前主节点;所以主从切换后首次请求可能短暂失败(取决于哨兵 failover 时间)
- 别漏掉
socket_connect_timeout和socket_timeout,否则哨兵响应慢会导致整个 Redis 操作阻塞
Nginx upstream 怎么做数据库连接层的故障转移
不能。Nginx 的 upstream 只能转发 TCP/HTTP 流量,对 MySQL/PostgreSQL 协议没有状态理解能力,无法识别认证、查询、事务等语义。强行代理会导致连接建立失败或查询乱序。
有人试过用 stream 模块做四层转发,但问题更隐蔽:
- MySQL 握手包含协议版本、服务端 salt,Nginx 不解析直接转发,某些客户端(如新版
mysql-shell)会校验失败 - PostgreSQL 的 startup message 里有
database和user字段,Nginx 不改写,导致所有请求都打到同一个后端 - 真正可行的是用专有代理:如
pgbouncer(PostgreSQL)、mysql-router(MySQL)、redis-sentinel自带的 client 端逻辑 - 如果非要用 Nginx,只能代理 HTTP 封装层(比如把数据库操作封装成 REST API),此时故障转移才可控
最易被忽略的一点:所有客户端侧的 failover 都假设备用服务器数据已同步完成。主从延迟超过几秒时,切过去立刻读到旧数据,业务可能出错——这不是配置问题,是架构前提没满足。











