更新时间:2026-07-28 GMT+08:00
分享

技术原理

核心机制

  • 进程间通信

    内核与CM交互链路不应受制于网络问题、高负载问题,采用进程间通信方式交互,具体使用了Unix domain socket(后简称UDS)实现。

    分析CM探活的场景,需考虑以下几点:

    • 指标时效:CM探活指标获取频率较高,部分指标采集周期为1次/s,采用共享内存具有滞后性,且需要额外考虑对指标时效性的判断;使用UDS的实时性较高,较符合该场景。
    • 参数可变:原CM探活是通过网络建连后执行SQL的方式,CM会动态的通过参数拼接SQL,内核侧无法提前预判入参并采集。在这种场景下,CM需将查询指令置于共享内存,内核读取后再执行指标查询操作,最终转化为更大的时效问题。

    综合考虑采用UDS方式实现CM和内核的交互。

  • 应急通道资源预留

    内核应急通道预留资源,以在极端负载场景下仍能提供探活能力,且在执行探活指标获取/运维的过程中,尽可能少地依赖I/O。

    • 预留CPU资源:绑定HA_BACKEND cgroup组;
    • 预留内存资源:分析应急通道线程所使用的内存较少,但优先级极高,因此内存上下文用量不设上限,通过应急通道线程查询视图或执行运维操作前执行内存上下文切换。
  • 内核、应急通道线程与CM(gsql)交互主流程
    • CM、内核完成UDS的初始化。
    • CM与内核建立长连接。
    • CM内线程按需、定期向内核发送报文以查询指标或进行仲裁后的运维指令下发。
    • 内核解析报文,反序列化参数,根据指令执行查询/运维操作。对于运维操作,根据具体命令逻辑确定是同步/异步接口,对于指标查询均为同步接口。内核获取结果集后进行序列化、报文封装及报文发送。特别地,内核在获取CM所需信息时,确保只加SpinLock和极少数必要的哈希表相关锁。

    考虑该长连接可能由于异常原因断开或阻塞,为保证探活链路通畅需有如下机制:

    • 内核探活线程需有保活机制,当异常退出后应及时重拉。
    • CM与内核的链路若异常断开,CM需进行一定次数的建连尝试,若无法成功建连,则结合原网络建连探活的结果仲裁节点状态。
    • CM与内核间的通信应设置超时与重试机制,当请求达到一定重试次数仍未返回结果时,则结合原网络建连探活的结果仲裁节点状态。
  • 探活机制

    CM通过网络链路探活的原核心流程为建连后发送“SELECT 1”,高负载下通过网络链路探活失败时,会通过应急通道探活作为代替。因此内核新增一个探活指令,其具体实现为:通过wlm_monitor线程异步执行SELECT 1操作并记录结果,覆盖除建连外的SQL执行过程链路的检测,应急通道线程对结果进行获取并反馈给CM。

  • 简易运维命令

    gsql提供简易运维元命令,其原理是gsql客户端执行简易命令时,将简易运维命令翻译为指定的sql后发送给服务端。

