ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

CoreDNS loadbalance 插件实战:round_robin 随机轮询、weighted 加权调度与子网优先排序

CoreDNS loadbalance 插件实战:round_robin 随机轮询、weighted 加权调度与子网优先排序 后端网络云原生【免费下载链接】corednsCoreDNS is a DNS server that chains plugins项目地址https://gitcode.com/gh_mirrors/co/coredns点击查看免费下载本文围绕 CoreDNS 内置的loadbalance插件展开讲解它如何对 DNS 应答中的 A、AAAA、MX 记录做随机打乱round-robin 负载均衡如何通过权重文件weightfile控制“第一条 A/AAAA 记录”的返回概率以及如何使用prefer指令让指定子网的 IP 在应答中优先出现。读完本文你将掌握该插件的完整配置语法、权重文件格式、热重载机制与底层实现原理可以直接在真实 Corefile 中落地使用。一、插件定位在响应阶段做 DNS 负载均衡loadbalance是 CoreDNS 众多插件中的一个其核心职责是改写响应报文而非转发请求它不关心请求如何被处理而是在下游插件如forward、file、hosts生成应答之后、把报文写回客户端之前对 Answer 区中的 A、AAAA、MX 记录顺序进行调整实现传统意义上的轮询 DNSround-robin DNS负载均衡效果。它在插件链中的注册位置位于 plugin.cfg 的第 52 行loadbalance:loadbalance介于chaos与tsig之间属于核心插件无需额外编译即可使用。从源码结构看该插件的实现分成两条主线通用随机轮询round_robin对 A、AAAA、MX 记录按均匀概率分布打乱顺序这是默认策略加权调度weighted根据权重文件为不同 IP 赋权控制某条 IP 成为应答中第一条 A/AAAA 记录的概率子网优先prefer作为附加能力将命中指定 CIDR 的 A/AAAA 记录重排到应答前列。一个关键细节是插件会始终把 CNAME 记录排在地址记录之前。这是为了兼容 glibc 等部分 stub resolver 实现——它们对先地址后 CNAME的应答顺序比较敏感顺序不当可能导致解析异常。这一行为在 plugin/loadbalance/loadbalance.go 的roundRobin函数中体现得十分明确记录先被分成 CNAME、address、MX、rest 四组输出时按 CNAME → rest → address → MX 的顺序拼接。二、语法与配置参数完整语法如下来自 plugin/loadbalance/README.mdloadbalance [round_robin | weighted WEIGHTFILE] { reload DURATION prefer CIDR [CIDR...] }各配置项说明配置项含义默认值 / 约束round_robin对 A、AAAA、MX 记录按均匀概率分布随机打乱顺序默认策略不写策略参数时即为此策略weighted WEIGHTFILE按权重文件为各 IP 赋权控制第一条 A/AAAA 记录的返回概率必须提供权重文件路径reload DURATION周期性重扫权重文件、更新权重分配的时间间隔默认30s设为0s表示不扫描、不重载prefer CIDR [CIDR...]将命中这些 CIDR 的 A/AAAA 记录重排到应答最前面可指定多个 CIDR按书写顺序优先WEIGHTFILE 路径解析规则如果传入的是相对路径CoreDNS 会在其前面拼接root 插件配置的根路径在 plugin/loadbalance/setup.go 中通过filepath.Join(config.Root, weightFileName)实现。也就是说相对路径是相对于 Corefile 中root指令所设定的目录而不是相对于 Corefile 文件本身所在目录配置时需要注意。reload 时间格式使用 Go 的time.ParseDuration解析支持30s、1m、500ms等写法。若传入无法解析的值插件会直接报错invalid reload duration见 setup_test.go 的负向测试用例。三、round_robin 策略均匀随机打乱应答记录round_robin是默认且最常用的策略。它把应答中同一类型的记录A、AAAA、MX顺序打乱使得多次查询时客户端拿到不同 IP 的先后顺序从而把流量分散到多个后端。其实现位于 plugin/loadbalance/loadbalance.go快速路径优化如果应答中全是同一种地址记录全部是 A 或全部是 AAAA直接整体打乱即可无需分组。注意这里会先复制一份切片再打乱——因为后端如file插件可能直接持有 zone 树中的切片原地打乱会污染后端数据导致并发查询互相干扰。源码注释明确说明了这一点。通用路径将记录分为 CNAME / address / MX / rest 四组分别对 address 和 MX 两组做随机洗牌再按 CNAME → rest → address → MX 顺序输出保证 CNAME 永远在地址记录之前。洗牌算法使用 Fisher-Yates 洗牌随机数取自dns.Id()即 DNS 报文 ID 生成器保证每次应答的顺序都具有随机性。此外randomShuffle不仅处理 Answer 区还会对res.Ns权威区和res.Extra附加区同样做一次roundRobin处理避免遗漏附加区中的地址记录。适用场景当上游如forward指向的公共 DNS或权威后端返回多条 A/AAAA 记录时round_robin可以让不同客户端、不同时刻拿到的首条 IP各不相同实现简单有效的流量分散。四、weighted 策略按权重控制首条记录weighted策略与round_robin有本质区别它不打乱整组记录只关心应答中的第一条 A/AAAA 记录是谁。通过权重文件为每个 IP 赋值插件按权重比例随机选出一条地址记录并交换到列表首位从而控制该 IP 作为首选地址被客户端拿到的概率。注意README 明确指出weighted 策略不涉及 MX 等其它类型记录的顺序调整只关注第一条 A/AAAA 记录。4.1 权重文件Weightfile格式权重文件的通用格式如下# Comment lines are ignored domain-name1 ip11 weight11 ip12 weight12 ip13 weight13 domain-name2 ip21 weight21 ip22 weight22 # ... etc.规则要点以#开头的行是注释空行也会被忽略域名行单独一行的域名作为后续 IP 权重行的所属分组IP 行一行包含IP 地址 权重值两个字段属于最近一个域名行权重值范围是[1, 255]源码中用uint8存储见 weighted.go如果应答中的某个 IP没有出现在权重文件中则按默认权重1参与选择。4.2 源码级的选择算法在 weighted.go 的topAddressIndex函数中对应答中的每条地址记录先在权重文件中查找其 IP 对应的权重值查不到就用默认值 1计算所有权重之和wsum按权重降序对地址排序sort.Slice权重大的排前面生成一个[0, wsum)的随机数按权重累积区间命中某条记录——这等价于按权重比例抽样把选中的记录交换到列表首位setTopRecord见 weighted.go。因此如果给100.64.1.1、100.64.1.2、100.64.1.3分别赋权 3、1、2那么三者成为首条 A 记录的次数比例会收敛到3 : 1 : 2。4.3 权重文件的解析与校验parseWeightsweighted.go对权重文件做严格校验单字段行会被当作域名若该字段本身是一个 IP 地址则报错提示Maybe a missing weight value?域名若未以.结尾会自动补全规范化为 FQDN 形式IP 字段必须是合法 IP权重值必须是 1255 的整数否则报错并给出具体行内容每行字段数不是 1 或 2 时报could not parse weight line。这些校验保证了配置错误能在启动阶段或重载阶段被尽早发现。五、reload权重文件的热更新机制weighted策略下权重文件可以被周期性重读无需重启 CoreDNS 即可动态调整权重分配默认 30 秒扫描一次设reload 0s则完全关闭扫描见 setup.go重载实现weighted.go先计算文件的MD5 校验和与上次记录值相同则跳过避免无谓的重解析文件内容变化时才重新解析并加锁替换内存中的权重表w.mutex.Lock()保护周期性扫描由一个 goroutine ticker 驱动periodicWeightUpdate插件关闭时通过关闭 channel 优雅退出启动时若权重文件暂时打不开插件会记录警告并稍后重试在reload非 0 的前提下而不是直接导致 CoreDNS 启动失败。六、prefer 子网优先排序prefer是插件最近新增的能力与前面两种策略正交它不改变随机性而是在洗牌/加权完成之后再把命中指定 CIDR 的 A/AAAA 记录重排到应答最前面。配置示例摘自 README. { loadbalance round_robin { prefer 10.9.20.0/24 192.168.1.0/24 } forward . 1.1.1.1 }实现位于 prefer.goreorderPreferredSubnets同时处理 Answer 和 Extra 区sortBySubnetPriority按prefer指令中 CIDR 的书写顺序逐个子网把命中记录的 IP 依次取出放入matched列表未命中的记录保持原相对顺序排在后面——因此子网优先级由书写顺序决定先写的 CIDR 优先级更高排序过程中同样保持 CNAME 记录在前CIDR 在 setup 阶段通过net.ParseCIDR解析非法 CIDR 会直接报错见 setup.go。prefer_test.go 的TestSortPreferred用例给出了一个典型验证给定 A、AAAA、CNAME 混合应答与2001:db8::/32、10.9.20.0/24、10.9.30.0/24三个子网期望的最终顺序是 CNAME 在最前随后是三个子网各自命中的记录按 CIDR 书写顺序最后才是未命中的记录。这与文档描述的命中首选子网的 IP 排在前面完全一致。七、完整配置示例7.1 配合 forward对公共 DNS 的应答做轮询对 Google Public DNS 返回的多条 A/AAAA 记录做随机打乱. { loadbalance round_robin forward . 8.8.8.8 8.8.4.4 }7.2 配合 file按权重返回首条地址假设./db.example.comzone 文件中www.example.com有三条 A 记录IP 分别为100.64.1.1、100.64.1.2、100.64.1.3希望它们成为首条 A 记录的概率比为 3 : 1 : 2example.com { file ./db.example.com { reload 10s } loadbalance weighted ./db.example.com.weights { reload 10s } }权重文件./db.example.com.weights内容www.example.com 100.64.1.1 3 100.64.1.2 1 100.64.1.3 2注意此处权重文件的相对路径会被拼接上root插件配置的根路径若 Corefile 中未配置root指令则以 CoreDNS 工作目录为基准因此请确保文件实际位于该目录下。7.3 子网优先让内网地址优先返回. { loadbalance round_robin { prefer 10.9.20.0/24 192.168.1.0/24 } forward . 1.1.1.1 }如果应答中包含多条 A/AAAA 记录插件会将命中10.9.20.0/24的记录排在最前其次是192.168.1.0/24最后才是未命中的记录。八、底层机制插件如何拦截并改写响应从实现角度看loadbalance是一个典型的**响应包装器response writer wrapper**插件LoadBalance.ServeDNShandler.go创建一个LoadBalanceResponseWriter包裹原始的dns.ResponseWriter并把洗牌函数注入其中然后调用链上的下一个插件下游插件写完响应时会调用LoadBalanceResponseWriter.WriteMsgloadbalance.go此时洗牌逻辑才真正生效WriteMsg有一组重要的透传保护条件响应码不是RcodeSuccess如 NXDOMAIN、SERVFAIL时直接透传不做洗牌请求没有 question 区如 AXFR/IXFR 等区域传输场景时直接透传避免Question[0]越界 panic查询类型是 AXFR / IXFR 时直接透传不干扰区域传输若下游直接调用Write原始字节写入而非WriteMsg插件只会记录一条警告日志不做洗牌见 loadbalance.go——这提示使用者只有在走WriteMsg路径的插件组合下loadbalance 才会生效。这套包装响应写入器的设计使得 loadbalance 无需修改请求处理逻辑对上游/后端插件完全透明也天然兼容forward、file、hosts等绝大多数插件。九、配置校验与测试保障插件的配置解析由 setup.go 的parse完成并通过 setup_test.go 覆盖了大量正反向用例可作为排查配置问题的参考合法loadbalance、loadbalance round_robin、loadbalance weighted wfile、带reload 10s/reload 0s的写法报错场景未知策略unknown policy、round_robin后带多余参数unknown property、weighted缺少权重文件参数missing weight file argument、weighted参数过多unexpected argument、非法 reload 时长invalid reload duration、未知块属性unknown property等。这些测试用例同时验证了默认 reload 值30s与自定义值10s、0s的解析结果说明reload 0s是一个被官方测试覆盖的合法配置。十、使用注意事项小结round_robin打乱的是整组记录顺序weighted只决定第一条 A/AAAA选择策略前先明确需求——流量分散用前者控制首选地址用后者权重范围 [1, 255]缺省为 1给少数 IP 赋高权重时其余 IP 会以权重 1 参与竞争比例关系按权重和计算权重文件相对路径以 root 插件路径为基准而不是 Corefile 所在目录跨目录部署时建议使用绝对路径prefer与weighted可以组合使用从源码看preferSubnets存在时洗牌函数会在原策略结果之上再执行reorderPreferredSubnets见 setup.go即先按 round_robin/weighted 洗牌再做子网优先重排AXFR/IXFR 与失败响应会被透传不会破坏区域传输和错误语义若应答经Write原始字节路径写出loadbalance 不会生效——确保你的插件组合走WriteMsg路径。通过 plugin/loadbalance/README.md 与 plugin/loadbalance 目录下的源码handler.go、loadbalance.go、weighted.go、prefer.go、setup.go及对应测试你可以进一步追踪每条记录的洗牌、加权与重排细节并结合自己的 DNS 架构按需选用这三种能力。赞分享后端网络云原生【免费下载链接】corednsCoreDNS is a DNS server that chains plugins项目地址https://gitcode.com/gh_mirrors/co/coredns点击查看免费下载相关推荐MediaMTX5 步跑通 RTSP 推流到 WebRTC 播放的完整链路MediaMTX5 步跑通 RTSP 推流到 WebRTC 播放的完整链路 摄像头吐 RTSP网页端要 WebRTC 低延迟播放App 想走 HLS运维音视频后端Apache DolphinScheduler 负载均衡机制全解析从加权随机、平滑轮询到动态加权调度Apache DolphinScheduler 负载均衡机制全解析从加权随机、平滑轮询到动态加权调度 本篇技术指南以 Apache DolphinSchedu任务调度大数据后端前端draw.io 桌面版 免费离线画图工具draw.io 桌面版 免费离线画图工具 给内网设备画网络拓扑文件上不了云draw.io 桌面版drawio desktop把开源画图编辑器整个装进 E桌面应用图形学上一篇生产环境部署bpftop高可用监控方案设计下一篇Snipsnap终极开发加速工具10个技巧让你代码效率翻倍创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表