当前位置: 首页 > article >正文

nettrace rtt分析器

开源工具学习记录之流程梳理

近期对腾讯的的开源项目: nettrace(网络故障分析工具) ,进行源码学习。
开源仓库:Nettrace开源仓库
开源工具实现注释:nettrace学习记录

  • Nettrace学习记录之流程梳理
  • Nettrace eBPF程序自动挂载方式探究

nettrace rtt分析器

在这里插入图片描述

DEFINE_ANALYZER_ENTRY(rtt, TRACE_MODE_ALL_MASK)
{/*1.通过define_pure_event提取rtt事件数据*/define_pure_event(rtt_event_t, event, e->event);char *msg = malloc(1024);msg[0] = '\0';/*2.将first_rtt和last_rtt格式化成字符串,用于输出和日志记录*/sprintf(msg, PFMT_EMPH_STR(" *rtt:%ums, rtt_min:%ums*"),event->first_rtt, event->last_rtt);/*3.entry_set_msg将聚合后的消息绑定到当前分析条目analy_entry_t*/entry_set_msg(e, msg);return RESULT_CONT;
}
DEFINE_ANALYZER_EXIT_FUNC_DEFAULT(rtt)

1. rtt分析器逻辑

1.1 逻辑梳理

首先看一下哪些跟踪点会触发该分析器:

trace_t trace_tcp_ack_update_rtt = {.desc = "",.type = TRACE_FUNCTION,.analyzer = &ANALYZER(rtt),.is_backup = false,.probe = false,.name = "tcp_ack_update_rtt",.sk = 1,.custom = true,.def = true,.index = INDEX_tcp_ack_update_rtt,.prog = "__trace_tcp_ack_update_rtt",.parent = &group_tcp_state,.rules = LIST_HEAD_INIT(trace_tcp_ack_update_rtt.rules),
};
trace_list_t trace_tcp_ack_update_rtt_list = {.trace = &trace_tcp_ack_update_rtt,.list = LIST_HEAD_INIT(trace_tcp_ack_update_rtt_list.list)
};

在跟踪点的定义中,发现tcp_ack_update_rtt触发该分析器;

看一下该分析器的具体逻辑:

analyzer_result_t analyzer_rtt_exit(trace_t *trace, analy_exit_t *e) __attribute__((weak));
analyzer_result_t analyzer_rtt_entry(trace_t *trace, analy_entry_t *e) __attribute__((weak));
/*analyzer_rtt结构体,trace_t中的.analyzer指向的就是这个结构体*/
analyzer_t analyzer_rtt = {.analy_entry = analyzer_rtt_entry,.analy_exit = analyzer_rtt_exit,.mode = TRACE_MODE_ALL_MASK,
};
analyzer_result_t analyzer_rtt_entry(trace_t *trace, analy_entry_t *e)
{/*1.通过define_pure_event提取rtt事件数据*/define_pure_event(rtt_event_t, event, e->event);char *msg = malloc(1024);msg[0] = '\0';/*2.将first_rtt和last_rtt格式化成字符串,用于输出和日志记录*/sprintf(msg, PFMT_EMPH_STR(" *rtt:%ums, rtt_min:%ums*"),event->first_rtt, event->last_rtt);/*3.entry_set_msg将聚合后的消息绑定到当前分析条目analy_entry_t*/entry_set_msg(e, msg);return RESULT_CONT;
}analyzer_result_t analyzer_rtt_exit(trace_t *trace, analy_exit_t *e)
{rule_run_ret(e->entry, trace, e->event.val);return RESULT_CONT;
}

该分析器首先先通过define_pure_event定义pure_rtt_event_t类型的指针event、并指向采集到的原始数据;接着将数据first_rtt, last_rtt等写入msg中;最终调用entry_set_msg将数据放入对应分析器msg中;

1.2 详细分析

上面简单介绍了rtt分析器的实现过程,重点可以放在define_pure_event ,以及entry_set_msg上,前者获取到原始数据, 后者将有用的数据存入分析器analy_entry_t中的msg中;

1.2.1 获取原始数据

shared.h文件中定义了三个变量:rtt_event_tdetail_rtt_event_tpure_rtt_event_t,