接口介绍

  • GUC参数
    Unix Domain Socket运维通道主要使用以下GUC参数,具体描述请参见《参考》中“数据库运行参数说明 > GUC参数说明 > 负载管理”章节。
    表1 GUC参数

    参数名

    参数说明

    enable_emergency_access

    设置是否开启Unix Domain Socket 运维通道。

  • 应急通道的运维命令

    gsql工具提供-O选项执行应急通道的运维命令,具体示例参见操作指导。gsql的使用请参见《参考》中“工具参考 > 数据库连接工具 > gsql连接数据库 > gsql使用指导”章节。

    表2 gsql支持的Unix Domain Socket运维通道的运维命令

    参数

    参数说明

    取值范围

    -O, --emergency-command=EMERGENCYCOMMAND

    Unix Domain Socket运维通道的运维命令。

    在极端情况下,gsql工具无法与GaussDB建立连接时,可以使用该命令进行应急运维。此命令通过Unix Domain Socket运维通道与GaussDB通信,实现一键运维功能。

    -O选项的参数格式具体如下:

    "{port} {command} [{param} [...]]"

    {port}:数据库监听端口。

    {command}:具体运维命令。

    {param}:该运维命令的参数,可能有0个或多个。

    说明:
    • 使用此选项时,gsql工具必须与GaussDB进程位于同一台服务器上。
    • 如果运维命令的参数包含空格,请在参数两边加上引号。
    • "{port} mem_log":记载全局的内存概况与全局级内存上下文、线程级内存上下文、session级内存上下文的top20内存上下文占用详情。该功能仅在GUC参数use_workload_manager开启时有效,范围同内存过载记录mem_log特性。无参数。示例:
      -O "19995 mem_log"
    • "{port} kill_wait_event {wait_event}":查杀指定等待事件会话。参数{wait_event}表示具体的锁、轻量级锁以及I/O的信息等。示例:
      -O "19995 kill_wait_event relation"
    • "{port} kill_business_sql":查杀非rdsAdmin用户的全部业务SQL语句。无参数。示例:
      -O "19995 kill_business_sql"
    • "{port} kill_slow_sql {username}":批量查杀非默认数据库下,指定用户的状态为非idle的执行超过1分钟的SQL语句。参数{username}表示用户名。示例:
      -O "19995 kill_slow_sql omm"
    • "{port} kill_slow_sql {username} {database}":批量查杀指定用户在指定数据库中的执行超过1分钟的SQL语句。参数{username}表示用户名,{database}表示数据库名。示例:
      -O "19995 kill_slow_sql omm db1"
    • "{port} kill_executing_sql {username}":查杀非默认数据库下,指定用户的状态为active的正在执行的SQL语句。参数{username}表示用户名。示例:
      -O "19995 kill_executing_sql omm"
    • "{port} kill_mem_topn {top n}":查杀内存占用top n的SQL语句。参数{top n}表示指定的top n。示例:
      -O "19995 kill_mem_topn 10"
    • "{port} kill_cpu_topn {top n}":查杀CPU TIME占用top n的SQL语句。参数{top n}表示指定的top n。示例:
      -O "19995 kill_cpu_topn 10"
  • gsql的简易运维元命令

    gsql使用简易运维元命令使用示例参见操作指导,gsql的元命令使用请参见《参考》中“工具参考 > 数据库连接工具 > gsql连接数据库 > 元命令参考”章节。

    表3 常用简易运维元命令

    简易运维命令

    参数解释

    实际执行的SQL

    \view stmt_track {unique_sql_id}

    stmt_track:记录指定SQL的L2级别的FULLSQL信息。

    unique_sql_id:需要记录的SQL的unique_sql_id。

    SELECT * FROM pg_catalog.dynamic_func_control('LOCAL', 'STMT', 'TRACK', '{"{unique_sql_id}", "L2"}');

    \view stmt_untrack {unique_sql_id}

    stmt_untrack:取消记录指定SQL的L2级别的FULLSQL信息。

    unique_sql_id:需要取消记录的SQL的unique_sql_id。

    SELECT * FROM pg_catalog.dynamic_func_control('LOCAL', 'STMT', 'UNTRACK', '{"{unique_sql_id}"}');

    \view stmt_list

    stmt_list:查询记录列表。

    SELECT * FROM pg_catalog.dynamic_func_control('LOCAL', 'STMT', 'LIST', '{}');

    \view stmt_clean

    stmt_clean:清理记录列表。

    SELECT * FROM pg_catalog.dynamic_func_control('LOCAL', 'STMT', 'CLEAN', '{}');

    \view explain_and_stack {pid}

    explain_and_stack:查询指定会话的运行时计划及堆栈。

    pid:指定会话的pid。

    SELECT pg_catalog.gs_get_explain(pid), pg_catalog.gs_stack(pid) FROM pg_catalog.pg_stat_activity WHERE pid = {pid};

    \view slow_sql {top_n}

    slow_sql:查询实时慢SQL情况。

    top_n:查询的行数。

    SELECT pid, sessionid, pg_catalog.SUBSTRING(query, 0, 100), state, usename, pg_catalog.NOW() - query_start AS elp FROM pg_catalog.pg_stat_activity WHERE state != 'idle' AND usename NOT IN ('rdsAdmin', 'rdsMetric', 'rdsBackup', 'rdsRepl', 'dbmind_monitor_agent', 'dbmind_monitor') ORDER BY elp DESC LIMIT {top_n};

    \view slow_trans {top_n}

    slow_trans:查询实时长事务情况。

    top_n:查询的行数。

    SELECT pid, sessionid, pg_catalog.SUBSTRING(query, 0, 100), state, usename, pg_catalog.NOW() - xact_start AS elp FROM pg_catalog.pg_stat_activity WHERE state != 'idle' AND usename NOT IN ('rdsAdmin', 'rdsMetric', 'rdsBackup', 'rdsRepl', 'dbmind_monitor_agent', 'dbmind_monitor') ORDER BY elp DESC LIMIT {top_n};

    \view wait_event

    wait_event(不带参数):查询当前语句和等待事件。

    SELECT a.pid, a.sessionid, a.datname, a.usename, a.client_addr, a.xact_start, a.query_start, (pg_catalog.NOW() - a.query_start)::text "query_runtime", w.wait_status, w.wait_event, w.locktag, w.lockmode, w.block_sessionid, a.query FROM pg_catalog.pg_stat_activity a JOIN pg_catalog.pg_thread_wait_status w ON a.sessionid = w.sessionid WHERE a.pid <> pg_catalog.pg_backend_pid() AND a.state = 'active' AND a.client_addr IS NOT NULL ORDER BY query_runtime DESC;

    \view wait_event {unique_sql_id} {start_time} {end_time}

    wait_event(带有三个参数):查询指定慢SQL的历史等待事件。

    unique_sql_id:需要查询的慢SQL的unique_sql_id。

    start_time:开始时间。如'2025-01-01 00:00'。

    end_time:结束时间。如'2025-01-01 00:00'。

    SELECT *, pg_catalog.statement_detail_decode(details, 'plaintext', true) FROM dbe_perf.statement_history WHERE unique_query_id = {unique_sql_id} AND start_time > {start_time} AND start_time < {end_time} ORDER BY db_time DESC;

    \view thr_wait_event

    thr_wait_event(不带参数):查询实时整体等待事件。

    SELECT wait_status, wait_event, pg_catalog.COUNT(*) FROM pg_catalog.pg_thread_wait_status GROUP BY 1, 2 ORDER BY 3 DESC;

    \view thr_wait_event {sessionid}

    thr_wait_event(带有一个参数):查询指定语句的等待事件。

    sessionid:指定的sessionid。

    SELECT * FROM pg_catalog.pg_thread_wait_status WHERE sessionid = {sessionid};

    \view gs_asp {start_time} {end_time}

    gs_asp:查询历史指定时间段整体等待事件。

    start_time:开始时间。如'2025-01-01 00:00'。

    end_time:结束时间。如'2025-12-31 23:59'。

    SELECT wait_status, event, pg_catalog.COUNT(*) FROM pg_catalog.gs_asp WHERE sample_time BETWEEN {start_time} AND {end_time} GROUP BY 1, 2 ORDER BY 3 DESC;

    \view pg_stats {table_name} {att_name}

    pg_stats:查询指定表的统计信息分布。

    table_name:表名。

    att_name:列名。

    SELECT * FROM pg_catalog.pg_stats WHERE tablename = '{table_name}' AND attname = '{att_name}';

    \view autovac {table_name}

    autovac:查询统计信息更新阈值。

    table_name:表名。

    SELECT * FROM pg_catalog.pg_autovac_status('{table_name}'::regclass);

    \view thr_pool

    thr_pool:查询线程池使用情况。

    SELECT node_name, worker_info FROM dbe_perf.global_threadpool_status;

    \view failed_proc {proc_name}

    failed_proc:查询失效的视图或存储过程。

    proc_name:失效的函数。

    SELECT re.ev_class, cl.relname FROM pg_catalog.pg_rewrite re, pg_catalog.pg_class cl WHERE re.ev_action LIKE '%{proc_name}%' AND cl.oid = re.ev_class;

    \view failed_proc_pkg

    failed_proc_pkg:查询失效存储过程对应的package。

    SELECT DISTINCT object_type, pg_catalog.pg_get_userbyid(creator) AS owner, CASE object_type WHEN 'P' THEN ( SELECT DISTINCT pg_catalog.UPPER(pkgname) FROM pg_catalog.gs_package WHERE oid = ( SELECT propackageid FROM pg_catalog.pg_proc WHERE oid = object_oid ) ) WHEN 'B' THEN ( SELECT DISTINCT pg_catalog.UPPER(pkgname) FROM pg_catalog.gs_package WHERE oid = object_oid ) WHEN 'S' THEN ( SELECT DISTINCT pg_catalog.UPPER(pkgname) FROM pg_catalog.gs_package WHERE oid = object_oid ) END package_name FROM pg_catalog.pg_object WHERE valid = 'f' AND object_type IN ('P', 'B', 'S');

    \view failed_index

    failed_index:查询不可用的索引。

    SELECT a.schemaname, a.relname, a.indexrelname, b.indisusable FROM pg_catalog.pg_stat_user_indexes a, pg_catalog.pg_index b WHERE a.indexrelid = b.indexrelid AND b.indisusable = 'f';

    \view table_size

    table_size:查询当前库下所有表的大小,按降序输出。

    SELECT schemaname, relname, pg_catalog.pg_total_relation_size(pg_catalog.CONCAT(schemaname, '.', relname)) / 1024 / 1024 / 1024 "GB" FROM pg_catalog.pg_stat_user_tables ORDER BY 3 DESC;

    \view dead_tup {top_n}

    dead_tup:查询死元组的数量。

    top_n:查询的行数。

    SELECT relname, n_live_tup, n_dead_tup, (n_dead_tup / (n_live_tup + 1)) AS rating, last_vacuum, last_autovacuum, last_analyze, last_autoanalyze FROM pg_catalog.pg_stat_user_tables ORDER BY rating DESC, n_dead_tup DESC LIMIT {top_n};

    \view table_size {table_name}

    table_size:查询指定表的大小。

    table_name:表名。

    SELECT * FROM pg_catalog.pg_size_pretty(pg_catalog.pg_total_relation_size('{table_name}'::regclass));

    \view login {start_time} {end_time} {ip} {port}

    login:查询指定IP和端口的登录即退出信息。

    start_time:开始时间。如'2024-01-01 00:00:00'。

    end_time:结束时间。如'2025-12-31 23:59:59'。

    ip:IP地址。

    port:端口。

    SELECT *, pg_catalog.SUBSTRING( client_conninfo::varchar, pg_catalog.POSITION(client_conninfo::varchar, '@'::varchar) + 1, 15 ) AS ip FROM pg_catalog.pg_query_audit({start_time}, {end_time}) WHERE ip = '{ip}' AND remote_port = '{port}';

    \view mem

    mem:查询当前内存使用信息

    SELECT * FROM pg_catalog.pg_total_memory_detail;

    \view thr_mem {top_n}

    thr_mem(带有一个参数):查询数据库所有线程的内存上下文使用情况。

    top_n:查询的行数。

    SELECT contextname, pg_catalog.SUM(totalsize) / 1024 / 1024 "totalsize", pg_catalog.SUM(freesize) / 1024 / 1024 "freesize", pg_catalog.COUNT(*) "sum" FROM pg_catalog.gs_thread_memory_context GROUP BY contextname ORDER BY sum DESC LIMIT {top_n};

    \view thr_mem {context_name} {top_n}

    thr_mem(带有两个参数):查询使用内存最多的线程的线程id。

    context_name:内存上下文的名称。

    top_n:查询的行数。

    SELECT * FROM pg_catalog.pv_thread_memory_detail() WHERE contextname = '{context_name}' ORDER BY totalsize DESC LIMIT {top_n};

    \view sess_mem {top_n}

    sess_mem:查询数据库所有session的内存上下文使用情况。

    top_n:查询的行数。

    SELECT contextname, pg_catalog.SUM(totalsize) / 1024 / 1024 "totalsize", pg_catalog.SUM(freesize) / 1024 / 1024 "freesize", pg_catalog.COUNT(*) "sum" FROM pg_catalog.gs_session_memory_context GROUP BY contextname ORDER BY sum DESC LIMIT {top_n};

    \view thr_mem_detail {tid} {context_name}

    thr_mem_detail:查询指定线程的内存使用情况。

    tid:线程id。

    context_name:内存上下文的名称。

    SELECT * FROM pg_catalog.gs_get_thread_memctx_detail({tid}, '{context_name}');

    \view sess_mem_tp {context_name}

    sess_mem_tp:查询指定内存上下文的内存使用情况。

    context_name:内存上下文的名称。

    SELECT * FROM pg_catalog.gs_get_session_memctx_detail('{context_name}');

    \view shared_mem {top_n}

    shared_mem:查询数据库全局共享内存上下文的使用情况。

    top_n:查询的行数。

    SELECT contextname, pg_catalog.SUM(totalsize) / 1024 / 1024 "totalsize MB", pg_catalog.SUM(freesize) / 1024 / 1024 "freesize MB", pg_catalog.COUNT(*) "sum" FROM pg_catalog.gs_shared_memory_detail GROUP BY contextname ORDER BY sum DESC LIMIT {top_n};

    \view sess_mem_detail {top_n}

    sess_mem_detail:查询session级内存上下文的使用情况。

    top_n:查询的行数。

    SELECT contextname, pg_catalog.SUM(totalsize) / 1024 / 1024 "totalsize MB", pg_catalog.COUNT(1) "count" FROM pg_catalog.pv_session_memory_detail() GROUP BY contextname ORDER BY 2 DESC LIMIT {top_n};

    \view sess_mem_detail_tp {top_n}

    sess_mem_detail_tp:查询session级内存上下文的使用情况(仅在线程池模式开启时生效)。

    top_n:查询的行数。

    SELECT sessid, pg_catalog.SUM(totalsize) / 1024 / 1024 "totalsize MB", pg_catalog.COUNT(1) "count" FROM pg_catalog.gs_session_memory_context GROUP BY sessid ORDER BY 2 DESC LIMIT {top_n};

    \view thr_mem_pv {top_n}

    thr_mem_pv:查询线程级内存上下文的使用情况。

    top_n:查询的行数。

    SELECT contextname, pg_catalog.SUM(totalsize) / 1024 / 1024 "totalsize", pg_catalog.SUM(freesize) / 1024 / 1024 "freesize", pg_catalog.COUNT(1) "count" FROM pg_catalog.pv_thread_memory_detail() GROUP BY 1 ORDER BY 2 DESC LIMIT {top_n};

    \view total_mem {top_n}

    total_mem:查询当前数据库节点的内存使用情况。

    top_n:查询的行数。

    SELECT * FROM pg_catalog.gs_total_memory_detail LIMIT {top_n};

    \view avg_cpu {top_n}

    avg_cpu:查询SQL语句的平均CPU时间,按降序输出。

    top_n:查询的行数。

    SELECT unique_sql_id, cpu_time / (n_calls) "average_cpu_time" FROM dbe_perf.statement WHERE n_calls != 0 ORDER BY 2 DESC LIMIT {top_n};

    \om create_abort_sql_patch {patch_name} {unique_sql_id}

    create_abort_sql_patch:创建避险SQL PATCH。

    patch_name:SQL PATCH名。

    unique_sql_id:指定SQL的unique_sql_id。

    SELECT * FROM dbe_sql_util.create_abort_sql_patch('{patch_name}', {unique_sql_id});

    \om kill_sess_thr {username} {database} {context_name}

    kill_sess_thr:根据线程内存占用,查杀内存占用高的SQL语句。

    username:用户名。

    database:数据库名。

    context_name:内存上下文的名称。

    SELECT pg_catalog.pg_terminate_session(pid, sessionid), pid, sessionid FROM pg_catalog.pg_stat_activity WHERE usename = '{username}' AND datname != 'postgres' AND datname = '{database}' AND pid IN ( SELECT tid FROM pg_catalog.gs_thread_memory_context WHERE contextname = '{context_name}' ) AND state = 'idle';

    \om kill_sess_sess {username} {database} {context_name}

    kill_sess_sess:根据session内存占用,查杀内存占用高的SQL语句。

    username:用户名。

    database:数据库名。

    context_name:内存上下文的名称。

    SELECT pg_catalog.pg_terminate_session(pid, sessionid), pid, sessionid FROM pg_catalog.pg_stat_activity WHERE usename = '{username}' AND datname != 'postgres' AND datname = '{database}' AND pid IN ( SELECT threadid FROM pg_catalog.gs_session_memory_context WHERE contextname = '{context_name}' );

  • 应急通道视图 DBE_PERF.EMERGENCY_OPERATION_RECORDS

    该视图用于查看各CN/DN节点对Unix Domain Socket运维通道的使用情况

    表4 DBE_PERF.EMERGENCY_OPERATION_RECORDS字段

    参数

    类型

    描述

    record_time

    timestamptz

    使用运维通道的时间。

    action

    text

    使用运维通道执行的操作。

    source

    text

    接入运维通道的来源,取值为gsql和cm。

    detail

    text

    执行操作的具体结果。

相关文档