Featured image of post 域名迁移

域名迁移

域名迁移避坑指南:解决 DNS 缓存与数据一致性的终极方案

在服务器迁移、更换 IP 或域名解析切换的过程中,开发者最常遇到的噩梦莫过于:明明 DNS 解析已经生效,Ping 也是新 IP,但部分用户依然访问的是旧服务器,甚至导致数据写入错误或服务不可用。

很多开发者倾向于直接关停旧服务以“止损”,但这往往会导致用户端出现 502/504 错误或连接超时,严重影响用户体验。本文将深入剖析 DNS 缓存的机制,解释为何“刷新页面”无效,并提供三种不同级别的平滑迁移方案,帮助你实现用户无感知的无缝切换。


一、为什么解析生效了,流量还在旧 IP?

即使你在本地通过 pingnslookup 确认解析已更新,部分用户(甚至你自己)仍可能访问旧 IP。这并非玄学,而是由 DNS 缓存的多级机制网络连接特性 决定的。

1. DNS 缓存的多级“拦路虎” DNS 解析并非实时查询,而是层层缓存。当用户发起请求时,IP 地址的获取顺序如下:

  1. 浏览器缓存:Chrome、Safari 等浏览器自带 DNS 缓存(如 Chrome 的 chrome://net-internals/#dns)。
  2. 操作系统缓存:Windows/macOS/Linux 系统内核会缓存 DNS 记录。
  3. 本地网络设备:家庭或公司的路由器、光猫可能缓存了旧解析。
  4. 运营商(ISP)缓存:这是最不可控的一环。电信、联通等运营商为了节省带宽,往往无视你设置的 TTL(生存时间),强行缓存旧记录。部分地区可能需要几小时甚至 48 小时才能彻底刷新。

2. 长连接(Keep-Alive)未断开 如果客户端(App、浏览器页面、第三方 API)与旧服务器建立了 HTTP 长连接或 WebSocket,只要连接未断开,后续请求会直接在原有的 TCP 连接上发送,根本不会触发新的 DNS 查询


二、为什么用户疯狂“刷新”也没用?

很多开发者误以为让用户“刷新页面”就能获取最新网络状态。实际上,浏览器的“刷新”刷新的是 HTTP 请求,而不是 DNS 解析。

  • 真实情况:只要上述任何一个缓存环节(浏览器、系统、路由器、运营商)命中了旧 IP,用户无论按多少次 F5,流量依然会死死地打在旧服务器上。
  • 何时生效:除非用户切换网络(如 WiFi 切 5G)、重启路由器、或手动清空 DNS 缓存(ipconfig /flushdns),否则只能被动等待缓存过期(TTL 到期)。

直接关停旧服务的后果: 如果旧服务器直接关机或杀进程,访问旧 IP 的用户将面临:

  • 连接失败/超时:用户以为网站倒闭或服务器宕机。
  • 502/504 错误:如果只关了应用没关网关。
  • 数据焦虑:正在提交表单或付款的用户遇到报错,会疯狂重复提交,导致数据混乱或用户流失。

三、三大解决方案:如何完美处理旧服务?

核心诉求是:防止数据错误(写错库、数据不同步),同时保证用户体验。 根据业务容忍度,可选择以下三种方案。

方案 A:旧服务器做“反向代理”(⭐️ 最优解,强推)

这是大厂做无缝迁移的标准做法。不要停掉旧服务器的网络,而是让旧服务器充当“跳板”,将收到的流量透明地转发给新服务器。

  • 原理:无论用户 DNS 刷新与否,最终处理请求和写入数据的都是新服务器。
  • 优点:用户无感知,数据 100% 一致,无报错。
  • 操作:修改旧服务器 Nginx 配置,停掉旧服务进程,将请求 Proxy 到新服务器 IP。

Nginx 配置示例:

server {
    listen 80;
    server_name yourdomain.com;

    location / {
         # 关键点:直接写新服务器的 IP 地址,千万不要写域名
         # 否则旧服务器可能自己解析回自己,造成死循环
        proxy_pass http://<新服务器的 IP 地址>:<新服务器端口>;
    
         # 透传真实用户信息
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

后续步骤:配置生效后,观察旧服务器流量。等 48 小时后确认所有地区 DNS 刷新完毕,再无流量进入,再下线旧服务器。

方案 B:修改旧服务数据库连接(适用于内网/直连)

如果新旧服务器处于同一内网,或允许公网数据库直连,可保持旧服务器服务运行,但修改其配置。

  • 原理:流量可能打到旧机器,但数据落库指向新数据库。
  • 优点:避免数据分裂,实现数据统一。
  • 缺点:旧代码逻辑可能不兼容新库结构;依赖网络连通性。
  • 操作:修改旧服务的 JDBC URL / Redis URL 等配置,指向新服务器数据库。

方案 C:返回优雅的“维护中”提示(兜底方案)

如果方案 A 和 B 都无法实施,且你宁可让用户报错,也绝对不能接受数据出现错误。

  • 原理:停掉业务逻辑,但保留 Web 服务器返回明确状态码。
  • 优点:明确告知用户系统状态,避免产生“网站挂了”的误解,防止脏数据。
  • 操作:关掉旧服务器的后台应用(Java/Node/PHP),让 Nginx 直接返回 503。

Nginx 配置示例:

server {
    listen 80;
    server_name yourdomain.com;

    location / {
         # 返回 503 状态码及提示
        default_type application/json;
        return 503 '{"code": 503, "msg": "系统升级中,由于您的本地网络运营商 DNS 缓存暂未刷新,请等待 10-30 分钟后刷新重试。"}';
    }
}

四、未来迁移的避坑经验(TTL 预调整)

为了避免下次迁移出现同样的问题,建议在换 IP 的 前几天 执行以下操作:

  1. 调低 TTL:去域名服务商处,将 DNS 记录的 TTL 值改到最小(如 60 秒 或 120 秒)。
  2. 等待生效:等待旧的长 TTL 过期,确保全球 DNS 服务器都接受了短 TTL 设置。
  3. 执行迁移:此时更换 IP,缓存刷新速度会大大加快。
  4. 恢复 TTL:确认迁移无误后,将 TTL 调回正常值(如 10 分钟或更长),以减轻 DNS 服务器压力。

五、总结与建议

域名迁移不仅仅是改一条 A 记录,更是一场关于缓存与连接的博弈。

  • 立刻行动:如果正在迁移中,请首选 方案 A(Nginx 反向代理)。只需花 2 分钟改几行配置,就能确保流量无缝导向新服务器,杜绝 502 错误和数据不一致。
  • 核心原则:作为开发者,“让用户无感知地平滑过渡”是最佳实践。
  • 下线时机:只要旧服务器机器未到期,建议保留 2-3 天作为缓冲期。确认监控中旧服务器无任何流量后,再彻底关机。

通过优雅的处理方式,不仅能保护数据一致性,更能体现团队的专业性,避免不必要的用户投诉与信任危机。

使用 Hugo 构建
主题 StackJimmy 设计