这三个变量都包含与rtt分析器相关的信息:state, flags, last_update, qlen

#define DEFINE_EVENT(name, fields...)		\
typedef struct {				\event_t event;				\int __event_filed[0];			\fields					\
} name;						\
typedef struct {				\detail_event_t event;			\int __event_filed[0];			\fields					\
} detail_##name;				\
typedef struct {				\fields					\
} pure_##name;
#define event_field(type, name) type name;DEFINE_EVENT(rtt_event_t,event_field(u32, first_rtt)event_field(u32, last_rtt)
)

define_pure_event函数根据是否需要detail信息,来选择所定义的变量event指向rtt_event_tdetail_rtt_event_t对应的__event_filed,从而获取到原始数据;

#define define_pure_event(type, name, data)			\pure_##type *name =					\(!trace_ctx.detail ? (void *)(data) +		\offsetof(type, __event_filed) :		\(void *)(data) +			\offsetof(detail_##type, __event_filed))
1.2.2数据处理与记录

通过entry_set_msg将有用数据记录到analy_entry_t中的msg字段;

static inline void entry_set_msg(analy_entry_t *e, char *info)
{e->msg = info;e->status |= ANALY_ENTRY_MSG;
}

2. rtt全流程分析案例

nettrace提供了 基于RTT的性能分析 功能,rtt模式下可以去分析连接的RTT变化,支持根据rtt和srtt来进行过滤。这里是通过跟踪tcp_ack_update_rtt内核函数的调用来获取套接口的rtt更新事件的,默认情况下是统计RTT的分布情况的,使用方式如下:

./nettrace --rtt

在这里插入图片描述

可以通过-detail来输出详细的数据:

在这里插入图片描述

该功能通过tcp_ack_update_rtt挂载点获取rtt‘更新数据的时间, 当获取到的数据进入到perf_buffer缓冲区后,会触发数据处理函数stats_poll_handler执行相应的数据处理逻辑,在该逻辑中便会触发rtt分析器,去分析数据的时延以及时延分布直方图;

详细流程如下:

2.1 数据采集

用户通过./nettrace -rtt来开启rtt 功能, nettrace识别到–rtt ,将模式设定为RTT跟踪模式, 并根据RTT跟踪模式初始化其对应的操作函数stats_poll_handler,在加载和挂载bpf程序时将tcp_ack_update_rtt挂载到内核上;

在成功将ebpf程序挂载之后,便初始化perfbuffer缓冲区持续等待内核中数据,当缓冲区中收到了关于rtt的数据之后,便根据trace_poll() ->poll_handler_wrap->trace_ctx.ops->trace_poll去执行与RTT模式绑定的数据处理回调函数stats_poll_handler;

stats_poll_handler是如何进行数据处理的,将会在后面介绍

int main(int argc, char *argv[])
{/*1.初始化跟踪组*/init_trace_group();do_parse_args(argc, argv);/*2.跟踪点有效性标记*/if (trace_prepare())goto err;/*3.加载并附加eBPF程序*/if (trace_bpf_load_and_attach()) {pr_err("failed to load bpf\n");goto err;}/*4.启动网络追踪功能*/trace_poll(trace_ctx);}

在trace_prepare中进行跟踪模式设定、操作集初始化、挂载点预选;

/*遍历所有挂载点,通过比对内核符号表对每个跟踪点进行有效性标记*/
int trace_prepare()
{/*1.BTF支持检查*//*2.内核版本兼容检查*//*3.跟踪模式设定*/err = trace_prepare_args();/*4.初始化操作集*  遍历trace_ops_all选择支持当前系统的操作集*/for (; i < ARRAY_SIZE(trace_ops_all); i++) {if (trace_ops_all[i]->trace_supported()) {set_trace_ops(trace_ops_all[i]);break;}}/*5.挂载点的预处理*/err = trace_prepare_traces();/*6.确保以root权限运行*//*7.检查内核特性*//*8.只启用第一个有校挂载点,其他的备用挂载点标记为无效*//*9.打印所有有效挂载点*/
}

在trace_bpf_load_and_attach 中将bpf程序加载并挂载在预选的跟踪点上,并根据RTT跟踪模式将数据处理回调函数设定为stats_poll_handler

