BIND ICMP端口无法访问的响应

我在运行负载平衡器后面的BIND 9.8.2(RHEL6)的DNSparsing器时遇到了随机问题。

负载均衡器主动通过DNS查询来探测服务器,以确定它是否处于活动状态,并且每隔一段时间就会为端口53获取“连接被拒绝”(ICMP),从而导致服务器在负载均衡服务器池中暂时不可用。

这种情况会间歇性地发生(LB每10秒探测一次,通常会看到1或2次故障,接着是成功),每次几分钟,然后停止,这种情况在高峰负载时间发生,但是在交通在最低。

当问题发生时,BIND启动并运行,这使得“连接被拒绝”消息混乱,我期望从一个服务器端口53没有监听服务,事实并非如此。 即使DNSparsing失败的探测logging,答案将是一个NXDOMAIN或SERVFAIL,而不是一个平坦的UDP拒绝。

查询日志不显示失败的探测器,这意味着UDP数据包在被传送到BIND进行处理之前被拒绝。

我最好的猜测是,这是由于某种资源枯竭而引起的,但我无法弄清楚究竟是什么。 我们正在监视打开的文件描述符, net.netfilter.nf_conntrack_count ,CPU,内存, recursive-clients等,这些指标甚至没有达到问题发生时的限制。

在问题发生的时候,没有一个日志文件会有任何相关的错误信息。

所以,我的问题是:我应该考虑哪些networking指标/参数?

组态

在/ etc / SYSCONFIG /命名

 OPTIONS="-4 -n10 -S 8096 " 

