librdkafka的rdk:broker-1线程cpu百分百问题分析

问题调用栈:

(gdb) bt
#0  0x000000000068307c in rd_kafka_q_pop_serve (rkq=0x1ff31a0, timeout_ms=<optimized out>, version=version@entry=0, cb_type=cb_type@entry=RD_KAFKA_Q_CB_RETURN, callback=callback@entry=0x0, opaque=opaque@entry=0x0) at rdkafka_queue.c:373
#1  0x0000000000683130 in rd_kafka_q_pop (rkq=<optimized out>, timeout_ms=<optimized out>, version=version@entry=0) at rdkafka_queue.c:399
#2  0x000000000066abcf in rd_kafka_broker_ops_serve (rkb=rkb@entry=0x1ff28e0, timeout_ms=<optimized out>) at rdkafka_broker.c:2510
#3  0x000000000066ac84 in rd_kafka_broker_serve (rkb=rkb@entry=0x1ff28e0, abs_timeout=abs_timeout@entry=71168163411018) at rdkafka_broker.c:2532
#4  0x000000000066b157 in rd_kafka_broker_ua_idle (rkb=rkb@entry=0x1ff28e0, timeout_ms=<optimized out>, timeout_ms@entry=-1) at rdkafka_broker.c:2617
#5  0x000000000066c796 in rd_kafka_broker_thread_main (arg=arg@entry=0x1ff28e0) at rdkafka_broker.c:3571
#6  0x00000000006b8d87 in _thrd_wrapper_function (aArg=<optimized out>) at tinycthread.c:583
#7  0x00007f80a07e1eb5 in start_thread () from /lib64/libpthread.so.0
#8  0x00007f80a05098fd in clone () from /lib64/libc.so.6

相关代码(rd_kafka_q_pop):

rd_kafka_op_t *rd_kafka_q_pop (rd_kafka_q_t *rkq, int timeout_ms,int32_t version) {return rd_kafka_q_pop_serve(rkq, timeout_ms, version,RD_KAFKA_Q_CB_RETURN,NULL, NULL);
}

通过 gdb 观察到 timeout_ms 值为 1,也就是 1 毫秒,这是导致 cpu 百分百的原因:

(gdb) f 1
#1  0x0000000000683130 in rd_kafka_q_pop (rkq=<optimized out>, timeout_ms=<optimized out>, version=version@entry=0) at rdkafka_queue.c:399
399     in rdkafka_queue.c
(gdb) info args
rkq = <optimized out>
timeout_ms = <optimized out>
version = 0
(gdb) info reg
rax            0x0      0
rbx            0x0      0
rcx            0x64ab3c08       1688943624
rdx            0x7f7f537b4240   140184838160960
rsi            0x1ff31a0        33501600
rdi            0x1ff31c8        33501640
rbp            0x1ff28e0        0x1ff28e0
rsp            0x7f7f537b4288   0x7f7f537b4288
r8             0x7      7
r9             0x4748105a       1195905114
r10            0x7b     123
r11            0x1da063a5132567 8339124156310887
r12            0x7f7f537b42f0   140184838161136
r13            0x40ba2119744a   71168163411018
r14            0x0      0
r15            0x4      4
rip            0x683130 0x683130 <rd_kafka_q_serve>
eflags         0x246    [ PF ZF IF ]
cs             0x33     51
ss             0x2b     43
ds             0x0      0
es             0x0      0
fs             0x0      0
gs             0x0      0
(gdb) p *(rd_kafka_q_t*)0x1ff31c8
$1 = {rkq_lock = {__data = {__lock = 0, __count = 4289904, __owner = 2144952, __nusers = 0, __kind = 2144952, __spins = 0, __elision = 0, __list = {__prev = 0x20bab8, __next = 0x1ff31a0}}, __size = "\000\000\000\000puA\000\270\272 \000\000\000\000\000\270\272 \000\000\000\000\000\270\272 \000\000\000\000\000\240\061\377\001\000\000\000", __align = 18424997382979584}, rkq_cond = {__data = {__lock = 0, __futex = 0, __total_seq = 0, __wakeup_seq = 0, __woken_seq = 33501696, __mutex = 0x0, __nwaiters = 0, __broadcast_seq = 0}, __size = '\000' <repeats 25 times>, "\062\377\001", '\000' <repeats 19 times>, __align = 0}, rkq_fwdq = 0x300000001, rkq_q = {tqh_first = 0x1ff1930, tqh_last = 0x0}, rkq_qlen = 0, rkq_qsize = 0, rkq_refcnt = 9087760, rkq_flags = 0, rkq_rk = 0x0, rkq_qio = 0x261, rkq_serve = 0x23, rkq_opaque = 0x0, rkq_name = 0x1 <Address 0x1 out of bounds>}
(gdb) p *(int*)0x1ff31a0
$2 = 1

