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功能解密的更多相关文章

  1. Dash 2.9.0版本重磅新功能一览

    本文示例代码已上传至我的Github仓库https://github.com/CNFeffery/dash-master 大家好我是费老师,就在昨晚,Dash框架发布了其2.9.0版本更新,在一众更新 ...

  2. ICG_System之全自动代码生成器V2.0版本

    大家好! 早在2014年本人就已经利用业余时间开发自己的ICG之代码生成器系统.依靠bootstrap的崛起本人也在不断完善此应用.目的是为了减少开发人员的工作量. 减少不必要的复制粘贴操作,该系统已 ...

  3. 意料之外,情理之中,Spring.NET 3.0 版本发布-

    意料之外,情理之中,Spring.NET 3.0 版本发布- 备受社区和企业开发者广泛关注的Spring.NET在上周发布了3.0版本,并且目前已经保持着持续的更新,让我们一起来看一看他究竟发布了哪些 ...

  4. 百度echarts 3.0版本和2.0版本的兼容问题

    前一段时间,项目中要用到统计图表,之前也用过jqplot的图表插件,这次开发的内容中基于地图的展示还很多,所以后来选择了百度的echarts插件(echarts.baidu.com).刚开始用的时候, ...

  5. nlog 2.0 强制转换使用 4.0 版本

    今天下午研发代码,发现调用其他小组研发的代码,发现其中有使用nlog功能,但nlog版本是2.0 ,而我的项目使用4.0 版本 导致部分功能不能使用,故在web配置文件中加入以下代码即可 <de ...

  6. 帝国CMS 6.0功能解密之新版结合项功能,帝国结合项使用

    可以用来做A-Z信息检索    某字段等于多少,输出  等等 帝国CMS6.0在继承以往版本结合项功能的基础上又新增很多特性,更强大.今天我们就专门来讲解6.0的结合项改进. 回顾下以往版本的结合项语 ...

  7. 开源社交系统ThinkSNS+ V0.8.0 正式发布(一期功能版本)

    智士软件旗下开源sns社交系统ThinkSNS即将进入10周年,推出并行两代系统ThinkSNSV4和ThinkSNS+,以专业易用的技术源码输出,驱动互联网社交软件建设及创业,使用ThinkSNS改 ...

  8. 学霸系统UI项目功能说明书 v1.0版本

    发布人员:软件工程实践小队. 发布内容:学霸系统UI项目说明书. 版本:学霸v1.0版本. 学霸系统UI项目说明书 v1.0版本分为以下部分: Part 1:用户须知: Part 2:功能实现: Pa ...

  9. Apache Flink 1.9.0版本新功能介绍

    摘要:Apache Flink是一个面向分布式数据流处理和批量数据处理的开源计算平台,它能够基于同一个Flink运行时,提供支持流处理和批处理两种类型应用的功能.目前,Apache Flink 1.9 ...

  10. 体育类1.2.0版本 带有社交性质的 app 并且有内购功能

    上架经历 体育类1.2.0版本 应用是体育类的,带有社交性质的 app 并且有内购功能 - 关于内购 最初级的应该是内购的 产品类型 在开发者一开始设置的时候没有注意到区别: 消耗型产品 非消耗型 非 ...

随机推荐

  1. RocketMQ(4) 消息的消费

    消费者从Broker中获取消息的方式有两种:pull拉取方式和push推动方式.消费者组对于消息消费的模 式又分为两种:集群消费Clustering和广播消费Broadcasting. 1. 获取消息 ...

  2. SpringCloud Sentinel使用

    1. 简介 Sentinel 是面向分布式服务架构的流量控制组件,主要以流量为切入点,从限流.流量整形.熔断降级.系统负载保护.热点防护等多个维度来帮助开发者保障微服务的稳定性.替换原先Hystrix ...

  3. kafka 工作流程及文件存储机制

    1.kafka的数据存储      文件存储格式: .log 和 .index Kafka 中消息是以 topic 进行分类的, 生产者生产消息,消费者消费消息,都是面向 topic的. topic ...

  4. Codeforces Round 926 (Div. 2)(A~D)

    目录 A B C D A 输出最大值减最小值,或者排序算一下答案 #include <bits/stdc++.h> #define int long long #define rep(i, ...

  5. Python 潮流周刊第 41 期(摘要),赠书5本

    本周刊由 Python猫 出品,精心筛选国内外的 250+ 信息源,为你挑选最值得分享的文章.教程.开源项目.软件工具.播客和视频.热门话题等内容.愿景:帮助所有读者精进 Python 技术,并增长职 ...

  6. viewui tree 自定义化(源码copy出来改动)#添加 获取selected 解决方案

    需求: 对树有title的点击效果,右侧有说明文字 和 按钮能点击,不能右键,系统用的壳已经有右键了. 出现的问题: viewui的tree有两年没更新了,对ui这块,是采取的render自定义,但是 ...

  7. electron 下网页获取 micphone 权限

    网页获取麦克风或摄像头权限我们只需调用 navigator.mediaDevices.getUserMedia 方法就可唤起浏览器用户授权 const useMicphone = async () = ...

  8. netty Recycler对象池

    前言 池化思想在实际开发中有很多应用,指的是针对一些创建成本高,创建频繁的对象,用完不弃,将其缓存在对象池子里,下次使用时优先从池子里获取,如果获取到则可以直接使用,以此降低创建对象的开销. 我们最熟 ...

  9. 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 ...

  10. 大年学习linux(第六节---软件安装)

    六.软件安装 rpm RPM软件包的管理工具 补充说明 rpm命令 是RPM软件包的管理工具.rpm原本是Red Hat Linux发行版专门用来管理Linux各项套件的程序,由于它遵循GPL规则且功 ...