named.conf中

 options { directory "/var/named"; pid-file "/var/run/named/named.pid"; statistics-file "/var/named/named.stats"; dump-file "/var/named/named_dump.db"; zone-statistics yes; version "Not disclosed"; listen-on-v6 { any; }; allow-query { clients; privatenets; }; recursion yes; // default allow-recursion { clients; privatenets; }; allow-query-cache { clients; privatenets; }; recursive-clients 10000; resolver-query-timeout 5; dnssec-validation no; //querylog no; allow-transfer { xfer; }; transfer-format many-answers; max-transfer-time-in 10; notify yes; // default blackhole { bogusnets; }; // avoid reserved ports avoid-v4-udp-ports { 1935; 2605; 4321; 6514; range 8610 8614; }; avoid-v6-udp-ports { 1935; 2605; 4321; 6514; range 8610 8614; }; max-cache-ttl 10800; // 3h response-policy { zone "rpz"; zone "rpz2"; zone "static"; }; rate-limit { window 2; // seconds rolling window ipv4-prefix-length 32; nxdomains-per-second 5; nodata-per-second 3; errors-per-second 3; }; }; 

编辑:UDP接收错误

 $ netstat -su IcmpMsg: InType3: 1031554 InType8: 115696 InType11: 178078 OutType0: 115696 OutType3: 502911 OutType11: 3 Udp: 27777696664 packets received 498707 packets to unknown port received. 262343581 packet receive errors 53292481120 packets sent RcvbufErrors: 273483 SndbufErrors: 3266 UdpLite: IpExt: InMcastPkts: 6 InOctets: 2371795573882 OutOctets: 13360262499718 InMcastOctets: 216 

编辑2:networking内存大小

 $ cat /proc/sys/net/core/rmem_max 67108864 $ cat /proc/sys/net/ipv4/udp_mem 752928 1003904 1505856 

编辑3:与UdpInErrors没有问题

有一个探测失败事件,没有相应的UDP包接收错误的增加,所以似乎排除了原因。

编辑4:在这里可能有2个问题,一些失败的实例有相应的UdpInErrors增加,有些不

我发现了一个与UDP接收错误有关的事件:

UDP在流量中

UDP错误

我已经将内核内存值增加到了:

 # cat /proc/sys/net/core/wmem_max 67108864 # cat /proc/sys/net/core/rmem_max 67108864 # cat /proc/sys/net/ipv4/udp_rmem_min 8192 # cat /proc/sys/net/ipv4/udp_wmem_min 8192 

它似乎没有与负载有关,具有相同甚至更大工作量的类似服务器显示没有问题,同时同一负载均衡器之后的另一个服务器在该时间段内显示完全相同的行为。

编辑5:在BIND的统计信道数据中发现TCP问题的一些证据

发现高UDP数据包接收错误与BIND 统计信道数据中的TCP4ConnFailTCP4SendErr指标之间的关联。

TCP4ConnFail TCP4SendErr

虽然增加的规模与UDPInErrors的规模并不相同,但与其它规范相关性较强,因为在其他时间,这种影响并不存在。

编辑6:情节变厚… syslog似乎是一个促成因素

受影响的DNS服务器被configuration为将查询日志logging到系统日志的local0工具,然后通过UDP将它们转发到远程服务器。 过去,这一直是性能问题的一个原因,事实上,由于这个原因,我们并没有在繁忙的DNS服务器上启用它。

我尝试禁用查询logging,它似乎使udpInErrors问题消失,所以我已经设置了一个实验。 我们在同一个负载均衡器后面有两个服务器,我把serverA的querylogging保持为活动状态,并禁用了serverB上的querylogging(以及syslog的转发)。 问题同时停止在两台服务器上发生。

然后,我重新启用了serverB上的查询logging,这个问题再次出现在两台服务器上

这个试验分两次进行,一次工作量小,一次在最繁忙的时候,只在繁忙的时候才显现出来,所以似乎有一部分与负载有关。

下图显示了networkingstream量和UDP接收错误之间的关系。

服务器B serverB eth0 out serverB udpInErrors

服务器A serverA eth0 out serverB udpInErrors

编辑5中提到的TCP指标也可以find同样的增长效果。

所以根本原因似乎与联网有关,级联会产生所有的症状。 棘手的部分是,这些服务器(实际上是虚拟机)运行在不同的基础设施上(有时不同的机架,甚至是房间),所以它们之间不应该有任何影响传播。

它似乎没有涉及到查询自身,否则效果将不会在服务器之间传播。

发生在我身上的一件事情是,接收系统日志服务器没有路由回这些服务器,所以我们从来没有得到任何回复数据包(如果有的话),所以syslog以尽力而为的“随意忘却”的方式行事。 这可能是一个原因吗?

 Udp: 27777696664 packets received ... 262343581 packet receive errors 

每1个UDP接收错误接收到的105.88个数据报是DNS数据包丢失率非常高的一个比例,这表明您有一个软件瓶颈。 如果内核试图切换数据包时,与UDP套接字关联的接收队列已满,则数据包将丢失,此计数器将递增。 这意味着自上次在此服务器上重新启动以来,已经丢失了超过两亿个数据包

完整的接收队列意味着软件不会从内核快速移除数据包,从而产生最终超过缓冲区大小的积压。 您的下一步应该是确定队列运行如此之高的原因。 举个例子 ,我们的一个用户发现由于繁重的磁盘logging,系统已经被Iowait饱和了。 除了build议您查看所有SNMP性能指标并寻找相关性之外,我无法提供全面的指南来确定根本原因。 如果找不到任何关联,则可能是以硬件+软件堆栈的全部容量运行,而通过向其中添加更多服务器可以更好地解决问题。

作为一个方面说明,可以增加接收队列的大小,但是最好把它看作是处理突发stream量的能力。 如果突发stream量不是您遇到队列溢出的原因,则更大的队列大小将导致您接受的stream量的处理时间更长,这可能是不受欢迎的。 BIND将使用高达32K的接收队列深度,但限于/proc/sys/net/rmem_max指定的值。 通过使用–with-tuning = large选项重新编译BIND,可以进一步提高此数字,从而将潜在的最大值从32K增加到16M。