/*加载并附加eBPF程序*/
int trace_bpf_load_and_attach()
{/*1.load_bpf*/trace_bpf_load();/*2.attach bpf*//*3.准备ops操作函数*/trace_prepare_ops();
}
2.1.1 RTT跟踪模式设定

main->trace_prepare->trace_prepare_args 设定为RTT跟踪模式:

static int trace_prepare_args()
{...ASSIGN_MODE(rtt, RTT);...if (bpf_args->first_rtt || bpf_args->last_rtt)trace_tcp_ack_update_rtt.monitor = 2;/*根据当前的跟踪模式,对相应的追踪点进行标记*/if (trace_prepare_mode(args))goto err;...}
2.1.2 RTT数据处理

main->trace_bpf_load_and_attach->trace_prepare_ops设定RTT模式下的数据处理函数

static void trace_prepare_ops()
{...switch (trace_ctx.mode) {...case TRACE_MODE_RTT:trace_ctx.ops->raw_poll = stats_poll_handler;...}	
2.1.3 数据监听

点那个ebpf程序加载并挂载之后,便开始在内核中采集相应的数据,并将数据发送至perfbuffer, 并触发回调函数stats_poll_handler进行数据处理;

int trace_poll()
{/*1.获取map描述符*//*2.创建perf_buffer 用于监听eBPF程序的输出;*  poll_handler_wrap函数根据指定的模式进行数据的聚合与分析;*  trace_on_lost 用于处理丢失事件的回调函数;*/struct perf_buffer_opts pb_opts = {.sample_cb = poll_handler_wrap,.lost_cb = trace_on_lost,};/*3. 检查perf buffer是否创建成功*//*4.开始监听数据*  调用perf_buffer__poll 监听数据,每次有数据进来,都会触发回调函数poll_handler_wrap;*/while ((err = perf_buffer__poll(pb, 1000)) >= 0) {if (poll_timeout(err))break;}
}

2.2 数据处理

RTT跟踪模式下对应的数据处理回调函数是stats_poll_handler;该函数持续接收来自bpf_map中的数据,并将其

/*** stats_poll_handler - 处理统计数据并以指定格式输出的处理器函数* * 功能:* - 读取 BPF map `m_stats` 中的统计数据。* - 根据模式选择不同的统计类型(RTT 或延迟)。* - 输出统计分布信息。** 返回值:* - 成功时返回 0,失败时返回错误码。*/
int stats_poll_handler()
{/*1. 获取名为 "m_stats" 的 BPF map 文件描述符*/int map_fd = bpf_object__find_map_fd_by_name(trace_ctx.obj, "m_stats");/*2. 持续循环处理统计数据,直到追踪停止*/while (!trace_stopped()) {int start = 0, j;__u64 total = 0; // 统计总数// 从 BPF map 中读取统计数据,并计算总数for (i = 0; i < 16; i++) {bpf_map_lookup_elem(map_fd, &i, count + i);total += count[i];}// 打印统计分布的标题和总数pr_info("%-34s%llu\n", header, total);// 遍历每个桶并输出统计分布for (i = 0; i < 16; i++) {bool has_count = false; // 标志当前桶及其后续桶是否有数据int p = 0, t = 0;       // 百分比和精确度的临时变量// 检查当前桶及其后续桶是否有数据for (j = i; j < 16; j++) {if (count[j])has_count = true;}// 如果当前桶及后续桶都没有数据,且索引已超过 8,则提前结束循环if (!has_count && i > 8)break;// 计算当前桶的范围start = 1 << i; // 当前桶的起始值(指数)sprintf(buf, "%d - %5d%s", start == 1 ? 0 : start,(start << 1) - 1, unit); // 生成桶范围字符串// 如果总数不为零,则计算百分比if (total) {p = count[i] / total;              // 整数部分t = (count[i] % total) * 10000 / total; // 小数部分(四位精度)}// 打印当前桶的统计信息pr_info("%32s: %-8llu %d.%04d\n", buf, count[i], p, t);}// 休眠 1 秒后继续处理下一轮统计数据sleep(1);}return 0; // 处理成功返回 0
}

2.3 数据分析

见1.rtt分析逻辑

            p = count[i] / total;              // 整数部分t = (count[i] % total) * 10000 / total; // 小数部分(四位精度)}// 打印当前桶的统计信息pr_info("%32s: %-8llu %d.%04d\n", buf, count[i], p, t);}// 休眠 1 秒后继续处理下一轮统计数据sleep(1);
}return 0; // 处理成功返回 0

}


