多域名 · 多节点 · 自动择优访问

本套方案为设计,供参考。暂无时间实践操作,后续实践一番。

建议:无法备案用户使用。若备案,直接买国内CDN即可,无需如此麻烦。

建议:用户足够多的时候才采用,用户量小时无需为此一顿操作。

一、问题背景:为什么"多域名 ≠ 自动选择最快"

很多站长都会遇到类似场景:

  • 多个域名(A / B / C / D)

  • 分别部署在 不同服务器 / 不同地区

  • 都能访问同一套后端服务

  • 希望实现:

    • 用户访问自动选择最快的域名
    • 某个域名或服务器异常时,用户无感知切换
    • 不依赖昂贵的全局 CDN / Anycast

但现实是:

  • DNS 不能判断"哪个域名对某个用户最快"
  • DNS 只能在 IP 层 做多地址返回与简单健康检查
  • 浏览器也不会替你比较多个域名

结论一句话:

"多域名本身,不具备自动择优能力。"

要实现这个目标,必须在浏览器侧引入逻辑。


二、核心思想:把"最快"的判断权交给用户浏览器

这套方案的核心思想非常简单,也符合真实的网络工程逻辑:

谁离用户最近、网络路径最好,
就由谁(用户浏览器)来判断。

因此:

  • 不在服务器判断
  • 不在 DNS 判断
  • 而是在 用户真正发请求的那一刻判断

我们让浏览器做三件事:

  1. 同时请求多个候选域名
  2. 记录真实请求耗时(非 ping)
  3. 选择最快且可用的那个域名,并跳转

三、整体架构说明

这里为有四个入口域名:

  • A:https://share.zhangsan.cool
  • B:https://share-hk.zhangsan.cool
  • C:https://share.searchknowledge.cloud
  • D:https://hello.aiforme.cloud

每个域名:

  • 各自解析到一台服务器
  • 各自可以独立访问
  • 各自反向代理同一个真实后端服务 E

整体结构:

复制代码
用户浏览器
   ↓
任意域名 A / B / C / D
   ↓
页面加载时:浏览器测速 A/B/C/D
   ↓
选择最快且可用的域名
   ↓
自动跳转 + 缓存结果

一个非常重要的现实前提

⚠️ 如果用户访问的那个域名 完全打不开(被墙 / 被 DNS 污染)

浏览器 连页面都拿不到,自然无法执行自动逻辑。

因此:

  • 至少要 有一个域名能打开首页
  • 或用户知道其它备用域名

这是任何自动方案都无法绕过的物理限制。


四、DNS 层配置原则(以腾讯云 DNSPod 为例)

1️⃣ 每个域名互相独立(不要 CNAME 依赖)

错误做法(风险极大):

复制代码
B / C / D  → CNAME → A

一旦 A 域名出问题,全部都会"连坐"。

✅ 正确做法:

A / B / C / D 都直接使用 A 记录,各自独立解析

示例配置(每个域名各自配置)

share.zhangsan.cool 为例:

主机记录 类型 记录值
share A IP1

其他域名同理:

  • share-hk.zhangsan.cool → IP2
  • share.searchknowledge.cloud → IP3
  • hello.aiforme.cloud → IP4

这样做的结果是:

  • 任意一个域名异常,不影响其他域名
  • 域名层面做到真正解耦

五、服务器侧:提供统一的健康测速接口 /ping

浏览器要测速,必须有一个极轻量、稳定、永远快速返回的接口。

推荐做法:Nginx 直接返回

在每个站点对应的 Nginx 中加入:

nginx 复制代码
location = /ping {
    add_header Content-Type application/json;
    return 200 '{"status":"ok"}';
}

特点:

  • 不走后端业务

  • 不消耗资源

  • 即使后端挂了,也能区分出:

    • "前端节点还活着"
    • vs "整个站都死了"

六、关键部分:浏览器测速与自动跳转逻辑

这是 "自动选择最快域名" 的核心。

设计原则

  1. 并发测速,避免串行浪费时间
  2. 超时即失败,避免最差线路拖慢整体
  3. 结果缓存,避免每次页面打开都测速
  4. 只在必要时跳转,避免无限循环

可直接使用的前端脚本

把下面这段代码,原样复制到四个站点的公共页面中即可:

