thinkphp 6 实现 dns 轮询需将数据库 host 配置为轮询域名(如 db.example.com),禁用 php dns 缓存,并在连接工厂中调用 dns_get_record() 动态获取 ip;其本质是系统层解析,非框架负载均衡。

ThinkPHP 6 如何配置多个数据库连接实现 DNS 轮询?
DNS 轮询本身不是数据库层的负载均衡方案,它只是让同一个域名解析到多个 IP(比如 db.example.com 解析出 10.0.1.10、10.0.1.11、10.0.1.12),由操作系统或 PHP 的 DNS 缓存决定最终连哪个。ThinkPHP 并不感知 DNS 轮询,它只认你给的 host 字符串。所以真正起作用的是:把数据库 host 配置成一个 DNS 轮询域名,并确保 PHP 不做 DNS 结果缓存(或缓存时间极短)。
实操建议如下:
- 在
config/database.php中,将'hostname' => 'db.example.com',不要写死 IP - 确认服务器 DNS 解析行为:用
dig db.example.com多次执行,观察返回的 A 记录顺序是否轮换 - PHP 默认会缓存 DNS 结果(受
opcache.enable和realpath_cache_size影响),可在启动时加php -d opcache.enable=0 -d realpath_cache_size=0测试;生产环境更推荐用dns_get_record()手动刷新 + 连接池兜底 - ThinkPHP 自身无 DNS 刷新机制,若需强轮询,应配合自定义连接工厂,在每次获取连接前调用
dns_get_record($host, DNS_A)随机选一个 IP
为什么直接配多个 connection 并用 loadBalance 不等于 DNS 轮询?
ThinkPHP 6 的 load_balance 配置(如 'load_balance' => ['type' => 'random'])是在多个已声明的 connection 之间做分发,每个 connection 是独立 host+port 组合。它和 DNS 轮询完全无关——前者是应用层路由,后者是网络层解析。
常见误解是以为这样就能“模拟 DNS 轮询”:
'db1' => ['hostname' => '10.0.1.10'], 'db2' => ['hostname' => '10.0.1.11'], 'db3' => ['hostname' => '10.0.1.12'], 'load_balance' => ['type' => 'random']
这其实只是随机挑一个连接,且无法应对单点故障自动剔除(除非自己实现健康检查)。而 DNS 轮询下,如果某台 DB 宕机,只要 DNS 不再返回它的 IP,新连接自然绕过——但已有长连接、PHP DNS 缓存、MySQL 连接池仍可能持续打到坏节点。
如何避免 DNS 缓存导致轮询失效?
PHP 的 mysqli 和 PDO 在建立连接时调用系统 getaddrinfo,结果会被 glibc 或 musl 缓存。即使你改了 DNS 记录,PHP 进程可能数小时都连着旧 IP。
关键控制点:
- Linux 上检查
/etc/nsswitch.conf是否含hosts: dns [!UNAVAIL=return] files,避免仅查 hosts 文件 - 设置
options ndots:1和timeout:1在/etc/resolv.conf可缩短单次查询耗时,但不解决缓存 - 最有效方式:在 ThinkPHP 的数据库连接工厂中,每次创建连接前强制刷新 DNS,例如:
$ips = dns_get_record('db.example.com', DNS_A);
$ip = $ips[array_rand($ips)]['ip'];
$config['hostname'] = $ip;
注意:dns_get_record() 是阻塞调用,高并发下需加本地缓存(TTL 控制在 5–10 秒),否则 DNS 查询会成为瓶颈。
真实场景中 DNS 轮询的缺陷与替代建议
DNS 轮询在数据库场景下非常脆弱:没有健康检查、无连接失败重试、不感知后端负载、TCP 连接复用会让流量长期卡在一个节点。线上核心业务基本不用它做 MySQL 负载均衡。
更可行的路径:
- 用 ProxySQL 或 MaxScale 做中间代理,支持读写分离 + 权重 + 健康检测
- 用 Kubernetes Service + Headless Service + StatefulSet 管理 MySQL 实例,客户端直连 DNS 名,K8s 自动做 endpoint 轮转(比传统 DNS 更可控)
- 在 ThinkPHP 内通过自定义
ConnectionPool实现带心跳的多节点连接池,比依赖 DNS 更可靠
如果运维只给了一个轮询域名且不允许改架构,那就必须自己处理 DNS 刷新和连接容错——别指望框架自动兜底。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