相关文章:

nettrace rtt分析器

开源工具学习记录之流程梳理 近期对腾讯的的开源项目: nettrace(网络故障分析工具) ,进行源码学习。 开源仓库&#xff1a;Nettrace开源仓库 开源工具实现注释&#xff1a;nettrace学习记录 Nettrace学习记录之流程梳理Nettrace eBPF程序自动挂载方式探究 nettrace rtt分析器…...

裂变营销策略在“开源链动2+1模式AI智能名片S2B2C商城小程序”中的应用探索

摘要&#xff1a;在当今数字化时代&#xff0c;企业营销手段日新月异&#xff0c;裂变营销作为一种高效的用户增长策略&#xff0c;正逐渐成为众多企业竞相探索的焦点。本文旨在探讨“开源链动21模式AI智能名片S2B2C商城小程序”中裂变营销的应用&#xff0c;通过“分名、分利、…...

VC++ 获取目的IP的路由

GetBestRoute 函数获取到目的IP的最佳匹配路由。 第一个参数为&#xff1a;destination&#xff08;目的IP&#xff09; 第二个参数为&#xff1a;source&#xff08;源IP&#xff09; 通常不需要指定第二个source&#xff0c;这个一般用来匹配具体某一个网卡接口路由的&…...

WangEditor快速实现版

WangEditor快速实现版 效果 案例代码 后端 package com.diy.springboot.controller;import cn.hutool.core.util.IdUtil; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiImplicitParam; import org.sp…...

Java常见面试技术点整理讲解——后端框架(整理中,未完成)

前言&#xff1a; 对于后端常用框架的技术整理&#xff0c;其实框架在平时就是会用就行&#xff0c;但面试时多半需要描述实现原理&#xff0c;这个要靠自己理解&#xff0c;不推荐死记硬背。 这篇和另外几篇文章区分开&#xff0c;主要用于规整Java后端各种框架&#xff0c;…...

Dify 本地部署教程

目录 一、下载安装包 二、修改配置 三、启动容器 四、访问 Dify 五、总结 本篇文章主要记录 Dify 本地部署过程,有问题欢迎交流~ 一、下载安装包 从 Github 仓库下载最新稳定版软件包,点击下载~,当然也可以克隆仓库或者从仓库里直接下载zip源码包。 目前最新版本是V…...

Python----数据可视化(Seaborn二:绘图一)

常见方法 barplot方法 单独绘制条形图 catplot方法 可以条形图、散点图、盒图、小提亲图、等 countplot方法 统计数量 一、柱状图 seaborn.barplot(dataNone, xNone, yNone, hueNone, colorNone, paletteNone) 函数描述data用于绘图的数据集。x用于绘制长格式数据的输入。…...

加速科技Flex10K-L测试机:以硬核创新重塑显示驱动芯片测试新标杆!

在2024年召开的世界显示产业创新发展大会上&#xff0c;加速科技自主研发的高密度显示驱动芯片测试设备Flex10K-L凭借其突破性技术创新&#xff0c;成功入选"十大创新技术&#xff08;产品&#xff09;"。作为国内显示驱动芯片测试领域的标杆性设备&#xff0c;Flex1…...

linux-文本处理命令(echo,cut,sort,uniq,wc,tr,grep)

echo 打印&#xff08;标准输入输出命令&#xff09; [rootlocalhost ~]# echo $HOSTNAME-----$引用变量 localhost [rootlocalhost ~]# echo "$HOSTNAME"----“”弱引用符&#xff08;可以解释特殊含义的字符&#xff09; localhost [rootlocalhost ~]# echo $HOSTN…...

DeepSeek私有化部署7:openEuler 24.03-LTS-SP1安装Open WebUI

Open WebUI是一个 Open WebUI 是一个可扩展的、功能丰富、用户友好的自托管 AI 平台&#xff0c;专为完全离线运行而设计。 它支持多种 LLM 运行环境&#xff0c;包括 Ollama 和 OpenAI 兼容的 API&#xff0c;并内置了用于 RAG 的推理引擎&#xff0c;是一个强大的 AI 部署解决…...

