作者|石钟浩、张龙

企划|凌敏

近些年来,因为eBPF在Linux内核级别灵活的可编程性、安全性等优势,在云原生网路、安全和可观测性等方面应用广泛。eBPF可以在不侵入任何业务代码的基础上实现云原生应用的可观测性。并且eBPF对Linux内核版本是有一定要求的(4.14以上),伏羲私有云部份生产集群的内核版本比较低,升级内核会影响大量线上应用,成本太高。

而kindling刚好在基于eBPF实现云原生可观测性能力的基础上,利用内核模块技术在低版本Linux内核上实现了等价于eBPF的相关能力。本文会介绍一些伏羲私有云基于eBPF和kindling在云原生可观测性领域的一些探求。

背景

伏羲私有云的监控是基于主流的Prometheus+Grafana实现的,能较好地满足大部份日常的监控需求,然而随着业务的发展,内部多个RPC等自研网路通讯合同被广泛应用,对监控系统提出了更高的要求。目前主要面临的挑战有:

eBPF与kindling

eBPF简介

eBPF为ExtendedBerkeleyPacketFilter的简写,字面意思为扩充的伯克利数据包过滤器,经过扩充,eBPF的功能远比包过滤器强悍得多。eBPF是一个框架,容许用户在操作系统的内核中加载和运行自定义程序,这意味着它可以扩充甚至更改内核的行为。eBPF程序加载和运行构架图如右图所示:

linux内核中网络协议的设计与实现_linux内核设计和实现_linux 内核 设计 实现 第二版

eBPF相关技术原理不是本文重点,不再赘言。近些年来,eBPF之所在云原生领域发展迅速,主要得益于几个优势:

kindling简介

kindling是一款基于eBPF的云原生可观测性开源工具,借以帮助用户更好、更快地定界(triage)云原生系统故障。通过kindling,用户可以快速定界问题类型,例如是应用代码问题还是基础设施问题。若果是代码问题,可以利用APM(ApplicationPerformanceMonitoring应用性能监控)监控进一步排查问题;若果是基础设施问题,这么通过剖析来自内核的相关监控指标,定位故障点。

kindling构架如右图所示:

linux 内核 设计 实现 第二版_linux内核中网络协议的设计与实现_linux内核设计和实现

kindling整体构架包含三个部份:用户态Go程序、用户态C/C++程序和内核态drivers程序。用户态Go程序满足的是下层可观测需求的开发,其他两个部份实现是内核需求的开发。

伏羲私有云之所以选择kindling进行基于eBPF的云原生可观测性探求,是经过大量督查后综合考虑的结果,主要由于kindling有以下几个优势:

探求与实践

伏羲私有云基于eBPF和kindling在云原生可观测性领域探求和实践中取得了一些阶段性工作成果,并回馈开源社区做了一些贡献。

手动化适配任意Linux内核版本

kindling采用的内核模块或eBPF方式的探针工作在内核态,和内核版本强绑定,为了程序的确切性,目前是完全匹配内核版本号,使用时须要为每一个内核版本单独编译探针。编译依赖Linux内核头文件,但我们的集群诸多,不同时期的集群内核版本有所差别,虽然在同一个集群内,也有不同批次的机器加入集群的情况,同时共存了多个内核版本。建立kindling镜像时都会面临以下两个问题:

建立成本高,须要自动在不同内核版本的节点上执行建立镜像的操作,另外出于安全考虑,线上集群原则上是不能开放过多的操作权限的,下载头文件->编译探针->建立镜像的操作流程须要优化;

linux内核设计和实现_linux 内核 设计 实现 第二版_linux内核中网络协议的设计与实现

部份内核版本的头文件已被Debian软件源移除,难以直接下载。

对此,我们实现了一套手动化适配任意Linux内核版本的kindling镜像建立流程,急剧提高了基于kindling进行二次开发的工作效率,整体流程如右图所示:

