openGauss3.1.0 版本的gs_stack功能解密
openGauss3.1.0 版本的 gs_stack 功能解密
不管是测试还是研发,工作中总有遇到各种各样的问题。比如,你有没有遇到过在数据库中执行某个 SQL,却一直不返回结果,这时候的你是不是非常想看一下代码执行到了哪个函数?或者是数据库不响应连接,需要查看数据库当前线程的执行情况呢?
在实际生产中,获取生产系统进程堆栈比较麻烦,需要在服务端后台执行 gstack 命令。本期主要介绍内置 gs_stack 工具,可以通过函数调用的方式输出指定线程的堆栈,用于解决现网环境缺少 gs_stack 工具,无法获取调用栈的问题。
内置 gs_stack 工具介绍
在 openGauss 的很多客户场景中,gdb、gstack 等工具都是无法使用的,当系统出现 hang、慢等问题时,无法通过调用栈进行进一步的定位。还有一种情况就是登录客户数据库的流程非常繁杂,需要经过层层审批,这时通过 gsql 等工具连接数据库就相对容易一些。针对以上痛点,通过复用 openGauss 未使用操作系统信号,并在信号处理函数中获取调用栈的方式开发了调用栈工具,以获得服务端 openGauss 的调用栈。
获取调用栈主要包含两种方式,一种是通过执行 SQL 语句获取,另一种是通过 gs_ctl 工具执行命令获取~
1、在客户端工具执行 gs_stack([tid])函数
使用具有monadmin或者sysadmin用户权限的用户,通过 gsql 或者其他工具连接数据库;
执行命令:
openGuass=# select * from gs_stack();
返回当前 openGauss 所有线程的调用栈:
tid | lwtid | stack
---------------+------ +------------------------------------------------------------------
14026731434848 | 2626 | _poll + 0x2d +
| | WaitLatch0rSocket(Latch volatile,int,int,long) + 0x29f +
| | WaitLatch(Latch voatile,int,long) + 0x2e +
| | start_thread +oxc5 +
| | clone + OXC5 +
140116075071232| 23864 |__poll + 0x2d + | | poll + 0x81 +
| | WaitLatchOrSocket(Latch volatile, int, int, long) + 0x6af +
| | WaitLatch(Latch volatile, int, long) + 0x2e +
| | ckpt_pagewriter_sub_thread_loop() + 0x284 +
| | ckpt_pagewriter_main() + 0x92e +
| | int GaussDbAuxiliaryThreadMain<(knl_thread_role)46>(knl_thread_arg) + 0x482 +
| | int GaussDbThreadMain<(knl_thread_role)46>(knl_thread_arg) + 0x854 +
| | InternalThreadFunc(void) + 0x5c +
| | ThreadStarterFunc(void) + 0xa4 +
| | start_thread + 0xc5 +
| | clone + 0x6d +
只需要查看某一个线程的调用栈时,执行命令:
openGuass=# select gs_stack(xxx);
xxx 为为某个线程的 thread_id,能够返回 thread_id 为 xxx 的线程的调用栈:
gs_stack
pthread_sigmask + 0x2a +
gs_signal_recover_mask(__sigset_t) + 0x17 +
gs_signal_send(unsigned long, int, int) + 0x2f9 +
signal_child(unsigned long, int, int) + 0x36 +
get_stack_according_to_tid(unsigned long, StringInfoData) + 0x191 +
gs_stack(FunctionCallInfoData) + 0xcb +
unsigned long ExecMakeFunctionResult<false, false, true>(FuncExprState, ExprContext, bool, ExprDoneCond) + 0x554 +
ExecEvalFunc(FuncExprState, ExprContext, bool, ExprDoneCond) + 0x147 +
ExecTargetList(List, ExprContext, unsigned long, bool, ExprDoneCond, ExprDoneCond) + 0x15d +
ExecProject(ProjectionInfo, ExprDoneCond) + 0x40f +
ExecResult(ResultState) + 0x1da +
ExecResultWrap(PlanState) + 0x18 +
ExecProcNode(PlanState) + 0xde +
ExecutePlan(EState, PlanState, CmdType, bool, long, ScanDirection, _DestReceiver) + 0x1a6 +
standard_ExecutorRun(QueryDesc, ScanDirection, long) + 0x3d9 +
explain_ExecutorRun(QueryDesc, ScanDirection, long) + 0x109 +
ExecutorRun(QueryDesc, ScanDirection, long) + 0x1ad +
PortalRunSelect(PortalData, bool, long, _DestReceiver) + 0x294 +
PortalRun(PortalData, long, bool, _DestReceiver, _DestReceiver, char) + 0x62e +
exec_simple_query(char const, MessageType, StringInfoData) + 0x12b0 +
PostgresMain(int, char**, char const, char const) + 0x2e10 +
BackendRun(Port) + 0x327 +
int GaussDbThreadMain<(knl_thread_role)1>(knl_thread_arg) + 0x5a8 +
InternalThreadFunc(void) + 0x2d +
ThreadStarterFunc(void*) + 0xa4 +
start_thread + 0xc5 +
clone + 0x6d +
openGauss=# select gs_stack(140115727259392);
gs_stack
__select + 0x33 +
pg_usleep(long) + 0xa1 +
pg_sleep(FunctionCallInfoData) + 0xeb +
unsigned long ExecMakeFunctionResultNoSets<false, false>(FuncExprState, ExprContext, bool, ExprDoneCond) + 0x206f +
ExecEvalFunc(FuncExprState, ExprContext, bool, ExprDoneCond) + 0x622 +
ExecTargetList(List, ExprContext, unsigned long, bool, ExprDoneCond, ExprDoneCond) + 0x45d +
ExecProject(ProjectionInfo, ExprDoneCond) + 0xc2d +
ExecResult(ResultState) + 0x79b +
ExecResultWrap(PlanState) + 0x18 +
ExecProcNode(PlanState) + 0x2db +
ExecutePlan(EState, PlanState, CmdType, bool, long, ScanDirection, _DestReceiver) + 0x765 +
standard_ExecutorRun(QueryDesc, ScanDirection, long) + 0xbb5 +
explain_ExecutorRun(QueryDesc, ScanDirection, long) + 0x1f7 +
ExecutorRun(QueryDesc, ScanDirection, long) + 0x947 +
PortalRunSelect(PortalData, bool, long, _DestReceiver) + 0x7d2 +
PortalRun(PortalData, long, bool, _DestReceiver, _DestReceiver, char) + 0xe11 +
exec_simple_query(char const, MessageType, StringInfoData) + 0x3929 +
PostgresMain(int, char**, char const, char const) + 0x61f8 +
BackendRun(Port) + 0x64d +
int GaussDbThreadMain<(knl_thread_role)1>(knl_thread_arg) + 0x9c7 +
InternalThreadFunc(void) + 0x5c +
ThreadStarterFunc(void) + 0xa4 +
start_thread + 0xc5 +
clone + 0x6d +
2、在服务器端使用 gs_ctl stack –D data_dir 命令
当线程池满,无法通过 gsql 连接数据库的时候,可以使用 gs_ctl 工具执行命令获取线程调用栈:
使用集群用户登录服务器,执行命令 gs_ctl stack –D data_dir,data_dir 是指定 gaussdb 的数据目录的绝对路径:
gs_ctl stack –D /path/to/install/data/
可以取 gaussdb 所有线程的调用栈。
[user@euler omm]$ gs_ctl stack -D /path/to/install/data/opengauss
[2022-11-03 20:17:59.288][19256][][gs_ctl]: gs_stack start:
Thread 0 tid<140120252633600> lwtid<23675>
__poll + 0x2d
poll + 0x81
CommWaitPollParam::caller(int ()(pollfd, unsigned long, int), unsigned long) + 0xb1
int comm_socket_call<CommWaitPollParam, int ()(pollfd, unsigned long, int)>(CommWaitPollParam, int ()(pollfd, unsigned long, int)) + 0x28
comm_poll(pollfd, unsigned long, int) + 0x388
ServerLoop() + 0xb77
PostmasterMain(int, char**) + 0x612e
main + 0xaeb
__libc_start_main + 0xf5
0x55feac9a9907
Thread 1 tid<140116236076800> lwtid<23848>
__poll + 0x2d
poll + 0x81
WaitLatchOrSocket(Latch volatile, int, int, long) + 0x6af
SysLoggerMain(int) + 0x17c9
int GaussDbThreadMain<(knl_thread_role)17>(knl_thread_arg) + 0x860
InternalThreadFunc(void) + 0x5c
ThreadStarterFunc(void) + 0xa4
start_thread + 0xc5
clone + 0x6d
只需要查看某一个线程的调用栈时,执行命令:
gs_ctl stack –D data_dir –I xx
data_dir 是指定 gaussdb 的数据目录的绝对路径,xxx 指的是线程的 lwpid(taskid),可以通过 top –Hp 的方式获取线程的 lwpid, 也可以通过 cat /proc/yyyy/task 获取线程的 lwpid 。yyyy 指的是进程 id,可以通过 ps –ux | grep gaussdb 获取。
[uesr@euler omm]$ gs_ctl stack -D /path/to/install/data -I 23860
[2022-11-03 20:22:01.327][40608][][gs_ctl]: gs_stack start:
tid<140116142843648> lwtid<23860>
__poll + 0x2d
poll + 0x81
WaitLatchOrSocket(Latch volatile, int, int, long) + 0x6af
WaitLatch(Latch volatile, int, long) + 0x2e
ckpt_pagewriter_sub_thread_loop() + 0x284
ckpt_pagewriter_main() + 0x92e
int GaussDbAuxiliaryThreadMain<(knl_thread_role)46>(knl_thread_arg) + 0x482
int GaussDbThreadMain<(knl_thread_role)46>(knl_thread_arg) + 0x854
InternalThreadFunc(void) + 0x5c
ThreadStarterFunc(void) + 0xa4
start_thread + 0xc5
clone + 0x6d
总结
通过以上我们介绍的 openGauss 的 gs_stack 功能,我们可以很方便地定位某个 openGauss 线程正在做的事情,并可以根据这些函数调用情况判断当前 openGauss 任务是否出现了问题,以及发现性能瓶颈。后续,我们将会进一步在这个功能上进行演进,不断增强 openGauss 的核心竞争力。
openGauss3.1.0 版本的gs_stack功能解密的更多相关文章
- Dash 2.9.0版本重磅新功能一览
本文示例代码已上传至我的Github仓库https://github.com/CNFeffery/dash-master 大家好我是费老师,就在昨晚,Dash框架发布了其2.9.0版本更新,在一众更新 ...
- ICG_System之全自动代码生成器V2.0版本
大家好! 早在2014年本人就已经利用业余时间开发自己的ICG之代码生成器系统.依靠bootstrap的崛起本人也在不断完善此应用.目的是为了减少开发人员的工作量. 减少不必要的复制粘贴操作,该系统已 ...
- 意料之外,情理之中,Spring.NET 3.0 版本发布-
意料之外,情理之中,Spring.NET 3.0 版本发布- 备受社区和企业开发者广泛关注的Spring.NET在上周发布了3.0版本,并且目前已经保持着持续的更新,让我们一起来看一看他究竟发布了哪些 ...
- 百度echarts 3.0版本和2.0版本的兼容问题
前一段时间,项目中要用到统计图表,之前也用过jqplot的图表插件,这次开发的内容中基于地图的展示还很多,所以后来选择了百度的echarts插件(echarts.baidu.com).刚开始用的时候, ...
- nlog 2.0 强制转换使用 4.0 版本
今天下午研发代码,发现调用其他小组研发的代码,发现其中有使用nlog功能,但nlog版本是2.0 ,而我的项目使用4.0 版本 导致部分功能不能使用,故在web配置文件中加入以下代码即可 <de ...
- 帝国CMS 6.0功能解密之新版结合项功能,帝国结合项使用
可以用来做A-Z信息检索 某字段等于多少,输出 等等 帝国CMS6.0在继承以往版本结合项功能的基础上又新增很多特性,更强大.今天我们就专门来讲解6.0的结合项改进. 回顾下以往版本的结合项语 ...
- 开源社交系统ThinkSNS+ V0.8.0 正式发布(一期功能版本)
智士软件旗下开源sns社交系统ThinkSNS即将进入10周年,推出并行两代系统ThinkSNSV4和ThinkSNS+,以专业易用的技术源码输出,驱动互联网社交软件建设及创业,使用ThinkSNS改 ...
- 学霸系统UI项目功能说明书 v1.0版本
发布人员:软件工程实践小队. 发布内容:学霸系统UI项目说明书. 版本:学霸v1.0版本. 学霸系统UI项目说明书 v1.0版本分为以下部分: Part 1:用户须知: Part 2:功能实现: Pa ...
- Apache Flink 1.9.0版本新功能介绍
摘要:Apache Flink是一个面向分布式数据流处理和批量数据处理的开源计算平台,它能够基于同一个Flink运行时,提供支持流处理和批处理两种类型应用的功能.目前,Apache Flink 1.9 ...
- 体育类1.2.0版本 带有社交性质的 app 并且有内购功能
上架经历 体育类1.2.0版本 应用是体育类的,带有社交性质的 app 并且有内购功能 - 关于内购 最初级的应该是内购的 产品类型 在开发者一开始设置的时候没有注意到区别: 消耗型产品 非消耗型 非 ...
随机推荐
- RocketMQ(4) 消息的消费
消费者从Broker中获取消息的方式有两种:pull拉取方式和push推动方式.消费者组对于消息消费的模 式又分为两种:集群消费Clustering和广播消费Broadcasting. 1. 获取消息 ...
- SpringCloud Sentinel使用
1. 简介 Sentinel 是面向分布式服务架构的流量控制组件,主要以流量为切入点,从限流.流量整形.熔断降级.系统负载保护.热点防护等多个维度来帮助开发者保障微服务的稳定性.替换原先Hystrix ...
- kafka 工作流程及文件存储机制
1.kafka的数据存储 文件存储格式: .log 和 .index Kafka 中消息是以 topic 进行分类的, 生产者生产消息,消费者消费消息,都是面向 topic的. topic ...
- Codeforces Round 926 (Div. 2)(A~D)
目录 A B C D A 输出最大值减最小值,或者排序算一下答案 #include <bits/stdc++.h> #define int long long #define rep(i, ...
- Python 潮流周刊第 41 期(摘要),赠书5本
本周刊由 Python猫 出品,精心筛选国内外的 250+ 信息源,为你挑选最值得分享的文章.教程.开源项目.软件工具.播客和视频.热门话题等内容.愿景:帮助所有读者精进 Python 技术,并增长职 ...
- viewui tree 自定义化(源码copy出来改动)#添加 获取selected 解决方案
需求: 对树有title的点击效果,右侧有说明文字 和 按钮能点击,不能右键,系统用的壳已经有右键了. 出现的问题: viewui的tree有两年没更新了,对ui这块,是采取的render自定义,但是 ...
- electron 下网页获取 micphone 权限
网页获取麦克风或摄像头权限我们只需调用 navigator.mediaDevices.getUserMedia 方法就可唤起浏览器用户授权 const useMicphone = async () = ...
- netty Recycler对象池
前言 池化思想在实际开发中有很多应用,指的是针对一些创建成本高,创建频繁的对象,用完不弃,将其缓存在对象池子里,下次使用时优先从池子里获取,如果获取到则可以直接使用,以此降低创建对象的开销. 我们最熟 ...
- PAT 甲级【1012 The Best Rank】
本题用java极容易超时,提交了好几次才成功 另外90 88 77 77 50,名次应该是1 2 3 3 5 ,不是1 2 3 3 4 import java.io.*; public class M ...
- 大年学习linux(第六节---软件安装)
六.软件安装 rpm RPM软件包的管理工具 补充说明 rpm命令 是RPM软件包的管理工具.rpm原本是Red Hat Linux发行版专门用来管理Linux各项套件的程序,由于它遵循GPL规则且功 ...