开篇概述:SocketTracer定位是一款针对传输层(Socket&TCP)的指标采集工具,可以快速定义网络问题,填补网络监控的盲区。一、背景随着软件应用的集群化、容器化、微服务化,产品的稳定性越来越依赖于网络。现有专有云、一体机产品部署在裸机上,硬件服务器、交换机、OS均不可靠,监控盲点较多,其中网络是重灾区。对于网络不稳定导致的中间件链接超时、设备断开、视频流卡顿等问题,缺乏有效的网络层监控指标进行定界。一旦站点不存在,网络问题就很难定位。现有的网络监控方案主要集中在网卡维度对流量、错误包等指标进行统计,粒度太粗,仅从Socket和TCP连接维度,监控socket缓存状态,收集TCP连接建立、断开、实时时间流量、时延、重传等信息最能直接反映服务的网络状态。2、目标现有的网络监控工具,如ss、netstat等,可以显示服务器当前Socket状态的快照,可以有效协助我们在问题现场排查问题。我们希望拥有在该字段不存在时保留历史网络状态的工具。但是在拓扑复杂的场景下,简单记录历史Socket五元组信息是不够的,因为IP很可能是动态的,当前Socket连接必须关联业务属性(PodName,设备标识...)才能实现恢复问题站点和快速定义故障域的目的。1.典型场景集群中间件访问超时问题定界。数据采集??丢包问题定界:比如设备端声称发包,网关没有收到,站点没了,互相吵架。设备到云的链接检测。直播视频卡顿问题的定界。...2。能力概述Socket维度信息采集Traffic(tx/rx)、delay(srtt)、重传包数、重传总数、收发队列长度、Accept队列长度。TCP生命周期监控:监控TCPClose事件,统计连接时间,发送和接收数据包的总字节数。TCPReset异常监控:接收或发送Reset异常,以及异常发生时的TCPState。适配云原生监控方案现有的netstat、ss等网络信息统计工具无法实现跨网络namespcesocket信息统计。在云原生环境下使用不方便。需要监控k8s集群的所有节点以及节点上所有Pod的Socket状态。采集的数据进行索引,支持Prometheus的Exporter接口。支持将指标推送到VictoriaMetrics。metric选择原则TCPmetric有很多种。收集上述指标的原因是为了找到能够反映应用状态和网络连接状态的指标。如果您对收集指标有其他建议,欢迎留言。下面分析一下采集到以上指标的原因:1)TCPRetransmit包重传的超时时间为RTO,一般为200ms左右。当我们观察到一段时间内出现TCP包重传,然后又恢复正常时,我们就可以判断这个时间段内是否存在网络抖动,可以请网络上的同学帮忙排查。2)TCPSRTTRTT(round-triptime)是数据发送完毕(最后一个比特被推送到数据链路)到收到确认信号的时间。SRTT(平滑往返时间)是一种平滑的RTT。通过srtt历史曲线或者直方图,观察延迟的区间变化,可以知道网络连接的srtt是否抖动。如果服务延迟抖动,而srtt稳定,说明极有可能不是网络问题,可能是业务问题,或者调度问题等。反之,如果srtt也抖动,则可以检查网络连接第一的。3)TCPTx/Rx监听链路的流量,结合对现场业务的了解,在业务数据丢失的场景下,可以辅助定位网络问题或者应用问题:传输层接收到数据,但是在rcv_queue中累积,可能是应用层处理代码块。如果传输层的Rx没有增加,很可能是对端没有发送数据。4)TCP复位原因Reset包是TCP异常断开的常见原因之一。以下总结了可能触发重置事件的原因(如有错误请补充):Non-ExistenceTCPendpoint:PortorIP(RestrictLocalIPaddress):服务器不存在。(SYN->服务器重置)TCPSYN匹配现有会话:服务器或防火墙上已存在相同的5元组连接。(SYN->Serverreset)ListeningendPointQueueFull:应用层没有及时接受,导致服务器的Accept队列已满(fulllinkqueue)。有两种情况:对于新的握手请求SYN->SYN数据包将被服务器静默接收Discarding不会触发重置;恰好客户端返回ACK(握手的第三个数据包)时,accept队列已满,服务器会根据tcp_abort_on_overflowsysctl配置决定是否发送reset。Half-OpenConnections:服务器程序重启,导致连接信息丢失。(Intermediatedata->Serverreset)RESETbyFirewallsintransit:在防火墙保持会话状态(NAT网关)的场景下,防火墙SessionTTL过期。(Intermediatedata->FWreset)Time-WaitAssassination:在ClientTime-Wait期间,client从server收到一个latedatapacket,并向server发回一个Ack,导致server发送一个Rstpacket。(Serverlatedata->ClientAck->ServerReset)AbortingConnection:ClientAbort,内核向服务器发送reset。(ClientReset)3.实现原理SocketTracer使用eBPF+Tracepoint捕捉TCPreset&new&close等事件,使用netlink+tcp_diag周期性捕捉内核Socket信息的快照。1、eBPF背后的思想是:“与其将数据包复制到用户空间进行用户态程序过滤,不如将过滤程序注入内核。”eBPF是运行在内核中的虚拟机,可以运行用户。在用户态实现的eBPF代码在内核中以本地代码的形式和速度执行。它可以结合内核的Trace系统,为我们提供近乎无限的可观察性。eBPF的基本原理:它的所有接口都是通过BPF系统调用与内核交互的。eBPF程序通过LVM和Cline编译生成eBPF字节码,通过BPF系统调用加载到内核中,验证代码的安全性,从而通过JIT实时转换为NativeX86指令。eBPF的整体架构如下:2.kprobe在安装一个kprobes检测点时,kprobe首先备份检测到的指令,然后使用断点指令(即i386和x86_64中的int3指令)替换第一个或几个检测到的指令字节。当CPU执行到检测点时,由于断点指令的执行,会执行trap操作,导致CPU的寄存器被保存,调用相应的trap处理函数,进行trap处理函数会调用对应的notifier_call_chain(内核中一个异步工作机制中注册的所有notifier函数),kprobe通过将检测点关联的处理函数注册到trap对应的notifier_call_chain来实现检测过程。kprobe注册的notifier在执行时,首先执行与探测点关联的pre_handler函数,并将对应的kprobestruct和保存的寄存器作为函数的参数,然后kprobe执行探测指令step的备份步骤,最后,kprobe执行post_handler。所有这些都完成后,紧跟在被探测指令之后的指令流将正常执行。3.Tracepoint相对于kprobe,tracepoint是一个静态钩子函数,在使用前预先写在内核中。tracepoint的实现是基于hooks的思想。探测点放置在函数的入口处。该探测点会跟踪调用该函数的各种信息,并将跟踪到的信息保存在循环队列中。如果用户想读取这些内核,将通过debugfs访问这些内核。4、方案选择eBPF调用方案对比了bpftrace/bcc/libbpf三种调用eBPF能力的方案,最终选择了bcc:bpftrace提供了一种脚本语言,方便将内核信息输出到控制台,使用起来非常方便as一个CLI工具。但是没有提供API接口,不方便后台代码调用和信息读取。libbpf会直接将内核bpf代码编译成bin文件,然后在目标机器上运行。目标是一次编译到处运行。为了解决跨内核版本(配置)的可移植性问题,需要依赖BTF内核选项。目前大多数内核默认是不开启这个功能的。您需要修改配置并重新编译内核。bcc在目标机环境运行阶段动态编译bpf内核代码,解决可移植性问题。是现阶段应用最广泛的解决方案。大多数bpf监控工具都是基于bcc-tools;并提供代码集成的API接口。内核代码基于C语言,应用层代码提供python和go语言API。Socket信息采集方案eBPF+kprobe在目标函数上动态挂载钩子函数,在高频调用场景下额外开销较大(传输发送包函数)。参考ss的实现,基于linuxnetlink+tcp_diag内核模块,该方案适用于应用主动抓取某个时间点socket统计信息的快照,可以减少额外的性能开销。五、总体架构图四、部署配置方法1、命令行参数定义包括Socket收集过滤配置文件路径、socket信息收集周期、vm-insert的URL地址。bash-5.0#./socktracer--helpUsageof./socktracer:-configfilestringSockettracertargetconfigfile(default"/etc/filter.yaml")-metricsCacheNumintMetricslocalcachednumber(default10000)-namespacestringNamespaceformetrics-sockScanIntervalintSocketstatisticalinformationscaninterval(default30)-versionShowversioninformationandexit-vmaddrstringURLofVictoriaMetricswriteaddress-web.listen-addressstringAddresstolistenonforwebinterfaceandtelemetry.(默认“:8080”)-web.metrics-pathstringPathunderwhichtoexposemetrics。(默认“/metrics”)2。Socket收集和过滤配置文件格式一台服务器上的Socket连接很多,数据量比较大。我们往往只关心与一些服务相关的连接,就像tcpdump,我们经常会过滤IP和端口。过滤器配置文件使用yaml格式,定义如下:filter.yaml配置文件定义用于配置过滤跟踪的Socket链接:typeSocketIDstruct{Protocolstring`yaml:"protocol"`//目前只支持TCPv4,需要时会支持UDPandIPv6.LocalIPstring`yaml:"localIP"`//指定本地IP,willoverwriteLocalPodwhenbothsetLocalPodstring`yaml:"localPod"`//指定本地pod名称的前缀,willbeoverwrittenbyLocalIPwhenbothsetLocalPortint`yaml:"localPort"`//指定本地端口,setto0表示不过滤localportPeerIPstring`yaml:"peerIP"`//指定peerIP,willoverwritePortthinPeerPod"peerPort"`//SpecifypeerPort,setto0meansdonotfilterpeerportPeerPodstring`yaml:"peerPod"`//SpecifyprefixofpeerpodName,willbeoverwrittenbyPeerIPwhenbothset}例子:bash-5.0#cat/etc/filter.yamlfilters:-localIP:""//收集目标1:本地IP为不指定,可选ConfigureorsettoemptylocalPort:6379//指定本地端口,一般选择一个fixedserverport作为过滤条件localPod:"default/redis-"//指定本地PodName前缀,格式为:namespace/podNameprefix-localPod:"default/iotx-event-center"//Collectiontarget2:指定本地PodName前缀peerPod:"default/redis-"//指定对端PodName前缀,格式为:namespace/podNameprefixpeerPort:6379//指定对端port5.前台展示1.GrafanaDashboard下图中会监听所有连接到redis服务器的TCP连接(来自不同的Client+Ports),显示并发连接总数和rtt(delay)等信息theconnection:2.KernelVersiondependent(>=4.9)socket信息收集依赖tcp_diag内核模块eBPF还处于快速发展期,内核中的功能也在日益增强,一般推荐使用eBPF基于Linux4.4+(4.9以上)内核,部分LinuxEvent和BPF版本支持如下图所示:
