1、基 于 e B P F 的 N g i n x 可 观 测 性 实 践分享人:格尔软件安全网关团队贺红杰第三届 eBPF开发者大会w w w.e b p f t r a v e l.c o m中 国 西 安Nginx作为广泛使用的高性能Web服务器,随着应用复杂性的不断增加,为了保障系统的稳定可靠运行,实现对其内部状态的实时监控和对故障的快速定位越发重要。运维痛点 监控指标不足 基础指标缺失:原生指标覆盖不足,存在大量指标缺失(如SSL握手耗时、SSL Session尺寸)隐形指标缺失:一些性能相关问题需要观测函数级别的处理耗时,原生并不支持 指标关联断层:内核态处理(如TCP建立)与Ngin
2、x用户态处理(Accept)难以联动分析 排障效率低下 请求链路黑盒化:难以追踪单个请求在Nginx内部的完整生命周期(特别是从内核TCP建连到Nginx请求响应处理)偶发故障难复现:只在特定环境下偶发的问题排查定位十分困难(如ssl session偶发性创建失败)第 三 届 e B P F 开 发 者 大 会问题背景与挑战 应对监控指标不足 定制扩展指标:常规性指标缺失,可以通过扩展源码或使用第三方模块来实现支持 隐形指标缺失:临时修改代码来添加指标,费时费力 指标关联断层:排障效率低下 请求链路黑盒化:依赖于运行日志观察请求链路,由于数据量巨大,从中追踪单个请求让人痛不欲生 偶发故障难复现
3、:第 三 届 e B P F 开 发 者 大 会传统方案局限性零侵入:动态Hook Nginx内部函数,无需修改源码,能够很好地解决监控指标缺失问题广覆盖:通过同时追踪内核态+用户态连接请求处理全过程,能够应对指标关联断层问题低开销:观测过程不影响正常业务,对偶发性故障可以做到7x24小时观测高安全:观测操作不会导致内核崩溃进而引发业务故障,便于在生产环境使用第 三 届 e B P F 开 发 者 大 会eBPF方案优势如何解析Nginx自定义结构?Nginx内部自定义了许多结构(如ngx_http_request_t),要怎样方便地观测到特定结构的特定字段(如r-uri)?如何观测Nginx
4、全局变量?Nginx全局变量并不总是作为函数入参与返回值,要怎样观测全局变量(如ngx_accept_mutex_held)?如何观测Nginx局部变量?Nginx局部变量存储在栈/寄存器中,且生命周期仅限于函数上下文,要怎样观测局部变量(如ssl_session)?第 三 届 e B P F 开 发 者 大 会eBPF方案挑战往常方法是通过mock方式简化结构定义:结构成员间深层嵌套时特别麻烦内核追踪可以直接引用相应头文件,用户态对Nginx的追踪能不能做到类似效果?第 三 届 e B P F 开 发 者 大 会解析Nginx自定义结构struct ngx_http_request_s ui
5、nt32_t signature;void *connection;ngx_str_t uri;.;/lib/modules/6.12.13-amd64/source/include/linux/types.h:20:26:error:typedef redefinition with different types(_kernel_fd_set vs struct fd_set)/usr/include/x86_64-linux-gnu/sys/select.h:70:5:note:previous definition is here/lib/modules/6.12.13-amd64/s
6、ource/include/linux/types.h:21:25:error:typedef redefinition with different types(_kernel_dev_t(aka unsigned int)vs _dev_t(aka unsigned long).要做到能够引用Nginx头文件,必须首先解决与内核头文件存在的冲突,对Nginx原始头文件进行一些调整,比如-需要引入limits.h,以完成对各类数据类型的范围限制定义,避免查到内核态定义造成冲突-移除一些对追踪而言不必要的头文件引用,如:#include.第 三 届 e