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 并且有内购功能 - 关于内购 最初级的应该是内购的 产品类型 在开发者一开始设置的时候没有注意到区别: 消耗型产品 非消耗型 非 ...
随机推荐
- [Azure Developer]把Azure Function中ILogger对象静态化为静态方法提供日志记录
问题描述 在Azure Function代码中,有默认的ILogger对象来记录函数的日志,如果函数引用了一些静态对象,是否有办法使用这个默认的ILogger对象来记录日志呢? using Syste ...
- Rabbit使用CorrelationId进行可靠性消息回调
先放一张使用CorrelationId相关ID进行消息回调处理的流程图 客户端启动时,它将创建一个匿名回调队列 对于 RPC 请求,客户端发送一条消息,该消息具有两个属性: reply_to(设置为回 ...
- 关于mv命令,系统是如何区分是移动还是重命名
引入: 精简回答版:重命名的本质仍是移动覆盖 ,所以不存在应该如何区分的问题 最近学习到linux基础命令中的mv命令,了解到mv命令的作用是对文件的移动和重命名,但自己一直想不明白系统是如何分辨 ...
- Python实现snap:对齐多张遥感影像的空间范围
本文介绍基于Python中ArcPy模块,实现基于栅格图像批量裁剪栅格图像,同时对齐各个栅格图像的空间范围,统一其各自行数与列数的方法. 首先明确一下我们的需求.现有某一地区的多张栅格遥感影像 ...
- 50条MAUI踩坑记
1. 目录结构: (1)_imports.razor是一个全局using namespace的地方 (2)Platforms下的代码,虽然都放在同一个项目下,但是Platforms\Android下的 ...
- Zabbix与乐维监控对比分析(三)——对象管理篇
大家好,我是乐乐.今天就不更新zabbix6.0的使用教程了.在前面的文章中,我们详细介绍了Zabbix与乐维监控在架构.性能.Agent管理.自动发现.权限管理等方面的对比分析,本篇是Zabbix对 ...
- linux 服务器 执行命令挂起 nohup 改用 pm2
nohup http-server -p 80 & nohup完要 exit 退出,不能直接关! nohup完要 exit 退出,不能直接关! nohup完要 exit 退出,不能直接关! 重 ...
- C# NAudio 播放多个MP3文件
C# 使用 NAudio 来播放多个MP3文件.上代码 1.引入NAudio:using NAudio.Wave; 2.定义变量: private WaveOutEvent outputDevice; ...
- oracle用户密码有@符号连接方法
oracle用户密码不小心设置了带有"@"符号,正常登陆总是无法登陆,提示无法解析的连接字符串错误,其实解决办法很简单,转义即可,示例如下: exp system/\"x ...
- App启动页面优化
目录介绍 01.存在白屏问题 1.1 问题描述 1.2 问题分析 02.解决白屏的办法 2.1 解决方案分析 2.2 第一种解决方案 2.3 第二种解决方案 2.4 注意要点 03.Applicati ...