游客发表
把同一个域名指向多个IP地址,域名这件事在DNS层面早就支持了。解析你打开命令行,同域敲下 dig example.com,名配看到的置多A记录可能不止一条。这不是域名配置错误,是解析故意为之。
最直接的同域场景是负载均衡。假设你有个电商网站,名配一台服务器扛不住所有流量,置多于是域名你租了三台机器,IP分别是解析 203.0.113.10、203.0.113.11、同域203.0.113.12。名配在DNS服务商后台,置多你给 www.example.com 添加三条A记录,指向这三个IP。DNS服务器返回结果时,会把这三条记录都吐给客户端。客户端拿到列表后,通常选第一条用。至于选哪条,不同操作系统、不同DNS解析库的行为不一样。Windows倾向于按返回顺序,Linux的glibc有时会轮换。这种机制叫“轮询”,英文叫Round Robin。它简单、免费、不需要额外硬件,但有个致命问题:如果其中一台服务器挂了,DNS不会知道。客户端还是可能拿到那个坏IP,然后连接超时。你得自己写健康检查,或者用更高级的DNS服务。
说到健康检查,就得提AWS Route 53、Cloudflare这类服务。它们支持“加权轮询”或者“故障转移”。你可以给每个IP配一个权重,比如性能好的机器权重设100,旧的设20。DNS返回时按权重概率挑选。更关键的是,它们能主动探测IP对应的端口是否存活。一旦发现 203.0.113.11 的80端口不通,立刻把它从返回列表里踢掉。客户端下次查询就只拿到另外两个IP。这种动态调整,纯靠自建DNS很难做到。
另一个常见用途是灰度发布。你开发了新版本,想先让1%的用户试用。怎么做?给同一个域名配两个IP,一个跑旧版,一个跑新版。然后在DNS层面按比例返回。但DNS缓存是个麻烦。用户本地DNS、运营商DNS都可能缓存解析结果,TTL设短一点,比如60秒,能缓解但没法根治。有些团队干脆不用DNS做灰度,改用HTTP头或者网关层路由。DNS多IP更适合做机房级别的容灾,比如电信用户解析到电信IP,联通用户解析到联通IP——这叫“智能解析”或“视图解析”。BIND里用view,云DNS里用线路策略。同一个域名,不同来源的查询返回不同的IP集合。
我见过一个真实案例。某在线教育公司,主力机房在上海,备用机房在张家口。他们给 api.example.com 配了四个IP:两个上海电信、一个上海联通、一个张家口BGP。平时上海三个IP承担全部流量,张家口那个权重设得很低,只用来做监控探测。某天上海电信出口光纤被挖断,Route 53的健康检查在30秒内把两个电信IP标记为不健康。新来的DNS查询只返回联通和张家口IP。用户端虽然会经历几秒到几十秒的解析切换,但整体服务没断。这套方案比单纯用负载均衡器便宜得多,也皮实得多。
不过,多IP不等于高可用。如果所有IP都在同一个机房、同一路供电、同一台交换机上,那配一百个IP也没用。物理隔离才是关键。另外,客户端的行为你得心里有数。Java的InetAddress.getByName()默认只返回第一个IP,而且会缓存。Go的net.LookupHost返回全部,但net.Dial只试第一个。Python的socket.getaddrinfo返回列表,但requests库底层用的urllib3会自己选。写代码时如果不处理多IP重试,DNS配了也白配。
最后说个反直觉的点。有些运维喜欢给一个域名配几十个IP,觉得这样抗压能力最强。实际上,DNS响应包大小有限制。UDP协议下超过512字节就可能被截断,走TCP重试。IP太多,解析延迟反而上升。一般建议控制在4到8个以内。真要扛超大流量,Anycast才是正路——同一个IP广播到多个机房,路由协议帮你选最近的那个。但那已经是另一个话题了。
友情链接