linux内核设计和实现_linux内核中网络协议的设计与实现_linux 内核 设计 实现 第二版

其核心在于:

将建立镜像流程容器化,在docker容器中执行下载头文件->编译探针->建立镜像的操作;

通过岁月机手动匹配下载已被Debian官方源移除的内核头文件。

伏羲私有云自研RPC合同解析方案设计与实现

伏羲私有云剖析得出kindling现有能力存在一定缺陷,针对自研RPC合同的特点提出了自研的解决方案,基于kindling源码二次开发实现并验证了方案的正确性,在对业务代码零侵入性的基础上,实现了自研合同的可观测性能力,并回馈社区,参与到kindling合同解析核心流程改进方案的设计和验证工作中。

kindling缺陷剖析

kindling目前支持为使用HTTP、DNS、MySQL等通用合同的服务提供恳求级的RED指标(TPS,错误率、延时)。伏羲私有云内部好多服务使用自研合同进行通讯,须要基于kindling进行二次开发,解析自研合同,来获取这种服务的RED指标。

在开发测试过程中,我们发觉,因为自研合同通讯场景相较于HTTP更为复杂,当测试用例中存在以下三种情况之一时,kindling提供的tps指标不确切:

linux 内核 设计 实现 第二版_linux内核中网络协议的设计与实现_linux内核设计和实现

顾客端异步的向服务端发送多次恳求;

服务端在响应个别恳求前linux内核中网络协议的设计与实现,会先恳求顾客端;

服务端主动向顾客端发送消息,并且不要求得到响应。

通讯场景建模

按照自研合同的特点,我们将通讯场景进行建模,以下三种通讯场景是kindling已有的合同解析流程不能支持的。

自研合同解析

自研合同简介

我们选定其中一个RPC自研合同(以下简称gateway合同,已脱敏)进行介绍,它的合同格式和数组涵义如下:

gateway合同用在顾客端和网段的通讯中,网段代理了顾客端和服务端的通讯。顾客端恳求网段时,service_id数组标示真正要恳求的服务,sub_service_id是二级服务标示,标示service_id服务的某个插口,网段按照这两个数组把恳求转发给对应服务的对应插口。body_size数组标示body数组的宽度,body数组储存恳求和响应内容。响应报文body数组前4个字节必须是int32类型的字节码。session_id为会话标示,访问无状态服务时可为空字符串,访问有状态服务时假如为空,代表开启一个新的会话,由gateway依照负载均衡策略分配session_id,交由响应带回,上次恳求若要保持会话则需携带。

解析流程设计与实现

linux内核设计和实现_linux内核中网络协议的设计与实现_linux 内核 设计 实现 第二版

解析流程中,我们专门为gateway合同开启一条旁路,优先根据gateway合同格式解析输入的数据包。显存中维护gatewayMap哈希结构,记录所有根据gateway合同格式的tcp联接,对于系统捕获的每一个kindlingEvent,获取惟一标示TCP联接的PID+FD信息。若gatewayMap记录该TCP联接采用gateway合同,则数据包送入gateway专属解析流程处理;若requestMonitor记录该TCP联接非gateway合同,数据包送入已有解析流程处理。对于新构建的TCP联接,两个哈希表中均无记录,则根据gateway恳求报文格式解析数据包,判定是否属gateway合同,对应更新哈希表。

linux 内核 设计 实现 第二版_linux内核中网络协议的设计与实现_linux内核设计和实现

gateway合同专属解析流程进行处理时linux服务器代维,判别数据包是恳求报文或响应报文,分别根据恳求/响应报文的格式解析,若解析失败,则直接扔掉数据包;若因数据包太紧未能完成解析,则停止处理,等待合并下一数据包内容,重新解析。成功解析出gateway恳求报文时,先将gateway恳求详情缓存到requestMap中,之后,数据包截掉当前恳求报文,剩余部份继续步入恳求报文的解析流程。成功解析出gateway响应报文时,从requestMap匹配对应恳求详情,匹配失败则遗弃响应,匹配成功即完整构成一次网路调用详情,生成DataGroup。

