Hello大家好,我是来自阿里云的谢宇宁今天给大家讲一下如何在K8s里面实现DNS异常的可观的性以及问题的诊断那么我会首先从K8s里面DNS是如何工作的开始然后以及讲到K8s的DNS为什么如此重要那K8s集群里面的DNS是什么时候被用到的呢?当你的微服架构的一个App想要跟另外一个App进行通信的时候它需要DNS做服务发现然后当你如果部署了一些数据库集群数据库集群里面不同的节链之间需要发现的时候也会用到DNS然后在当说日日主件和一些监控主件需要去跟APS server进行通信的时候它需要去发现APS server的地址那它也是通过于DNS来实现的在右图中我们可以看到Web App它想要去寻求数据库的时候它带上了一个域名是Database 6379所以Database就是依赖与了DNS去做域名的解析然后最后拿到IP的地址那底下来看的话其实它只是一个TTP的连接被建立成功了建立的域名是一个Database的一个字幕串并不是一个IP地址所以Web App它首先要做的一件事就是像DNS server去查询这个Database在哪个IP地址上我们可以看到Out这边有一个IP地址这个IP地址通常是一个KBS的Service IP这个Service IP还要被IPPS或者IPTables做一些目的IP地址的一个转换转换完了以后才是我们真正的跑的IP所以我们整个链路是非常的复杂的具体来说Web App它是如何找到这个DNS server的那其实我们看etc result文件可以发现其实etc result文件里面就配置了一个DNS server的一个IP地址172.21.0.10这个IP地址指向的其实是call DNS的一个服务的IP然后配上了一些设取的一些域也就是我们通常所说的搜索域这个搜索域会在比如说你输入Database的时候它会拼接到你的Database后面组成了一个非常长的一个完全的一个域这个完全域才会被递交到call DNS的服务上面去这个call DNS服务刚刚说到它也是一个Service IP所以它也会被做一次DNet也就是目的地址转换最终映射到某一个call DNS的附本上然后其实在整个查询过程中会产生非常多的一些查询当你的搜索域并不满足的时候比如说我们请求3W.R6.com的时候我们通常会拼三次搜索域发现三次搜索域并没有满足只有在最后一次单独请求3W.R6.0的时候才会去满足所以我们会有至少四次请求但是还有一半的请求是在请求4A的级录所以通常我们会花费八次的一个UDP请求也就是DNF请求去得到一个R6.3W.R6.com域名的解析结果这个就很惊讶了那么在DNF里面它本身就是一个非常简单并且可靠的一个协议但是由于KBS里面我们基本上每个组件都会用到前面说到有日治监控等等所以它的报价半径是非常大的其次就刚刚讲到说我们每一次DNF查询除了查询本身和服务除了TTP建立连接的本身需要服务IP的目的地指印设以外我们在做DNF查询的时候也会需要做一次所以整一个链路会非常的长就是会经过比如说内核网络站IPVS 这些模块也会依赖于Cooprosity这种母组件再整合就是说当我们去请求一个外部的域名的时候或者说请求一个跨秘密空间的域名的时候我们其实会产生额外的这些DNF查询其实对DNF二来说就是一个非常高的QPS的要求所以我们在日常的运萎以及供单的处理过程中我们发现DNF的异常成为了一个非常头疼非常高频的一个问题并且这些高频的问题它的一个具体的原因又是不一样的接下来我就介绍几个DNF它出现异常的一些原因比方说有Results Limit也就是我们的资源的限制受限于说我们DNF7它能提供的QPS是受限于CPU的数量也就是说当我们CPU已经不够用或者说你的业务高峰期来的时候你很有可能会遇到DNF的一些解释延迟或者是解释失败等等所以当然这个好解这个只要提升你副本的数量或者说提升每个副本的CPU限制就可以了那么另外一个就是说我们每一个经过内核网络站的包都有可能会进到叫contract table的挥挂跟踪的一个表里面去当你的DS想要去发出去的时候你必须得进到这个表里面去创一个项目但是这个表格它有一个大小的限制所以当有些请求比如说你用了特别多的短连接请求或者说contract table这个表特别小的时候你可能遇到contract table 4这种爆错那这个时候其实你的DNF请求都会失败解法也很简单就是我们尽可能去使用一些长连接请求或者说我们直接把这个表给扩大就好了还有一些场景是由于冲突来导致通常我们在高的QPS场景下我们会遇到比方说contract会在原端口产生冲突的时候比方说我们同时发A和4A记录的时候比方说我们用了RPY这个镜像然后它里面有一个叫MUSL的Lib插件代替Lib C的一个插件那这个插件应该说是一个运行库那这个运行库它会有一个问题就是它会去并发的发这个A和4A的记录然后这就很容易导致Kono里面的一个bug然后会触发contract的这个原端口的冲突然后这个原端口冲突会导致后来的UDP爆弯会直接丢掉所以我们说就是从Kono来看的话就是很多设计来说这个UDP的爆弯它就是很容易丢的再举个例子就是IPVS这个场景IPVS的后端再进行变更比如说我们CodeX去挂掉了一个或者说我们缩了我们的时候那么IPVS也会丢掉来一个同样原端口的爆弯的时候我们也会丢掉这个爆弯这两个问题其实都非常好解就只要把Kono的版本升级到最新或者说升级到5.9以上就OK了那么CodeX它也不是一个没有bug的一个软件然后在某些场景下比如说在早期的一些版本里面它对CodeX的update的一些事件处理的有问题然后导致它的一些插件推出了panic重启了或者说outpass它也是有遇到相似的问题这两个问题会导致Headless Service以及一些外部的域名解决失败这种问题的话可以通过升级CodeX到最新版本来解决以上我们知道了一些DS异常的场景我们如何在CodeX里面去发现这些问题呢CodeX其实有个特点就是它有非常多的插件来组成的比如说Log,Dump,Debug,DnTab这类日之的一些插件然后Trace这种tracing以及Promius这个Metrix的插件这些插件可以帮我们实现非常好的一个可观的性Log是我们最常用的一个插件在客户端请求进来并且CodeX响应的时候它会打印行日制然后去标明这个请求的内容返回马阿扣的以及请求所耗费的时间等等Log可以辅助我们快速的定位一些问题发生的位置完成问题的整个定界过程此外的话我们日之也可以采计到运端里面去做一些日之统计一些趋势的展示甚至一些域名比如说恶意域名的一些访问的神机可以识别到我们集群里面是否有一些沐马或者收工资等等这边就是一个我们在云上面SLS日之服务制作的这个仪表盘然后这个仪表盘里面可以展示一些历史请求的成功率或者说各类请求的Code的变化趋势等等Dump这个插件的话和日之也就是Log插件很类似但是Log插件的话是会在一个请求响应了以后才会打赢Dump会在请求进来的时候就开始打赢这个很适合比如说你相信一个请求已经进到QDNS了但是没有看到相应的Log日之所以这个时候你就可以打开Dump看一下这个日之是什么时候进来的到底进来了没有Dubug插件的话它顾名C就是用于排错比方说你的DNS报完有一些异常的场景的话那其实它会返回一个format arrow等等这样的response code就返回码开始的Dubug之后它会把整个报完以十六进制的方式打印出来这样的话你就可以后期用一些别的工具去看当时这个DNS报完具体是什么情况导致的format arrow就是格式错误像DNS Type插件是一个非常有意思的插件DNS Type本身是一种灵活的二进制日制的协议这个协议是专门为DNS所设计的然后像图中这种客户端想要去访问CodeNsCodeNs在访问上游DNS服务器的这种过程中存在着更多的报文11234这11234会被CodeNs中的DNS Type插件用Pro的Buffer的这种协议发送给DNS Type Server中然后这个server中我们可以去实现一些报文的存储以及一些分析分析完了以后如果说有一些异常的报文的话我们是可以去做告警或者一些进一步的存储等等整个过程中DNS Type插件在处理这些报文的时候采用了一些异部的设计所以对整个CodeNs的一个性能开销影响是非常小的除此之外就是DNS Type这边不是要去做一些文本的处理因为拿到的报文格式就是二进制的直接可以拿来用这个用的场景是什么呢它其实可以代替我们在TDP dump里面去实现这种报文的存储它不是要存到磁盘上它可以直接存到一个远程的DNS Type Server上面然后它可以非常好的完成这个问题的定界然后它可以实现比日治更高效率一些这种反省类化的流程OK 有了DNS Type这个工具以后我们怎么去分析呢其实DNS Type的报文里面的话会涵盖整个DNS协议的原始头部这原始头部里面有一个Rcode这个Rcode代表的就是这个DNS查询的一个返回码所以我们可以根据它的返回码的异常信息去做一些异常的问题的识别以及一些上报比方说0那就是no error就是正常的然后format error就是代表了格式有问题代表的是连不到上游或者是上游有一些别的异常non-exist domain就是域名不存在或者说仅仅就是我们这个域名请求拼的这个社区域也就是搜索域的时候拼错了或者query refuse的通常就是我们配错了一些DNS的上游服务器等等前面说的是Rcode怎么去判断一个DNS是否异常那其实借助于Message types也可以去判断一些异常比方说我们其实请求中一般有三方扣端CodeS以及CodeS的上游DNS服务器那正常的一个外部域名请求的时候如果没有被缓存的情况下其实是扣端请求给CodeSCodeS请求给DNS上游服务器上游服务器再返回给CodeSCodeS再返回给扣端所以相当于有四种Message type的参与如果是被cash的那种请求也就是被缓存过的请求那你只会出现一和四如果是连不到上游服务器的场景下那只有一二四那其实我们在DNS type server端我们可以去识别每个报文它出现的这种情况的组合然后来判断这个报文到底流经了哪些点位然后以及它对你的硬藏场景是什么也可以去做一些分析以及一些问题的定界等等Trace插件的话比较简单它实现了Open Tracing的一个跟踪能力它可以把CodeS接收到请求的一刻然后以及整个插件链是如何往下运行的每个插件它运行了多少时间都会被记录下来发给一个外部的比如说ZipKin这种Tracing的一种服务端上面去这个场景的话通常是用于我们在定位到发现它某个插件有性能瓶颈或者说某个插件的延迟特别高的情况下我们也希望去做一些问题定位的时候可以用到这个插件Promius的话就大家应该都很熟悉它是可以把CodeS里面的这些Metrics也就是一些数值的一些数据给它进行暴露出来然后我们需要一些Promius的服务端去定期的采集这些数据然后这个数据的话可以根据一些Accode或者说根据一些它的一些Cache的这种运行的情况等等的去做一些关键或者说异常形式的一个判断那这边就是一个我们在云上面Promius和Graphon去搭建了一些CodeS的一些实力的监控然后我们可以去看到它的一个Response和Request的一些趋势以及不同Accode的这种请求的这种分布刚才介绍的是一些CodeS服务端侧的一些内建的一些插件然后通常这些插件只能用于整段服务端的异常那么如果说异常发生在客户端的话我们就需要去看到内核网络站里面发生了什么当时为什么UDP这个DS报文会被丢掉等等这种场景我们可以借助于BPF工具去实现这么一些问题的定界以及一些可观测性那这边的话我给出一个实力这个实力是用BPFTrace去写的这个Trace工具可以识别到IPVS在原端口冲突的情况下把一个报文给丢掉然后以及IPTables里面我们可能不小心配了一些像Nanimal Policy或者是一些拦戒策略然后我们也不小心把UDP这个DS报文给丢掉这种场景那它其实可以识别到我们的容器的IP容器使用这个原端口以及它的目的的一些目的IP和目的端口然后甚至说我们可以对这个程序做一些小改造我们可以打出这个DS内部的一些东西比如说它请求了域名 它进入类型等等的所以BPF工具可以去帮我们去实现内核纬度的一些可观的性以及哪个包 哪个原端口什么的 哪个时间段具体丢了什么 因为什么原因丢了因为哪个函数丢了等等这种场景那像BTC比如说有个Galaxy Latency.py那这个工具可以帮我们去定位到我们某个DS它时间是不是耗费的特别长然后Packet的VRU就可以看到我们每个包经过了哪些函数然后通常需要一些网络工底来看这个包在哪个地方被丢掉等等当然借助BPF工具可以实现这种非常丰富的一些问题定位的原因不仅限于扣DSDS以及UDP这种报纹等等OK 最后的话我想跟大家介绍一下就是如果说你接到一个DS报纹的一个异常DS比如说解释失败了或者说等等的一些情况那如何去排查那我觉得一个标准的一个流程会分为四个部分确认采集信息 验证以及修复确认的话就是有一个很重要的点就是说你不要去太快的下结论结论是比如说DS一定是扣无端的异常或者是一定是服务端的异常等等你要确认所有的配置不管是扣无端的DS ConfigDS的配置以及扣DS的一些配置以及所有的POD是不是都是符合预期的甚至是一个运行的状态然后你要确认你最近没有做任何非预期的修改那个修改会不会会直接导致现在的异常然后是第二步采集信息你需要从扣DS的Server然后扣无端和扣无端的科诺认知等等地方去采集有可能跟异常相关的一些情况日质或者说Metrix的数据等等然后你要在不同的地方就扣无端比如说容器里面或者说容器外面的ECS主机上面也有虚机上面然后去对着扣DS的CoopersDS Service IP做一些第一个的测试或者是直接对扣DS的后端做一些第一个测试第三步就是通过一些扣DS的RogMetrix和Trace的一些工具来帮助我们诊断服务端的一些异常或者说一些BPF或者TDPDump之类的工具去诊断是不是这些东西发生了扣无端的丢包或者说一些电路上的丢包最后一点就是我们怎么去执行这个修复这个修复的过程必须得是可以恢度并且可以慢慢地去执行不要一次性把所有的边根或者说被复手段都执行完了然后最好是可以通过一些Metrix比如说Graphna去看我们这个修复以后是不是有所缓解通常我们执行修复的时候我们可以有一些问题去问自己比方说DS异常它多久出现一次是一直在出现然后业务整个都挂掉了还是说每次业务高峰的时间会发生还是说就跟高峰没有关系就时不时的会来这么一次异常不同的这种频繁程度通常代表不同的原因所以我们也要做进一步的不同的一些问题诊断的手段然后再一个问题就是这个影响的规模有多大是整个集群的DS解析都失败了还是部分的节点出现了问题那么很有可能整个集群都失败的时候是我们的配置出现了问题或者说K8s的整个管控平面APS Server出现了当机等等如果只是一些节点或者说几个容器出现了问题的话很有可能是一些资源的一些限制比如说CPU啊Contractor等等这些限制导致了DS的异常最后我们再来小节一下我们听了这么多知道了K8s里面的DS是非常重要的但是又有一些脆弱如果问题发生在服务端我们可以借助一些CodeS的内置可观测性工具来诊断如果说问题大概率的在扣断我们可以使用BPF或者是一些TTP dump等等的工具来诊断那最后给到一点建议就说我们去在K8s里面去做服务发现的时候我们尽可能去参考一些往上当推加实践比如说使用本地款存这些能力那今天分享就到此结束谢谢大家 拜拜