虎牙在全球 DNS 秒级生效上的实践( 二 )


bind 在数据量比较大的时候 , 同步比较慢 。
Local DNS:
根据 TTL 缓存 , 过期后才会刷新数据 。
部分厂商不遵循 TTL 时间缓存 , 超过24小时的缓存时间 。
服务器:
服务器开启 nscd 做 DNS 缓存 。
业务进程:
应用的 DNS 缓存 , 比如 JAVA 虚拟机、框架层的 DNS 缓存 。
以上四种情况会比较影响 DNS 的变更生效流程 , 下图是我们现有的 DNS 变更生效流程:

虎牙在全球 DNS 秒级生效上的实践

文章插图
整体上相对简单 , 只要业务进程这边将自己内部的 DNS 缓存关掉 ,  通过 DNS-F 进行查询的时候 ,  会直接到最近的 Nacos 集群拉取最新的服务节点信息 ,  而且后续节点的变化也会推送到 DNS-F 中 ,  后续可以直接在缓存中获取最新信息 。
国内 Nacos 集群:
集群内通过 raft 协议同步数据 , 毫秒级别完成同步 。
Nacos Sync:
Nacos 推送变化到 Nacos Sync , 跨区域、跨国网络差的情况下可能会导致推送结果丢失 , 或者延迟加大 。
Nacos Sync 会主动拉取实例变更 , 拉取周期和监听的服务数量会影响到变更时效 。
DNS - F:
Nacos 会将变更推送到 DNS - F , 网络差的情况可能会导致推送结果丢失 , 或者延迟加大 。
DNS - F 会主动拉取实例变更 , 拉取周期和监听的服务数量会影响到变更时效 。
业务进程:
通过应用禁用 DNS 缓存来解决 。
核心设计 NacosNacos 有两套推送机制 。
虎牙在全球 DNS 秒级生效上的实践

文章插图
一种是通过客户端来选择一个可获节点 , 比如它第一次拉取的是一个正常节点 , 这个正常节点就会跟它维护一个订阅关系 , 后面有变化就会有一个相应的实地变化推送给我 。如果当前节点挂掉 ,  他会通过重连 ,  在节点列表上 , 连上一个正常的节点 。这时候会有新的 DNS 关系出现 。
另一种是通过 SDK 的方式 , 在服务端寻找可获节点 。服务端每个节点之间 ,  会进行一个可活的探测 ,  选择其中一个可活节点用户维护这个订阅关系 。当这个节点出现问题 ,  连接断开后 ,  SDK 重新发送订阅请求 , 服务端会再次选择另外一个可活的节点来维护这个订阅关系 。这就保证整了推送过程不会因为某个节点挂掉而没有推送 。
推送的效率方面 , 主要是用 UDP 的方式 , 这个效率不像 TCP 消耗那么高 。
以上两个方案都比较适合我们目前的场景 。
核心组件设计 Nacos Sync我们选择 Nacos Sync 作为多集群数据同步的组件 , 主要是从以下4方面进行考虑的 。
  • 同步粒度:
Nacos Sync 同步数据的时候是以服务为维度 ,  比较容易做最终一致性处理 ,  同时可以提供保活的机制 , 满足节点维持的场景 。数据库通过 Binlog 同步的方式只能局限于事务粒度 ,  而文件同步只能通过单个文件的粒度 ,  在服务同步这个维度并不是很合适 。
  • 可用性方面:
Nacos Sync 作为一个中间件 , 是以集群方式进行的 , 传统的数据库和文件方式基本是单进程进行的 , 可用性方面可能不太满足要求 。
  • 同步方式方面:
Nacos Sync 通过在服务粒度的全量写入 , 满足服务注册和 DNS 这两种场景 ,  不需要额外的事务消耗 ,  能保证最终一致即可 。
  • 环形同步:
我们国内有多个可获的节点 , 希望它们之间的数据可以进行环形同步 , 每个节点之间是相互备份的 , 这时候用 Nacos Sync 的话 , 是支持的 。虽然数据库方面 , 比较经典的是主主同步 , 但如果同时对一个主件进行更新的话 , 每一个点进行协助是会有问题的 , 而且文件方面是不支持的 。
Nacos Sync 和开源版本的不同我们对 Nacos Sync 开源方案上做了几处修改 , 以更好的适用于现在的场景:
第一 , 通过配置方式对任务进行分拆 。因为在实际应用场景里面 , 因为 Nacos Sync 的任务达一两万 , 单机很容易到达瓶颈 , 所以我们通过配置的方式将这些分片到多台 Nacos Sync 机器上 。


推荐阅读