html 复制代码
<script>
(function () {
  const MIRRORS = [
    "https://share.zhangsan.cool",
    "https://share-hk.zhangsan.cool",
    "https://share.searchknowledge.cloud",
    "https://hello.aiforme.cloud"
  ];

  const CACHE_KEY = "best_mirror_cache";
  const CACHE_TTL = 10 * 60 * 1000; // 10分钟
  const TIMEOUT = 2000; // 单个测速超时:2秒

  const current = location.origin;

  // 1. 读取缓存
  try {
    const cached = JSON.parse(localStorage.getItem(CACHE_KEY));
    if (cached && Date.now() - cached.time < CACHE_TTL) {
      if (cached.origin !== current) {
        location.replace(cached.origin + location.pathname + location.search);
      }
      return;
    }
  } catch (e) {}

  // 2. 测速函数
  function ping(origin) {
    return new Promise(resolve => {
      const start = performance.now();
      const controller = new AbortController();

      const timer = setTimeout(() => {
        controller.abort();
        resolve({ origin, ok: false, cost: Infinity });
      }, TIMEOUT);

      fetch(origin + "/ping?_=" + Math.random(), {
        signal: controller.signal,
        cache: "no-cache"
      })
        .then(r => {
          clearTimeout(timer);
          resolve({
            origin,
            ok: r.ok,
            cost: r.ok ? performance.now() - start : Infinity
          });
        })
        .catch(() => {
          clearTimeout(timer);
          resolve({ origin, ok: false, cost: Infinity });
        });
    });
  }

  // 3. 并发测速并择优
  window.addEventListener("load", async () => {
    const results = await Promise.all(MIRRORS.map(ping));
    const alive = results.filter(r => r.ok);

    if (!alive.length) return;

    alive.sort((a, b) => a.cost - b.cost);
    const best = alive[0];

    localStorage.setItem(CACHE_KEY, JSON.stringify({
      origin: best.origin,
      time: Date.now()
    }));

    if (best.origin !== current) {
      location.replace(best.origin + location.pathname + location.search);
    }
  });
})();
</script>

七、这套方案是如何"判断最快"的?

很多人关心这点,这里说清楚。

实际判断过程是:

  1. 浏览器真实建立 HTTP 连接

  2. 包含:

    • DNS 查询
    • TCP 三次握手
    • TLS 握手
    • 实际 HTTP 响应
  3. 真实耗时 = performance.now() 差值

这比:

  • ping
  • 人为指定线路
  • 后端猜测

都更接近用户真实体验


八、缓存与体验优化

为什么要用 localStorage

  • 假如用户已经测出最快是 B
  • 下一次再访问任意域名
  • 直接跳过去,不再测速
  • 10 分钟后自动重新评估

这样做到:

  • 页面不闪
  • 不频繁跳转
  • 网络变化时可自动更新

九、方案边界与真实限制

这套方案 不是万能的,但它是"现实可用"的。

✅ 它能做到

  • 多域名真正自动择优
  • 某个域名异常时自动绕开
  • 不依赖 CDN / LB
  • 实现成本极低

❌ 它无法做到

  • 用户只知道 A,而 A 被彻底封锁 → 自动跳 B
    (因为 JS 没机会执行)
  • 毫秒级全局最优调度
  • 替代专业 Anycast / 全球 LB

实际运营建议

始终公开所有可用域名列表

并明确告知用户:

"任一入口均等价,系统会自动选择最快线路。"


十、总结:这是"工程上合理"的最佳解

一句话总结这套技术选择:

DNS 负责"能不能到",
浏览器负责"快不快",
缓存负责"不折腾用户"。

对于个人站长、中小团队:

  • 成本极低
  • 逻辑清晰
  • 可维护性强
  • 不容易翻车

这就是这套方案最大的价值。

相关推荐
C嘎嘎嵌入式开发2 小时前
【NLP实战项目:中文文本分类】数据集THUCNews
人工智能·python·机器学习·自然语言处理
winfredzhang2 小时前
用 Python 手搓一个 PDF 编辑器:wxPython 与 PyMuPDF 实战详解
python·pdf·合并·缩略图·书签
python机器学习ML2 小时前
EconML实战:使用DeepIV、DROrthoForest与CausalForestDML进行因果推断详解
人工智能·python·机器学习·数据挖掘·数据分析·scikit-learn·sklearn
线程A2 小时前
Python中 session flush 和 commit 的区别
数据库·python·oracle
吴佳浩10 小时前
大模型量化部署终极指南:让700亿参数的AI跑进你的显卡
人工智能·python·gpu
diegoXie11 小时前
Python / R 向量顺序分割与跨步分割
开发语言·python·r语言
七牛云行业应用11 小时前
解决OSError: No space left... 给DeepSeek Agent装上无限云硬盘
python·架构设计·七牛云·deepseek·agent开发
BoBoZz1911 小时前
CutWithScalars根据标量利用vtkContourFilter得到等值线
python·vtk·图形渲染·图形处理
失散1311 小时前
Python——1 概述
开发语言·python