spring-boot-starter和spring-boot-starter-web的关联

maven的作用是方便jar包的管理&#xff0c;所以每一个依赖都是对应着相应的一个或者一些jar包&#xff0c;从网上看到很多对spring-boot-starter的描述就是“这是Spring Boot的核心启动器&#xff0c;包含了自动配置、日志和YAML。”没看太明白&#xff0c;所参与的项目上也一直…...

群晖DS223 Docker搭建为知笔记

群晖DS223 Docker搭建为知笔记&#xff0c;打造你的专属知识宝库 一、引言 在数字化信息爆炸的时代&#xff0c;笔记软件成为了我们管理知识、记录灵感的得力助手。为知笔记&#xff0c;作为一款专注于工作笔记和团队协作的云笔记产品&#xff0c;以其丰富的功能和便捷的使用体…...

NLP文本分析之依存句法分析(理论及技术实践)

引言 在自然语言处理&#xff08;NLP&#xff09;领域中&#xff0c;理解句子的语法结构是实现语义理解的基础。依存句法分析&#xff08;Dependency Parsing&#xff09; 作为句法分析的核心任务之一&#xff0c;通过揭示句子中词语之间的依存关系&#xff0c;为机器翻译、信…...

回溯-子集

78.子集 给你一个整数数组 nums &#xff0c;数组中的元素 互不相同 。返回该数组所有可能的子集&#xff08;幂集&#xff09;。解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。输入&#xff1a;整型数组 输出&#xff1a;二元列表 思路&#xff1a;利用二进制&…...

Nginx(基础安装+配置文件)

目录 一.Nginx基础 1.基础知识点 2.异步非阻塞机制 二.Nginx安装 2.1安装nginx3种方式 1.包管理工具安装&#xff08;yum/apt&#xff09; 2.本地包安装&#xff08;rpm/dpkg&#xff09; 3.源码编译安装 3.1 源码编译安装nginx流程&#xff08;ubuntu&#xff09; 1.…...

Cryptography 与 PyCryptodome 源码级解析

目录 Cryptography 与 PyCryptodome 源码级解析一、引言二、Cryptography 库源码解析2.1 Cryptography 库概述与设计理念2.2 核心模块与数据流分析2.2.1 目录结构与模块划分2.2.2 以 AES-GCM 模式为例的加解密实现2.2.3 源码示例解析2.3 错误处理与边界检测三、PyCryptodome 源…...

uni-app+vue3学习随笔

目录相关 static文件 编译器会把static目录中的内容整体复制到最终编译包内&#xff0c; 非 static 目录下的文件&#xff08;vue组件、js、css 等&#xff09;只有被引用时&#xff0c;才会被打包编译。 css、less/scss 等资源不要放在 static 目录下&#xff0c;建议这些…...

边缘计算的业务种类划分

Pcdn的业务可以根据不同的分类标准来划分 一、按线路类型划分 汇聚模式&#xff1a;一个地方有多条线路&#xff0c;业务种类较多。通常使用X86或X99主板组装的服务器&#xff0c;或各品牌的准系统服务器。收益通常比单线模式更高。 单线模式&#xff1a;一个地方只有一条线路&…...

prompt大师高效提示词解析

Prompt大师李继刚高效提示词示例解析 一、「汉语新解」提示词 核心结构 采用Lisp语言框架嵌套中文语义&#xff0c;通过(defun 新汉语老师 ()...)定义角色风格&#xff08;融合奥斯卡王尔德、鲁迅的批判性语言&#xff09;&#xff0c;用(隐喻 (一针见血...))构建解释逻辑链。…...

QT系列教程(18) MVC结构之QItemSelectionModel模型介绍

视频教程 https://www.bilibili.com/video/BV1FP4y1z75U/?vd_source8be9e83424c2ed2c9b2a3ed1d01385e9 QItemSelectionModel Qt的MVC结构支持多个View共享同一个model&#xff0c;包括该model的选中状态等。我们可以通过设置QItemSelectionModel&#xff0c;来更改View的选…...