linux内核设计和实现_linux内核中网络协议的设计与实现_linux 内核 设计 实现 第二版

gateway合同专属解析流程中涉及包太紧等待合并、包太长须要分隔。为了易于进行两种操作linux内核中网络协议的设计与实现,用ByteStream储存TCP链接连续出现的数据包。它是类似队列的数据结构,入队KindingEvent,出队字节链表。

linux内核中网络协议的设计与实现_linux内核设计和实现_linux 内核 设计 实现 第二版

基于TPS的内部服务手动扩缩容,实现降本增效

伏羲私有云上不仅通过kong代理对外曝露的服务外,还有好多应用是作为服务调用链的中间服务存在的,并没有通过kong代理对外曝露,因而现有的监控系统得不到基于kong的服务TPS监控指标。

假如须要对这种应用进行TPS监控,就须要对业务代码进行侵入性整修,而基于eBPF和kindling则可以在完全不侵入业务代码的情况下,通过基础指标过滤、转换得到应用的TPS指标,伏羲私有云用户可以依据业务特征在页面上配置基于TPS的手动扩缩容策略,有助于提高集群的资源借助率,实现降本增效。

linux内核设计和实现_linux内核中网络协议的设计与实现_linux 内核 设计 实现 第二版

参与开源社区

伏羲私有云在eBPF和kindling的云原生可观测性的探求和实践中,给社区提了多个issue和PR,在开源技术生态建设中与社区保持沟通与合作,下文介绍其中两个案例。

布署更新kindling流程优化

在基于kindling进行二次开发的过程中,我们会在集群中频繁批量更新布署kindlingdaemonset服务,却发觉kubernetesAPIServer所在节点的监控数据会伴随着出现异常,在kindling批量删掉重建的时间点,刚好对应了节点上ETCDc盘IO负载和CPU负载暴跌的情况。

通过阅读源码,我们定位到kindling程序刚启动时会从APIServer同步集群全部的Pod、Service、ReplicateSet、Node等资源信息,但是确认调用APIServer插口时带有参数"resource_version=0"(会默认优先读缓存数据),通过查看集群日志,我们进一步发觉是由于开发集群APIServer的显存配额较小,直接OOM重启了,这一过程中kindling还在大量并发向APIServer发送查询恳求,连锁引起了ETCD的负载暴跌。

经过和社区沟通确认,我们做了如下操作优化kindling的布署更新流程:

提供容器中编译topoplugin的方式

kindling提供了一个Grafana插件(topoplugin)拿来勾画网路调用拓扑图,该插件仍未通过Grafana官方的,难以从应用商店直接安装使用。kindling只提供了一个预置了topoplugin插件的Grafana镜像供用户试用,缺乏该插件的可执行文件。因此,提供了在容器中编译topoplugin的方式,免予在宿主机配置node.js环境(#332)。

总结与展望

通过一段时间的探求和实践,伏羲私有云在基于eBPF技术生态的云原生可观测领域取得了一些阶段性成果,与开源社区保持着良好的沟通与合作中文linux操作系统,也回馈社区参与到eBPF开源技术生态的建设中。

近些年来,eBPF技术发展非常迅速,相关的云原生可观测性领域的技术生态也十分活跃,而且目前成熟稳定的基础设施还相对较少,将eBPF技术生态在生产环境落地的门槛还是很高,一些比较热门的开源项目,例如cilium等,在我们的实际工作中经过测试和试用,发觉与我们的预期还有一定差别,我们会对基于eBPF的云原生可观测领域保持关注。

作者介绍

石钟浩,网易伏羲中级平台开发工程师。

张龙,网易伏羲平台开发实习生。

本文原创地址://q13zd.cn/fxsyyjyehkzy.html编辑:刘遄,审核员:暂无