继续跟踪,问题发生在函数 cnd_timedwait_abs:

(gdb) b cnd_timedwait_abs
Breakpoint 1 at 0x6b92c0: file tinycthread_extra.c, line 95.
(gdb) c
Continuing.Breakpoint 1, cnd_timedwait_abs (cnd=cnd@entry=0x1ff31c8, mtx=mtx@entry=0x1ff31a0, tspec=tspec@entry=0x7f7f537b4240) at tinycthread_extra.c:95
95      tinycthread_extra.c: No such file or directory.
(gdb) p *tspec
$3 = {tv_sec = 1688943624, tv_nsec = 1000000000}

函数 cnd_timedwait_abs 源码:

int cnd_timedwait_abs (cnd_t *cnd, mtx_t *mtx, const struct timespec *tspec) {if (tspec->tv_sec == RD_POLL_INFINITE)return cnd_wait(cnd, mtx);else if (tspec->tv_sec == RD_POLL_NOWAIT)return thrd_timedout;return cnd_timedwait(cnd, mtx, tspec); // 走这里来了
}

底层调用的是 Posix 的 pthread_cond_timedwait 函数:

#include <pthread.h>int pthread_cond_timedwait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex,const struct timespec *restrict abstime);

函数 pthread_cond_timedwait 的参数 abstime 是个绝对时间,不是相对时间。初始化如下:

rd_kafka_op_t *rd_kafka_q_pop_serve (rd_kafka_q_t *rkq, int timeout_ms,int32_t version,rd_kafka_q_cb_type_t cb_type,rd_kafka_q_serve_cb_t *callback,void *opaque) {struct timespec timeout_tspec;rd_timeout_init_timespec(&timeout_tspec, timeout_ms);if (cnd_timedwait_abs(&rkq->rkq_cond, &rkq->rkq_lock, &timeout_tspec) == thrd_timedout) {mtx_unlock(&rkq->rkq_lock);}
}static RD_INLINE void rd_timeout_init_timespec (struct timespec *tspec, int timeout_ms) {if (timeout_ms == RD_POLL_INFINITE ||timeout_ms == RD_POLL_NOWAIT) {tspec->tv_sec = timeout_ms;tspec->tv_nsec = 0;} else {timespec_get(tspec, TIME_UTC); // 这里tspec->tv_sec  += timeout_ms / 1000;tspec->tv_nsec += (timeout_ms % 1000) * 1000000;if (tspec->tv_nsec > 1000000000) {tspec->tv_nsec -= 1000000000;tspec->tv_sec++;}}
}

函数 timespec_get:

/* If TIME_UTC is missing, provide it and provide a wrapper fortimespec_get. */
#ifndef TIME_UTC
#define TIME_UTC 1
#define _TTHREAD_EMULATE_TIMESPEC_GET_int _tthread_timespec_get(struct timespec *ts, int base);
#define timespec_get _tthread_timespec_get
#endif#if defined(_TTHREAD_EMULATE_TIMESPEC_GET_)
int _tthread_timespec_get(struct timespec *ts, int base)
{
#if defined(_TTHREAD_WIN32_)struct _timeb tb;
#elif !defined(CLOCK_REALTIME)struct timeval tv;
#endifif (base != TIME_UTC) // 约束为 UTC,即世界统一时间{return 0;}#if defined(_TTHREAD_WIN32_)_ftime_s(&tb);ts->tv_sec = (time_t)tb.time;ts->tv_nsec = 1000000L * (long)tb.millitm;
#elif defined(CLOCK_REALTIME)base = (clock_gettime(CLOCK_REALTIME, ts) == 0) ? base : 0;
#elsegettimeofday(&tv, NULL);ts->tv_sec = (time_t)tv.tv_sec;ts->tv_nsec = 1000L * (long)tv.tv_usec;
#endifreturn base;
}
#endif /* _TTHREAD_EMULATE_TIMESPEC_GET_ */

回过头看函数 cnd_timedwait_abs 的参数 tspec 的值:

(gdb) p *tspec
$3 = {tv_sec = 1688943624, tv_nsec = 1000000000}

将 tv_sec 转为可读的值:

时间戳(秒)	1688943624
ISO 8601	2023-07-09T23:00:24.000Z
日期时间(UTC)	2023-07-09 23:00:24
日期时间(本地)	2023-07-10 07:00:24

而本地的实际时间为:

# date +'%Y-%m-%d %H:%M:%S'
2023-07-13 16:15:27# date +'%s'
1689236277# expr 1689236277 - 1688943624
292653
# expr 292653 / 3600
81

很明显 tspec 不对,。

准备进一步分析时,遇到 gdb 的 bug 了:

(gdb) b gettimeofday
Breakpoint 1 at 0x7fddd8ba9650 (2 locations)
(gdb) b clock_gettime
Breakpoint 2 at gnu-indirect-function resolver at 0x7fddd8c08800 (3 locations)
(gdb) c
Continuing.
../../gdb/elfread.c:1052: internal-error: elf_gnu_ifunc_resolver_return_stop: Assertion `b->loc->next == NULL' failed.
A problem internal to GDB has been detected,
further debugging may prove unreliable.
Quit this debugging session? (y or n)

进一步验证是发生在 clock_gettime,单独断点 gettimeofday 没有问题,而且不会进入 gettimeofday。

$ man clock_gettimeclock_getres(), clock_gettime(), clock_settime():_POSIX_C_SOURCE >= 199309L#  ifdef __USE_POSIX199309
/* Identifier for system-wide realtime clock.  */
#   define CLOCK_REALTIME

找了个正常的,查看:

(gdb) p timeout_tspec
$2 = {tv_sec = 1689237800, tv_nsec = 687268217}# expr 1689237800 - 1688943624
294176
# expr 294176 / 3600
81

暂时怀疑 clock_gettime 调用出问题了,实现在最新的代码中没有变化:https://github.com/confluentinc/librdkafka/blob/master/src/tinycthread.c。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/4797.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

nginx推流环境搭建

目录 1、创建安装文件夹2、安装编译 nginx 所需要的库3、下载 nginx-1.21.6.tar.gz下载 nginx-rtmp-module4、解压解压nginx文件解压rtmp模块5、编译6、安装7、启动nginx,检测nginx是否能成功运行8、配置nginx使用RTMP9、重启nginx服务器1、创建安装文件夹 cd ~ mkdir nginx …

React Hooks

React Hooks basic hooks useStateuseEffectuseContext useState useState接收一个参数&#xff0c;返回的是一个数组&#xff0c;参数表示初始值&#xff0c;数组的第1项就是定义的变量&#xff0c;第2项就是改变变量的方法。 参数可以是基本数据类型&#xff0c;如string…

Comparator.comparing()实现中文排序及空指针处理

一、 Comparator.comparing()的用法请详见以下上一篇文章的汇总介绍。 Comparator用法_乞力马扎罗の黎明的博客-CSDN博客 二、应用示例&#xff1a; 1、中文排序、空值处理 Collator instance Collator.getInstance(Locale.CHINA); checkItemVoList.stream().sorted(Compar…

每日科技分享-POE新增文件和链接发送功能

POE推出新功能 注意POE需要魔法上午才能进去。 实测 实测可以发送论文给chatgpt&#xff0c;然后和AI进行共享的对话。 POE网站链接&#xff1a; 也可以发送链接&#xff0c;实测了一下&#xff0c;似乎有时候并不准确&#xff0c;我发送了关于分层强化的文章&#xff0c;但是…

<数据结构>NO11.归并排序|递归|非递归|优化

文章目录 归并排序递归写法非递归写法修正方案1.归并一段拷贝一段修正方案2.修正区间 算法优化算法分析 归并排序的应用外排序和内排序 归并排序 递归写法 思路: 如果给出两个有序数组&#xff0c;我们很容易可以将它们合并为一个有序数组。因此当给出一个无序数组时&#xf…

http和https的区别(面试题)

概念 Http&#xff1a;HTTP协议是Hyper Text Transfer Protocol&#xff08;超文本传输协议&#xff09;的缩写。HTTP 协议和 TCP/IP 协议族内的其他众多的协议相同&#xff0c; 用于客户端和服务器之间的通信。从WWW服务器传输超文本到本地浏览器的传输协议&#xff0c;它可以…

一个月学通Python(二十):Python制作报表(Web开发)

专栏介绍 结合自身经验和内部资料总结的Python教程,每天3-5章,最短1个月就能全方位的完成Python的学习并进行实战开发,学完了定能成为大佬!加油吧!卷起来! 全部文章请访问专栏:《Python全栈教程(0基础)》 文章目录 专栏介绍制作报表导出Excel报表导出PDF报表生成前端…

python 写个excle表格数据导入mysql数据的服务

下面是一个使用Python将Excel表格数据导入MySQL数据库的示例代码。需要使用pandas和MySQL Connector库。 pythonimport pandas as pd import mysql.connector# 读取Excel文件 df pd.read_excel(data.xlsx)# 连接MySQL数据库 cnx mysql.connector.connect(useryour_username, …

华为无线ac+ap旁挂二层组网常用配置案例

AC控制器理解配置步骤&#xff1a; capwap source interface Vlanif 100 //源IP回包地址 wlan ssid-profile name test //新建个模版名称为test ssid test //wifi名称 wlan security-profile name test //建立安全模版也叫test security wpa-wpa2 psk pass-phrase admin123 a…

linux 安装 cuda

需求&#xff1a; inux 下安装 cuda 进程&#xff1a; 先查看一下系统版本 uname -a查看能支持什么版本的cudacuda toolkit 下载 wget https://developer.download.nvidia.com/compute/cuda/11.1.0/local_installers/cuda_11.1.0_455.23.05_linux.run sudo sh cuda_11.1.0_4…

API 接口是什么?怎么对接 API?

一、API接口是什么&#xff1f; API接口即应用编程接口&#xff0c;是一些预先定义的函数&#xff0c;可以提供应用程序与开发人员基于某软件或硬件以访问一组例程的能力。简单来说&#xff0c;API接口相当于信息的桥梁&#xff0c;它可以让不同平台、应用程序或系统共享数据&…

红帽不再公开RHEL源码,下游如何应对,CentOS的最佳替代需要重新选择

之前写过两篇centos替代的文章 CentOS7将在三年后停止支持&#xff0c;有哪些替代品_centos7 替代_gsls200808的博客-CSDN博客 CentOS8替代盘点_centos8替代品_gsls200808的博客-CSDN博客 现在情况又有新变化了。 当地时间 6 月 21 日&#xff0c;红帽发布公告称&#xff0…

对Element DatePicker时间组件的封装,时间组件开始时间和结束时间绑定

背景 我们时常有时间范围选择&#xff0c;需要选择一个开始时间和一个结束时间给后端&#xff0c;但我们给后端的是两个字段&#xff0c; 分别是开始时间和结束时间&#xff0c;现在使用element绑定的值是一个数组&#xff0c;我们还要来回处理&#xff0c;很麻烦列表也的查询…

JAVA集成国密SM2

JAVA集成国密SM2加解密 一、pom配置二、代码集成2.1、目录结构2.2、源码2.3、测试 三、相关链接 国密算法概述&#xff1a;https://blog.csdn.net/qq_38254635/article/details/131801527 SM2椭圆曲线公钥密码算法 为非对称加密&#xff0c;基于ECC。该算法已公开。由于该算法…

react使用SVGA特效 常用api

下载插件 npm install svgaplayerweb --save react中代码 import React, { useEffect } from react; import SVGA from svgaplayerweb const Svga () > {const bofang () > {var player new SVGA.Player(#demoCanvas);//创建实例var parser new SVGA.Parser(#demo…

centos7安装 mongodb

一、rpm安装 1.1、配置MongoDB Enterprise的yum 源文件 [mongodb-enterprise] nameMongoDB Enterprise Repository baseurlhttps://repo.mongodb.com/yum/redhat/$releasever/mongodb-enterprise/3.4/$basearch/ gpgcheck1 enabled1 gpgkeyhttps://www.mongodb.org/static/pgp…

Pytest使用fixture实现token共享

同学们在做pytest接口自动化时&#xff0c;会遇到一个场景就是不同的测试用例需要有一个登录的前置步骤&#xff0c;登录完成后会获取到token&#xff0c;用于之后的代码中。首先我先演示一个常规的做法。 首先在conftest定义一个login的方法&#xff0c;方法返回token pytes…

【Rust 基础篇】Rust Cargo 自定义构建

导言 在 Rust 中&#xff0c;Cargo 是一个功能强大的构建工具和包管理器&#xff0c;它可以帮助我们管理项目的依赖、构建和发布。Cargo 提供了许多默认的构建行为&#xff0c;但有时我们需要自定义构建过程以满足特定的需求。本篇博客将详细介绍如何在 Rust 中使用 Cargo 自定…

【Maven三】——maven生命周期和插件

系列文章目录 Maven之POM介绍 maven命令上传jar包到nexus 【Maven二】——maven仓库 maven生命周期和插件 系列文章目录前言一、什么是生命周期&why1.三套生命周期2.clean生命周期3.default生命周期4.site生命周期5.命令行与生命周期 二、插件目标三、插件绑定1.内置绑定2…

Matlab使用etopo在线地形数据绘制中国区域DEM地形图

以下是使用MATLAB绘制中国区域DEM地形图的过程和代码示例&#xff1a; 1. 首先&#xff0c;需要从etopo网站下载中国区域的地形数据。进入etopo网站&#xff08;https://www.ngdc.noaa.gov/mgg/global/etopo5.HTML&#xff09;&#xff0c;找到“Download Global Relief Data”…