大山最近有一些苦恼
这两年 AI 势头发展有些迅猛,大山所在公司是传统行业,他们的高管也想着用 AI 来降本增效,都说 ChatGPT 是 AI 的翘楚,于是高管决定先让员工从使用 ChatGPT 开始
但是直接用 ChatGPT 官网需要访问国外网站,有一定的门槛,高层决定部署一个面向用户的套壳 ChatGPT 网站试试水,通过调用 OpenAI api 来使用 ChatGPT
大山在 Github 上找到了一个套壳项目,很快把这个套壳网站给部署好了,但很快就发现了问题,因为国内直接调 ChatGPT 官网的 api 也是需要访问国外网站的,这样的话用户得访问国外网站才能访问 OpenAI 的 api,这与实际的需求不符(国内用户 99% 不懂访问国外网站)
眼看着交付日期临近,大山急忙向 CTO Tony 求助,Tony 听了大山的汇报,心平气和地说了一句话:大山啊,应该听过一句话,在计算机领域,没有什么是加一层解决不了的,如果有那就再加一层,你想想看,直连不行,能不能采用间接的方式来访问 OpenAI 呢,比如中间加一个代理?
大山恍然大悟,于是立即动手先在 vercel.com(可以简单理解为一个免费高效的 Web 应用部署平台)上部署了一个访问 OpenAI api 的应用,然后国内的请求先访问这个应用,应用再访问 OpenAI api,打算通过这样的方式来实现间接访问 OpenAI api 的效果
然而理想很丰满,现实很骨感,国内无法访问 vercel 上的应用
大山心想主要问题在于国内无法访问 vercel,那我是不是可以找一个代理服务器,只要国内能访问,它也能访问 OpenAI,不就行了,比如香港的服务器就满足需求,于是就把自己的想法给 Tony 提了一下
Tony 笑了一下:使用代理服务器确实可以,但其实国内也有办法访问 vercel 的,可以使用 CNAME 哦
「CNAME,这是啥,之前从未听说过呢」大山困惑道
Tony 看大山对 CNAME 确实一无所知,于是给他科普起了域名解析:
我们知道域名是为了方便人类记忆的,计算机只认 IP 的,任何一个域名都要被解析成 IP 地址才能访问,为了表示域名和其对应的 IP 的关系,我们在 DNS 后台可以填上一条记录来记录域名和 IP 的关系,如下:
example.com | record type | value | TTL |
---|---|---|---|
@ | A | 192.0.2.1 | 14400 |
我们把这样的域名与 IP 直接对应的记录称为 A 记录,上文中的 @ 表示解析主域名(example.com),这样 DNS 解析服务器就知道这个域名可以直接被解析成对应的 IP 了
理论上有了 A 记录域名解析就不成问题了,但 A 记录无法完美解决以下两个场景
多个应用部署在同一台机器( 同一个 IP),这种场景很常见,比如在机器上部署了多人应用,然后使用 Nginx 作为负载均衡器来转发部署在这台机器的其他应用
为了让 DNS 识别每一个域名对应的 IP(假设为 121.239.166.161),我们可以为每一个域名用 A 记录来记录一下
这么做确实也可以,但其实有一个很大的问题是,IP 可能会变的,假设你的服务从一个厂商迁到另一个厂商(比如从腾讯云迁移到阿里云),那么你的服务器 IP 就会发生变化,此时你需要一个个地去改 A 记录中每个域名对应的 IP,实在太过烦琐(几十个应用部署在同一台机器上对大厂而言很常见)
当然了如果你不嫌麻烦,这样确实也能达到目的,但有没有更优雅的方案呢?
计算机科学领域的任何问题都可以通过增加一个间接的中间层来解决,此时 CNAME 就发挥了作用,我们可以让这些域名都先解析到一个临时的域名(假设为 alias.com),然后再为这个 alias.com 域名配置一个 A 记录,这个 A 记录会记录 alias.com 对应的真正的 IP
这样的话 DNS 会先把应用的域名解析到 alias.com,然后再解析成 alias.com 对应的 IP
如果 IP 变了,只要改 alias.com 这一条 A 记录对应的 IP 地址就行了,实在是省事太多
对比原来的一个个改 A 记录无疑是一个巨大的进步
如果说以上的这种场景你不嫌麻烦一个个为每个域名配置 A 记录的话也能达到解析访问域名的话,那接下来的这种场景不使用 CNAME 就无解了
现在很多云厂商都提供了 CDN 的功能,CDN 会将源站资源缓存到位于全国各地的CDN节点上,用户请求资源时,就近返回节点上缓存的资源,那么问题来了,如果我从杭州访问一个资源,假设为 https://b1.example.com/upload/avatar.png,那么 CDN 怎么知道我是从杭州访问的从而从杭州的 CDN 节点返回结果给我呢
如果你用 A 记录显示不合适,因为 A 记录是记录域名与 IP 的关系,无论你填哪个地区的 IP,DNS 都无法把就近的 IP 返回给你
此时 CNAME 就派上用场了,我用 CNAME 让 b1.example.com 指向一个 DNS 调度器,这样的话每次访问请求先打到这个调度器,然后再由节点调度器根据请求的 IP 来判断它来自哪个地区的
进而调度器就可以把离这个 IP 就近的 CDN 节点 IP 返回给请求方,然后就可以从这个就近的 CDN 节点拉取内容了,完整的 CDN 请求链路如下
「我明白了,原来 CNAME 起到了偷天换日的效果,但我还是不明白如何使用 CNAME 来达到让国内的用户访问 vercel 上的应用」大山疑惑道
「vercel 提供了一个域名 cname.vercel-dns.com.,这个域名是能被国内 DNS 解析的」Tony 会心一笑
听到这,大山恍然大悟,我可以为我访问的 api 域名配置一个 CNAME,填的就是 cname.vercel-dns.com.,然后就可以解析出 vercel 平台的对外 IP,拿到了 IP 一切就简单啦
搞完之后普通用户果然能访问 OpenAI api 啦
想起 OpenAI 之前宣布的将封禁中国的流量,大山会心一笑