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. 【Azure Redis 缓存 Azure Cache For Redis】Azure Redis删除 TLS 1.0 和 1.1的计划及问题

    问题描述 Azure Redis 正式关闭TLS1.0和1.1关闭的时间 根据文档描述Azure Redis阶段2我们将停止支持 TLS 1.1 和 TLS 1.0,暂时计划 2020 年 12 月 ...

  2. 【Azure Redis 缓存】Azure Cache for Redis 服务的导出RDB文件无法在自建的Redis服务中导入

    问题描述 使用微软云的Redis服务,导出它的RDB文件后,想把数据恢复到本地自建的Redis服务中,发现出现如下错误: 15000:S 21 Jun 08:14:11.199 * Retrying ...

  3. 【Azure Fabric Service】怎样关闭 Azure Service Fabric?

    问题描述 怎样关闭Azure Service Fabric服务呢?在Azure门户上没有找到 Stop 按钮. 问题回答 Azure Service Fabric 默认是无法停止的,可以删除. 虽然可 ...

  4. SpringMVC快速复习(超详细)

    目录 一.SpringMVC简介 1.什么是MVC 2.什么是SpringMVC 3.SpringMVC的特点 二.HelloWorld 1.开发环境 2.创建maven工程 a>添加web模块 ...

  5. HiSi 3516CV500 NNIE(Neural Network Inference Engine) 摸鱼记录(1) --- 环境搭建

    PS:要转载请注明出处,本人版权所有. PS: 这个只是基于<我自己>的理解, 如果和你的原则及想法相冲突,请谅解,勿喷. 前置说明   本文作为本人csdn blog的主站的备份.(Bl ...

  6. HMAC算法:数据传输的保护神

    HMAC算法起源: HMAC(Hash-based Message Authentication Code)算法是由Mihir Bellare.Ran Canetti和Hugo Krawczyk于19 ...

  7. 常用命令---less---more

    常用命令---less---more 常用选项 less 和 more 都是 Linux 和类 Unix 系统中的文本阅读工具,主要用于分页查看文件内容.虽然两者都能让用户逐屏查看大文件,但 less ...

  8. Oracle与MySQL的差异和对比

    Oracle与MySQL的差异和对比:配套hands-on参考脚本. 方便客户针对培训课件内容进行动手实践,加强理解. --------------------------------- -- 主题: ...

  9. 并发CPU伪共享及优化

    伪共享 缓存系统中是以缓存行(cache line)为单位存储的.缓存行是2的整数幂个连续字节,一般为32-256个字节.最常见的缓存行大小是64个字节.当多线程修改互相独立的变量时,如果这些变量共享 ...

  10. 【Pavia】遥感图像数据集下载地址和读取数据集代码

    [Pavia]遥感图像数据集下载地址和读取数据集代码 目录 [Pavia]遥感图像数据集下载地址和读取数据集代码 前言 Pavia数据集 Pavia数据集地址: Pavia数据集预览 PaviaU.m ...