云服务器价格_云数据库_云主机【优惠】最新活动-搜集站云资讯

网站服务器_mysql数据库学习_好用

小七 141 0

调试战争故事:NXDOMAIN之谜

下面的博客文章描述了在Cloudflare基于Mesos的集群上的一次调试冒险。此内部群集主要用于处理日志文件信息,以便Cloudflare客户能够进行分析,以及用于检测和响应攻击的系统。遇到的问题对我们的客户没有任何影响,但确实让工程师挠头。。。问题在我们的一个集群中的某个时候,我们开始看到这样的错误(我们内部DNS上现有域的NXDOMAIN):查找一些。现有的。内部的.host on 10.1.0.9:53:没有这样的主机这看起来很奇怪,因为域确实存在。这是我们的一个内部领域!工程师们曾提到他们见过这种行为,所以我们决定进行更深入的调查。触发此错误的查询多种多样,从mesos dns管理的动态SRV记录到从集群内部查找的外部域。我们第一次天真的尝试是在循环中运行以下内容:虽然是真的;一定要挖一些。现有的。内部的.host>/tmp/数字.txt||中断;结束在一台服务器上运行一段时间后,并没有再现问题:所有的查找都成功了。然后我们记录了一天的服务日志,并对"没有这样的主机"和类似的消息进行了grep。错误是偶尔发生的。错误之间有几个小时,没有明显的模式可以让我们得出任何结论。我们的调查排除了错误发生在Go中的可能性,因为错误也来自Java服务,我们在很多服务中都使用Go。进了兔子洞我们曾经为我们的集群DNS解析程序在单个IP上运行,跨越几个机器。BGP负责宣布从机器到路由器的内部路由。我们决定尝试通过从不同的机器发送大量请求并记录错误来寻找模式。以下是我们的负载测试程序开始时的样子:主包装进口("标志""fmt""净值""操作系统""时间")函数main(){n:=标志。字符串("n","","要查找的域")p:=标志。持续时间("p",时间。毫秒*10,"查找之间暂停")标志。解析()如果*n=""{flag.PrintDefaults标志()操作系统退出(一)}为{_,错误:=net.LookupHost(*n)如果出错!等于零{正式印刷品("错误:",错误)}时间。睡觉(*p)}}我们跑net.LookupHost在一个有小停顿和日志错误的循环中;就这样。将其打包到Docker容器中并在Marathon上运行对我们来说是一个明显的选择,因为不管怎样,这就是我们运行其他服务的方式。原木被运到卡夫卡,然后运到基巴纳,在那里我们可以分析它们。在65台每50毫秒进行一次查找的机器上运行此程序,会在主机之间显示以下错误分布(从高到低):我们没有看到与机架或特定机器的强相关性。错误发生在许多主机上,但不是所有主机上,并且在不同的时间窗口错误发生在不同的计算机上。X轴上的放置时间和Y轴上的错误数显示如下:为了查看某些特定的DNS递归器是否疯了,我们停止了常规计算机上的所有负载生成器,并在递归器本身上启动了负载生成工具。几个小时内没有出现任何错误,这表明未绑定是完全健康的。我们开始怀疑数据包丢失是问题所在,但为什么会出现"没有这样的主机"?只有在DNS响应中出现NXDOMAIN错误时才会发生,但我们的理论是,回复根本没有返回。失踪者为了验证丢失数据包会导致"没有这样的主机"错误的假设,我们首先尝试在端口53上阻止传出流量:sudo iptables-A OUTPUT-p udp--dport 53-j删除在这种情况下,dig和类似的工具只是超时,但不要返回"没有这样的主机":;挖9.9.5-9+deb8u3 Debiancloudflare.com网站;;全局选项:+cmd;;连接超时;无法访问任何服务器Go更聪明一点,它会告诉你发生了什么,但也不会返回"没有这样的主机":错误:查找cloudflare.com网站在10.1.0.9:53:写入udp 10.1.14.20:47442->10.1.0.9:53:写入:不允许操作由于Linux内核告诉发送方它丢弃了数据包,所以我们不得不将命名服务器指向网络中的某个黑洞,该黑洞对数据包没有任何处理,以模拟数据包丢失。还是不走运:错误:查找cloudflare.com网站在10.1.2.9:53:读取udp 10.1.14.20:39046->10.1.2.9:53:i/o超时为了继续指责网络,我们不得不以某种方式支持我们的假设,因此我们在查找时添加了时间信息:s:=时间。现在()_,错误:=net.LookupHost(*n)e:=时间。现在().Sub秒()如果出错!等于零{log.Printf(%.4fs后出错:%s",e,err)}否则,如果e>1{log.Printf(%.4fs后成功,e)}老实说,我们从计时错误开始,后来又增加了成功计时。错误发生在10秒之后,相对较多的成功响应发生在5秒之后,看起来确实像丢包,但仍然不能告诉我们为什么"没有这样的主机"。因为现在我们知道哪些主机更容易受此影响,所以我们在两个屏幕会话中并行运行以下两个命令:虽然是真的;一定要挖cloudflare.com网站>/tmp公司/挖掘日志||中断;完成;日期;sudo killall tcpdumpsudo tcpdump-带州/wtf.盖端口53关键是获取一个解析失败的网络转储。在那里,我们看到了以下查询:00.00秒cloudflare.com网站05.00秒Acloudflare.com网站10.00秒Acloudflare.com.in.我们的.internal.domain两个查询超时,没有任何答案,但第三个查询幸运地成功了。当然,我们没有cloudflare.com网站在我们的内部域中,所以Unbound在查找启动10秒后,正确地给NXDOMAIN答复。宾果游戏让我们看看/等等/决议.conf要了解更多:名称服务器10.1.0.9搜索我们内部.域使用search关键字可以使用短主机名而不是FQDN,从而使myhost透明地等价于我的主人.内部.domain.对于DNS解析程序来说,这意味着以下内容:对于任何DNS查询,请求nameserver10.1.0.9,如果失败,则追加。我们内部.domain到查询,然后重试。对于原始DNS查询,发生什么故障并不重要。通常它是NXDOMAIN,但在我们的例子中,它是由于数据包丢失而导致的读取超时。似乎必须发生以下事件才能出现"无此类主机"错误:原始DNS请求必须丢失5秒后发送的重试必须丢失对内部域的后续查询(由搜索选项引起)必须成功并返回NXDOMAIN另一方面,要观察超时的DNS查询而不是NXDOMAIN,您必须依次丢失4个5秒发送的包(2个用于原始查询,2个用于域的内部版本),这是一个小得多的概率。事实上,我们在15秒后只看到一次NXDOMAIN,而在20秒后却没有看到错误。为了验证这一假设,我们构建了一个概念验证DNS服务器,它可以删除cloudflare.com网站,但为现有域发送NXDOMAIN:主包装进口("github.com/miekg/dns""日志")函数main(){服务器:=&dns服务器{Addr:":53",网络:"udp"}dns.HandleFunc(",",功能(wdns.ResponseWriter,右*dns消息) {m:=&dns消息{}m、 设置回复(r)对于u,q:=范围r.问题{log.Printf("正在检查%s",q.Name)如果q.名称="cloudflare.com网站." {log.Printf("忽略%s",q.Name)//就不管了返回}}w、 写入(m)})log.Printf("倾听…")如果错误:=服务器列表和服务();呃!等于零{日志。法塔尔夫("监听错误:%s",错误)}}最后,我们找到了正在发生的事情,并找到了可靠地复制这种行为的方法。解决让我们考虑一下如何改进我们的客户端,以更好地处理这些暂时性的网络问题,使其更具弹性。的手册页决议.conf告诉您有两个旋钮:timeout和retries选项。默认值分别为5和2。除非您让您的DNS服务器非常繁忙,否则它不太可能需要超过1秒的时间来回复。事实上,如果你碰巧在月球上有一个网络设备,你可以期待它在3秒钟内回复。如果您的名称服务器位于下一个机架中,并且可以通过高速网络访问,则可以安全地假设,如果1秒后没有回复,则您的DNS服务器没有收到您的查询。如果你想减少那些让你头疼的奇怪的"没有这样的域"错误,你可以增加重试次数。在暂时性数据包丢失的情况下重试的次数越多,失败的可能性就越小。你重试的次数越多,完成得越快的机会就越大。假设你有一个真正随机的1%包丢失。2次重试,5s超时:出错前最多等待10s,失败几率0.001%5次重试,1s超时:出错前最多等待5s,失败几率0.000001%在现实生活中,由于数据包丢失不是随机的,所以分布会有所不同,但是您可以期望等待DNS用这种类型的更改来回复的时间要短得多。如您所知,许多提供DNS解析的系统库(如glibc、nscd、systemd resolved)都没有经过加固,无法处理在internet上或在存在数据包丢失的环境中。随着我们的发展,我们已经多次面临创建一个可靠和快速的DNS解析环境的挑战,但后来发现解决方案并不完美。交给你鉴于您在本文中所读到的关于数据包丢失和拆分DNS/私有命名空间的内容,您将如何设计一个快速可靠的解析设置?你会用什么软件?为什么?您将使用标准配置的哪些调整更改?我们很乐意在评论中听到你的想法。如果你喜欢解决问题,比如把你的简历寄给我们。我们正在招聘。