【Java面试题汇总】Java面试100道最新合集!

1.说说你对面向对象的理解 得分点 封装,继承,多态、概念、实现方式和优缺点 面向对象的三大基本特征是&#xff1a;封装、继承、多态。 封装&#xff1a;将对象的状态和行为包装在一个类中并对外界隐藏实现的细节&#xff0c;可以通过访问修饰符控制成员的访问权限&#xff0c…...

Vue 实现智能检测文字是否溢出,溢出显示省略号,鼠标悬浮显示全部【附封装组件完整代码+详细注释+粘贴即食】

一、场景需求 在项目中&#xff0c;经常会遇到文本内容超出容器的情况。为了提高用户体验&#xff0c;我希望在文字溢出时显示悬浮提示&#xff0c;未溢出时则不显示。 二、效果演示 三、实现原理 DOM宽度对比法&#xff1a;通过比较元素的scrollWidth&#xff08;实际内容宽…...

51c大模型~合集10

我自己的原文哦~ https://blog.51cto.com/whaosoft/11547799 #Llama 3.1 美国太平洋时间 7 月 23 日&#xff0c;Meta 公司发布了其最新的 AI 模型 Llama 3.1&#xff0c;这是一个里程碑时刻。Llama 3.1 的发布让我们看到了开源 LLM 有与闭源 LLM 一较高下的能力。 Meta …...

为什么要使用前缀索引,以及建立前缀索引:sql示例

背景&#xff1a; 你想啊&#xff0c;数据库里有些字段&#xff0c;它老长了&#xff0c;就像那种 varchar(255) 的字段&#xff0c;这玩意儿要是整个字段都拿来建索引&#xff0c;那可太占地方了。打个比方&#xff0c;这就好比你要在一个超级大的笔记本上记东西&#xff0c;每…...

关于C/C++语言的初学者在哪刷题,怎么刷题

引言&#xff1a; 这篇博客主要是针对初学者关于怎么在网上刷题&#xff0c;以及在哪里刷题。 1.介绍平台&#xff08;在哪刷题&#xff09;&#xff1a; 1.牛客牛客网https://www.nowcoder.com/ &#xff1a;有许多面试题&#xff0c;也有许多供学习者练习的题 2.洛谷洛谷 …...

AI自动化编程初探

先说vscodeclinemodelscope方案&#xff0c;后面体验trae或者cursor再写写其它的。vscode和trae方案目前来说是免费的&#xff0c;cursor要用claud需要付费&#xff0c;而且不便宜&#xff0c;当然效果可能是最好的。 vscode方案&#xff0c;我的经验是最好在ubuntu上&#xff…...

《人月神话》:软件工程的成本寓言与生存法则

1975年&#xff0c;Fred Brooks在《人月神话》中写下那句振聋发聩的断言——“向进度落后的项目增加人力&#xff0c;只会让进度更加落后”——时&#xff0c;他或许未曾料到&#xff0c;这一观点会在半个世纪后的人工智能与云原生时代&#xff0c;依然如达摩克利斯之剑般悬在每…...

深入理解Java中的static关键字及其内存原理

static是Java中实现类级共享资源的核心修饰符&#xff0c;它突破了对象实例化的限制&#xff0c;使得变量和方法能够直接与类本身绑定。这种特性让static成为构建工具类、全局配置等场景的利器&#xff0c;但同时也带来独特的内存管理机制需要开发者关注。 static修饰成员变量…...

Nest.js全栈开发终极实践:TypeORM+微服务+Docker构建高可用企业级应用

文章目录 **第一部分&#xff1a;认识Nest.js与基础环境搭建****1.1 什么是Nest.js&#xff1f;****1.2 环境准备****1.3 创建第一个项目****1.4 启动开发服务器****1.5 核心文件解读** **第二部分&#xff1a;基础控制器与路由****2.1 控制器的作用****2.2 创建自定义控制器**…...

20250310-组件基础2

通过插槽来分配内容 一些情况下我们会希望能和 HTML 元素一样向组件中传递内容&#xff1a; <AlertBox>传入的内容 </AlertBox> 我们期望能渲染成这样&#xff1a; 这可以通过 Vue 的自定义 <slot> 元素来实现&#xff1a; <template><div clas…...