• [运维管理] GaussDB 运维案例集
    目  录1 DN动态内存使用满导致DN主备切换2 iptables策略限制导致实例升级报错3 修改bashrc导致om-agent升级失败4 目录权限问题导致DN异常5 2025-115.1 业务SQL包含自定义function,通过hint方式添加query_dop,smp不生效5.2 JDBC导入和gsql导入在insert,replace,duplicate方式性能差异5.3 主备切换时间长问题分析5.4 主机流控导致大量业务超时并且无法新建连接5.5 业务分布键选择不合理导致数据分布不均匀5.6 DN发生主备切换问题定位 1、DN动态内存使用满导致DN主备切换故障现象客户反馈,在05:00--10:31之间GaussDB集中式在DN主备切换。适用版本GaussDB全部版本。告警DN主备切换。业务影响业务闪断,1min内恢复。故障原因l   主备切换问题,通常先找到主备切换的节点,即原主DN,新主DN分别是哪个DN。l   然后先从cm_server主、cm_ctl等日志分析,确认主备切换的命令是由cm_server下发还是手动下发。l   最后如果是cm_server下发主备切换的命令,通常是原主DN异常,则分析原主DN 异常原因。处理办法                                步骤 1     确认DN主备切换时间点。查看cm_server主日志,搜索关键词“Failover message has sent to instance”,从日志中发现,2024-04-23 05:02:34,cm_server下发命令,将dn_6002切换为主DN。cd $GAUSSLOG/cm/cm_servervim cm_server-yyyy-mm-dd_******-current.log继续查看cm_server主日志,搜索关键词“send switchover to instance”,发现在2024-04-23 10:31:21,手工下发了switchover命令,将dn_6001切换为主。经以上分析,2024-04-23 05:02:34因为dn_6001的某些故障,cm_server将主DN切换为dn_6002,2024-04-23 10:31:21手动下发switchover命令将dn_6001切换为主。                                步骤 2     定位发生主备切换原因。查看DN进程,发现进程在05:02发生重启。ps ux|grep dn                                步骤 3     查看是否生成ffic日志。进入日志目录,发现存在ffic日志。cd $GAUSSLOG/ffic_log                                步骤 4     分析ffic日志。查看ffic_log日志,发现dn_6001因为发生oom,被AI Watchdog杀掉进程,从而触发主备切换。                                步骤 5     查看dn_6001日志。搜索关键词,AI Watchdog,发现是因为动态内存上涨,触发AI Watchdog主备切换。cd $GAUSSLOG/pg_log/dn_6001vim postgresql-yyyy-mm-dd_******.log                                步骤 6     查看动态内存使用情况。查看监控指标,动态内存使用率瞬间冲高。                                步骤 7     查看dn_6001动态内存上下文根。发现hashBatchContext上下文根动态内存使用高,判断可能为大的查询,其中的hash关联占用动态内存高。cd $GAUSSLOG/mem_log/dn_6001_6002_6003                                步骤 8     查找动态内存占用高的SQL语句。发现占用动态内存高的SQL语句为insert into语句,该语句存在大量的关联查询,在执行该语句时发生申请内存失败,报错信息为:memory is temporarily unavailable。cd $GAUSSLOG/pg_log/dn_6001zgrep -i debug_query_id postgresql-yyyy-mm-dd_******.log.zg | awk -F 'consuming about' '{print $2}'|sort -nk1                                步骤 9     优化insert into语句。----结束2、iptables策略限制导致实例升级报错故障现象客户进行实例升级,任务流报错,升级失败,如下图所示。适用版本GaussDB全部版本。业务影响l   管控任务流报错,无影响。l   内核任务流报错,自动回滚成功,无业务影响,运维功能、备份可能会受影响。l   内核任务流报错,自动回滚失败,集群状态可能异常,影响业务。故障原因根据报错任务流时间,147秒报错,说明升级任务流可能还没有下发内核,可能在om_agent前置校验阶段报错。处理方法                                步骤 1     根据升级报错任务流,找到命令下发节点。如下图,单击“操作 > 修改context”,找到“NODE_ID”。                                步骤 2     根据NODE_ID,找到对应节点,登录到节点后台。                                步骤 3     切换到Ruby用户,加载环境变量,执行如下命令,查看升级日志。ll $GAUSSLOG/om/gs_upgradectl_2025*.log                                步骤 4     发现节点上没有产生内核升级日志,说明升级动作还没有到内核侧,返回查看om_agent的日志。                                步骤 5     执行如下命令,查看om_agent的升级日志。vim /home/Ruby/log/om_agent/agent.log                                 步骤 6     搜索报错时间点前后有没有“ERROR、failed”等报错信息。                                步骤 7     根据报错日志分析,检查数据库连接失败:Check database connection failed。根据报错日志“could not connect to server: Operation now in progress Is the server running on host "127.0.0.1" and accepting TCP/IP connections on port 8000”分析,怀疑是gsql连接数据库报错。                                步骤 8     在数据库节点执行如上命令,指定-h 127.0.0.1不通,不指定可以连上,怀疑是127.0.0.1不通。l   指定-h 127.0.0.1l   不指定-h 127.0.0.1                                步骤 9     执行如下命令,测试127.0.0.1的连通性,连接失败。curl -kv 127.0.0.1 8000                             步骤 10     通过如下命令检查数据库连通性,是,指定-h 127.0.0.1。gsql -d postgres -p $port -h 127.0.0.1 -U rdsAdmin -W $password -m -c 'select 1;'                             步骤 11     127.0.0.1不通,怀疑是设置了iptable策略,root用户下执行如下命令查看iptable策略。iptables -L                              步骤 12     如上图,iptables策略存在一条策略限制了127.0.0.1访问。                             步骤 13     执行如下命令删除限制127.0.0.1的策略。iptables -D INPUT -p all -s 127.0.0.1/24  -j REJECT                              步骤 14     执行如下命令,测试127.0.0.1的连通性,连接成功。curl -kv 127.0.0.1 8000                             步骤 15     通过gsql连接,也可以连接成功。                             步骤 16     管控界面重试任务流,升级成功。----结束3、修改bashrc导致om-agent升级失败故障现象通过TPOPS平台,升级GaussDB实例,升级报错,查看升级任务流,升级子任务om-agent失败。适用版本GaussDB全部版本。业务影响升级失败。故障原因实例节点上,/home/Ruby/.bashrc 该文件为环境配置文件,该文件在实例安装成功后手动添加了 source ~/gauss_env_file 环境变量 ,导致升级om_agent时,自动加载了GAUSSHOME,使其获取到了GAUSSHOME/bin目录下的openssl,正常要求使用操作系统自带的openssl来生成客户端和服务端的证书和私钥。因为环境变量加载的的openssl路径不对,所以报错证书和私钥不匹配,无法正常启动om_agent进程,导致升级失败。处理办法                                步骤 1     查看om_agent日志,提示om_agent拉起失败。                                步骤 2     通过 ps -ux 查看 om_agent 进程是否拉起,未拉起,手动尝试拉起om_agent, 提示ssl证书相关错误。                                步骤 3     查看.bashrc 环境变量,发现手动添加了 source ~/gauss_env_file。                                步骤 4     登录实例每个节点,去掉 .bashrc 中手动添加的环境变量 source \~/gauss_env_file ,然后重做任务流。----结束4、目录权限问题导致DN异常故障现象复现案例:集群升级完后一个DN状态为down。cm_ctl query -Cv适用版本GaussDB全部版本。业务影响所有CN/DN权限异常,会导致数据库无法正常启动。故障原因升级过程中需要重启DN,DN数据目录由于权限问题无法正常启动。处理办法                                步骤 1     查看DN异常节点om_agent、cm_agent、cm_server等守护进程无异常。ps ux                                步骤 2     查看cm_agent进程日志打印有拉起动作但是未正常拉起,排除CMA异常。cd $GAUSSLOG/cm/cm_agent vim cm_agent-*current.log StartAndStop ASYN LOG: BuildStartCommand 0 StartAndStop ASYN LOG: DN START system(command:/usr/local/core/app/bin/gaussdb    -D /var/lib/engine/data1/data/dn_6002 -M pending >> "/var/lib/engine/data1/log/Ruby/cm/cm_agent/system_call-current.log" 2>&1 &), try 4 StartAndStop ASYN LOG: the dn(id:6002) instance restarts counts: 66 in 10 min, 66 in hour. DnStatus6002 ASYN ERROR: [get_connection: 1446]: fail to read pid file (/var/lib/engine/data1/data/dn_6002/postmaster.pid). DnStatus6002 ASYN ERROR: failed to connect to datanode:/var/lib/engine/data1/data/dn_6002 DnStatus6002 ASYN ERROR: DatanodeStatusCheck failed, ret=-1 DnStatus6002 ASYN LOG: set 6002 on offline. CheckProcess ASYN LOG: process (gaussdb) is not running, path is [[/var/lib/engine/data1/data/dn_6002]: [/var/lib/engine/data1/data/dn_6002]], haveFound is 0 CoreDumpCheck ASYN LOG: gaussdb state file "/var/lib/engine/data1/data/dn_6002/gaussdb.state" is not exist, could not get the build infomation: No such file or directory StartAndStop ASYN ERROR: error.dn is 6002 ret=-1 TpNetReportDnGroupInfoMain ASYN LOG: tp net dn report dn group [0] to cms. DnStatus6002 ASYN ERROR: [get_connection: 1446]: fail to read pid file (/var/lib/engine/data1/data/dn_6002/postmaster.pid). DnStatus6002 ASYN ERROR: failed to connect to datanode:/var/lib/engine/data1/data/dn_6002 DnStatus6002 ASYN ERROR: DatanodeStatusCheck failed, ret=-1 DnStatus6002 ASYN LOG: set 6002 on offline.                                步骤 3     查看system_call日志发现打印数据目录权限不足。cd $GAUSSLOG/cm/cm_agent vim system_call-current.log LOG:  assign g_instance_enable_dcf=0 LOG:  configuration file "/var/lib/engine/data1/data/dn_6002/gaussdb.conf" contains errors; unaffected changes were applied CAUSE:  Error from config file occurs and unaffected changes were applied. ACTION:  Use correct config file. FATAL:  data directory "/var/lib/engine/data1/data/dn_6002" has group or world access DETAIL:  Permissions should be u=rwx (0700). CAUSE:  The data directory has group or world access. ACTION:  Add the user to the group or world of the data directory.                                步骤 4     查看该DN数据目录权限为701异常。                                步骤 5     手动将DN数据目录恢复为700权限。                                步骤 6     集群状态恢复。----结束5、2025-115.1 业务SQL包含自定义function,通过hint方式添加query_dop,smp不生效问题现象业务sql执行时间较长,需要通过smp增加并行提升执行效率,通过hint 方式, 发现query_dop 不生效。以下是sql及对应执行计划、相关表表结构。执行计划select表结构insert表结构技术背景针对上述SQL案例,smp使用有如下约束条件,如下:1.         当function为易变函数,smp不生效, 需要将function调整为i函数。2.         当function不能下推到dn执行,smp不生效,需要将function修改为SHIPPABLE。3.         当业务表为分区表且创建了global索引,smp 不生效, 需要将业务表修改为local索引。function创建规则如下l   不主动指定 IMMUTABLE | STABLE , 默认创建 v 函数 | s 函数,即默认指定 VOLATILE | STABLE。l   不主动指定 SHIPPABLE,默认指定 NOT SHIPPABLE, 即该函数不下推到dn上执行。pg_proc 字段说明验证如下l   不主动指定 IMMUTABLE | STABLE , 默认创建 v 函数,即默认指定 VOLATILE。l   不主动指定 SHIPPABLE,默认指定 NOT SHIPPABLE, 即该函数不下推到dn上执行。gaussdb=> CREATE FUNCTION func1 RETURN integer gaussdb->     AS   gaussdb$>     BEGIN gaussdb$>         RETURN 2; gaussdb$>     END; gaussdb$>     / CREATE FUNCTION   --创建function , 默认是v 函数 gaussdb=> select proname, provolatile, proshippable  from pg_proc where proname = 'func1';  proname | provolatile | proshippable  ---------+-------------+--------------  func1   | v           | f验证案例1.         select 查询结果中使用到了v函数(易变 volatile),smp将不生效,需调整为i (不可变的 immutable) 函数或者s(稳定的 stable)函数。gaussdb=> CREATE FUNCTION func1 RETURN integer gaussdb->     AS   gaussdb$>     BEGIN gaussdb$>         RETURN 2; gaussdb$>     END; gaussdb$>     / CREATE FUNCTION   --创建function , 默认是v 函数 gaussdb=> select proname, provolatile, proshippable  from pg_proc where proname = 'func1';  proname | provolatile | proshippable  ---------+-------------+--------------  func1   | v           | f gaussdb=> create table stu2 ( gaussdb(> id int , gaussdb(> sid int, gaussdb(> sname int gaussdb(> ); CREATE TABLE   --默认执行计划 gaussdb=> explain select *, func1 AS pk_id  from stu2;  id |      operation       | E-rows | E-width |    E-costs       ----+----------------------+--------+---------+----------------   1 | ->  Seq Scan on stu2 |   1945 |      12 | 0.000..515.700 (1 row)     --smp 不生效 gaussdb=> explain insert /*+ set(query_dop 4) set(enable_force_smp on)*/ into stu1 select * from stu2;  id |        operation        | E-rows | E-width |    E-costs      ----+-------------------------+--------+---------+----------------   1 | ->  Insert on stu1      |   1945 |      12 | 0.000..515.700   2 |    ->  Seq Scan on stu2 |   1945 |      12 | 0.000..515.700 (2 rows)   --将 func1 修改为 i 函数 gaussdb=> ALTER FUNCTION func1() IMMUTABLE ; ALTER FUNCTION   gaussdb=> select proname, provolatile, proshippable  from pg_proc where proname = 'func1';     proname | provolatile | proshippable     ---------+-------------+--------------     func1   | i           | f    (1 row)     --smp 生效 gaussdb=> explain select /*+ set(query_dop 4) set(enable_force_smp on)*/ *, func1 AS pk_id  from stu2;  id |                 operation                  | E-rows | E-width |    E-costs     ----+--------------------------------------------+--------+---------+---------------   1 | ->  Streaming(type: LOCAL GATHER dop: 1/4) |   1945 |      12 | 0.000..11.992   2 |    ->  Seq Scan on stu2                    |   1945 |      12 | 0.000..7.362 (2 rows)2.         insert 使用了自定义函数,当函数为STABLE/VOLATILE类型的函数,且函数的属性是NOT SHIPPABLE的时候(不能下推到dn执行),smp将不生效,需要调整函数属性为SHIPPABLEgaussdb=> CREATE FUNCTION func2 RETURN integer gaussdb->     AS   gaussdb$>     BEGIN gaussdb$>         RETURN 2; gaussdb$>     END; gaussdb$>     / CREATE FUNCTION   --创建function , 默认不下推dn执行gaussdb=> select proname, provolatile, proshippable  from pg_proc where proname = 'func2';  proname | provolatile | proshippable  ---------+-------------+--------------  func2   | v           | f gaussdb=> create table stu1 ( gaussdb(> id int , gaussdb(> sid int, gaussdb(> sname int, gaussdb(> pk_id int  DEFAULT func2() gaussdb(> ); CREATE TABLE     gaussdb=> create table stu2 ( gaussdb(> id int , gaussdb(> sid int, gaussdb(> sname int gaussdb(> ); CREATE TABLE   --默认执行计划 gaussdb=> explain insert  into stu1 select * from stu2;  id |        operation        | E-rows | E-width |    E-costs     ----+-------------------------+--------+---------+---------------   1 | ->  Insert on stu1      |   1945 |      12 | 0.000..29.450   2 |    ->  Seq Scan on stu2 |   1945 |      12 | 0.000..29.450 (2 rows)   --smp 不生效 gaussdb=> explain insert /*+ set(query_dop 4) set(enable_force_smp on)*/ into stu1 select * from stu2;     id |        operation        | E-rows | E-width |    E-costs         ----+-------------------------+--------+---------+----------------      1 | ->  Insert on stu1      |   1945 |      12 | 0.000..515.700      2 |    ->  Seq Scan on stu2 |   1945 |      12 | 0.000..515.700   -- 调整 func2 函数属性为SHIPPABLE gaussdb=> ALTER FUNCTION func2() SHIPPABLE; ALTER FUNCTION   gaussdb=> select proname, provolatile, proshippable  from pg_proc where proname = 'func2';  proname | provolatile | proshippable  ---------+-------------+--------------  func2   | v           | t     -- smp 生效 gaussdb=> explain insert /*+ set(query_dop 4) set(enable_force_smp on)*/ into stu1 select * from stu2;  id |                 operation                  | E-rows | E-width |    E-costs      ----+--------------------------------------------+--------+---------+----------------   1 | ->  Streaming(type: LOCAL GATHER dop: 1/4) |      0 |       0 | 0.000..493.613   2 |    ->  Insert on stu1                      |   1945 |      12 | 0.000..493.613   3 |       ->  Seq Scan on stu2                 |   1945 |      12 | 0.000..493.613 (3 rows)3.         分区表创建global 索引不支持smp。需要将分区表调整成普通表或者将global索引修改为local索引。gaussdb=> create table stu1( gaussdb(> id int , gaussdb(> sid int, gaussdb(> sname int); CREATE TABLE   gaussdb=> create table stu2 ( gaussdb(> id int , gaussdb(> sid int, gaussdb(> sname int gaussdb(> ) PARTITION BY RANGE (id) ( gaussdb(>     PARTITION p1 VALUES LESS THAN (200), gaussdb(>     PARTITION pmax VALUES LESS THAN (MAXVALUE) gaussdb(> ); CREATE TABLE   --创建global 索引 gaussdb=> CREATE INDEX idx_st2 ON stu2(id) GLOBAL; CREATE INDEX     --默认执行计划 gaussdb=> explain insert  into stu1 select * from stu2;  id |               operation                | E-rows | E-width |    E-costs     ----+----------------------------------------+--------+---------+---------------   1 | ->  Insert on stu1                     |   1945 |      12 | 0.000..29.450   2 |    ->  Partition Iterator              |   1945 |      12 | 0.000..29.450   3 |       ->  Partitioned Seq Scan on stu2 |   1945 |      12 | 0.000..29.450 (3 rows)    Predicate Information (identified by plan id)  -----------------------------------------------    2 --Partition Iterator          Iterations: 2    3 --Partitioned Seq Scan on stu2          Selected Partitions:  1..2 (4 rows)   --smp 不生效 gaussdb=> explain insert /*+ set(query_dop 4) set(enable_force_smp on)*/ into stu1 select * from stu2;  id |               operation                | E-rows | E-width |    E-costs     ----+----------------------------------------+--------+---------+---------------   1 | ->  Insert on stu1                     |   1945 |      12 | 0.000..29.450   2 |    ->  Partition Iterator              |   1945 |      12 | 0.000..29.450   3 |       ->  Partitioned Seq Scan on stu2 |   1945 |      12 | 0.000..29.450 (3 rows)    Predicate Information (identified by plan id)  -----------------------------------------------    2 --Partition Iterator          Iterations: 2    3 --Partitioned Seq Scan on stu2          Selected Partitions:  1..2 (4 rows)   --修改索引为本地索引 gaussdb=> DROP INDEX idx_st2; DROP INDEX gaussdb=>  gaussdb=> CREATE INDEX idx_st2 ON stu2(id) LOCAL; CREATE INDEX   --smp 生效 gaussdb=> explain insert /*+ set(query_dop 4) set(enable_force_smp on)*/ into stu1 select * from stu2;  id |                 operation                  | E-rows | E-width |   E-costs     ----+--------------------------------------------+--------+---------+--------------   1 | ->  Streaming(type: LOCAL GATHER dop: 1/4) |      0 |       0 | 0.000..7.362   2 |    ->  Insert on stu1                      |   1945 |      12 | 0.000..7.362   3 |       ->  Partition Iterator               |   1945 |      12 | 0.000..7.362   4 |          ->  Partitioned Seq Scan on stu2  |   1945 |      12 | 0.000..7.362 (4 rows)    Predicate Information (identified by plan id)  -----------------------------------------------    3 --Partition Iterator          Iterations: 2    4 --Partitioned Seq Scan on stu2          Selected Partitions:  1..2 (4 rows)结论1.         select 语句中使用的ks_auth.F_IS_IDNO为易变函数,smp不生效,需要调整为i函数。2.         insert 对应的表TMP_WATCHLIST_CLIENT_PRE使用的函数dsc_ora_ext.dsc_fn_sys_guid() 不能下推到dn执行,smp不生效,需要修改为SHIPPABLE。3.         T_NOR_CLIENT为分区表且创建了global索引,smp 不生效,需要修改为local索引。5.2 JDBC导入和gsql导入在insert,replace,duplicate方式性能差异问题现象在insert插入数据,发现jdbc方式比gsql方式性能差。通过jdbc和gsql两种方式,对比以下三种插入数据方式,发现性能确实存在差异。l   insert into XXX;l   replace into XXX;l   insert into XXX on duplicate XXX;案例验证1.         gsql方式插入数据并查看耗时−           表结构gaussdb=> create table stu1 (f1 varchar(100), gaussdb(> f2 varchar(100), gaussdb(> f3 varchar(100)); CREATE TABLE−           插入方式insert into stu1 values (generate_series(1,200000),generate_series(1,200000), random() *100::decimal(5,2));   replace into stu2 values (generate_series(1,200000),generate_series(1,200000), random() *100::decimal(5,2));   insert into stu3 values (generate_series(1,200000), generate_series(1,200000), random() *100::decimal(5,2)) on duplicate key update f2 = generate_series(1,200000) + 1, f3=generate_series(1,200000)+1;−           执行耗时−           执行计划insert into XXXreplace into XXXinsert into XXX on duplicate XXXjdbc方式插入数据并查看耗时l   insert 方式l   replace方式l   insert ...duplicate 方式l   执行耗时−           执行计划insert into XXX 执行计划−           replace into XXX−           insert into XXX on duplicate XXX结果差异说明l   gsql方式:三种方式语义一样,在数据库内部只解析一次,走硬解析,一条语句插入20万数据,所以耗时短。l   jdbc方式:a.         insert into t_test (a,id,name) values(?,?,?) 走一次硬解析,20万次软解析,jdbc侧使用executeBatch接口调用,在数据库内部体现为执行了20万次insert,发送一次P报文,20万次UE报文,一个prepare语句多次调用,执行execute。b.         replace into t_test(id,name,a) values (?,?,?) 使用executeBatch接口批量插入20万数据,向内核发送pue报文,在数据库内部体现为执行了20万次insert,语句走一次硬解析,后边调用uE报文执行20万次,与1相同。replace into语句是先删除后更新,返回影响的结果有两行。c.         insert into t_test (id,name,a) values (?,?,?) on duplicate key update a = (a + ?),使用executeBatch接口批量插入20万数据,在数据库内部体现为执行了20万次insert。jdbc调用executeBatch接口向内核发送PUE报文,内部将此语句识别为upsert语句,此类语句不能走gplan计划复用,所以每次执行都会解析计划,耗时长.duplicate语句是原位更新,只影响一行。5.3 主备切换时间长问题分析问题描述客户反馈DN主备切换时间长,需要分析原因分析思路主备切换时间长,通常是因为各个别DN日志回放未完成导致,可根据日志实际进行分析。分析过程1.         查看cm_server主日志,确认cm_server下发升主命令的时间以及下发升主的DN。cd $GAUSSLOG/cm/cm_server vim cm_server-yyyy-mm-dd_******-current.log−           2025-06-20 09:31:13.416(cm_server日志时间差8小时),cm_server主收到上报的dn_6001(原主DN)状态异常,可搜索“ERROR”并根据时间点过滤。−           2025-06-20 09:31:13.475(cm_server日志时间差8小时),cm_server主分别下发Lock1锁命令,对dn_6004,dn_6003,dn_6002进行加锁,可搜索“Lock1 message has sent to instance”关键词。2.         查看dn_6002,dn_6003,dn_6004所在节点的cm_agent日志,确认是否收到cm_server下发的加锁命令。cd $GAUSSLOG/cm/cm_agent vim cm_agent-yyyy-mm-dd_******-current.log−           2025-06-20 09:31:13.478 (cm_agent日志时间差8小时),cm_agent对dn_6004加锁,但加锁失败,可搜索“set Lock1 to instance”关键词。−           期间对dn_6003,dn_6002也在加锁,也是加锁失败,可搜索“set Lock1 to instance”关键词。3.         cm_agent加锁失败,进一步查看DN日志,确认DN在执行什么操作。cd $GAUSSLOG/gs_log/dn_6004vim gaussdb-yyyy-mm-dd_******.log查看dn_6004日志,2025-06-20 17:31:13.477 dn_6004未完成回放,可根据时间点搜索。dn_6002、dn_6003在同一时间点也是未完成回放,此处省略截图。4.         继续查看DN运行日志,确认dn_6002,dn_6003,dn_6004在什么时间完成回放。cd $GAUSSLOG/gs_log/dn_6004 vim gaussdb-yyyy-mm-dd_******.log2025-06-20 17:32:31.517,dn_6004优先回放日志完成,可搜索“redo_done flag is:[true]”关键词。dn_6002、dn_6003在同一时间点未完成回放,此处省略截图。5.         dn_6004优先完成回放,进一步查看cm_server主日志,确认是否下发升主命令以及下发时间。cd $GAUSSLOG/cm/cm_server vim cm_server-yyyy-mm-dd_******-current.log2025-06-20 09:32:32.492(cm_server日志时间差8小时),cm_server主下发dn_6004升主命令,可搜索“Failover message has sent to instance”关键词。6.         查看dn_6004节点的cm_agent日志,确认是否收到dn_6004升主命令以及接收时间。cd $GAUSSLOG/cm/cm_agentvim cm_agent-yyyy-mm-dd_******-current.log2025-06-20 09:32:32.492 (cm_agent日志时间差8小时),cm_agent接受cm_server下发的命令,对dn_6004执行升主操作,可搜索“failover msg from cm_server”关键词。7.         查看dn_6004运行日志,确认是否开始升主以及时间点。cd $GAUSSLOG/gs_log/dn_6004 vim gaussdb-yyyy-mm-dd_******.log2025-06-20 17:32:32.529,dn_6004开始升主,可搜索“Instance to do failover”关键词。8.         继续查看dn_6004运行日志,确认升主完成时间点。cd $GAUSSLOG/gs_log/dn_6004 vim gaussdb-yyyy-mm-dd_******.log2025-06-20 09:32:36.808,dn_6004开始接受新的连接,可搜索“database system is ready to accept connections”关键词。9.         查看dn_6004所在节点的cm_agent日志,确认dn_6004解锁时间。cd $GAUSSLOG/cm/cm_agent vim cm_agent-yyyy-mm-dd_******-current.log2025-06-20 09:32:39.510 (cm_agent日志时间差8小时),cm_agent解锁dn_6004成功,可搜索“process_unlock_no_primary_command succeed”关键词。根本原因综上分析,得出主备切换时间长的原因为:l   dn_6001故障以后,dn_6002,dn_6003,dn_6004日志均与主机存在差距,cm_server分别给dn_6002,dn_6003,dn_6004发下锁DN命令,由于DN回放未完成因此支持锁DN失败,直到2025-06-20 17:32:31.517,dn_6004优先回放完成,因此选择dn_6004升主。l   dn_6004回放耗时:2025-06-20 09:31:13.478--2025-06-20 17:32:31.517,持续78s。l   dn_6004升主耗时:2025-06-20 09:32:32.492--2025-06-20 17:32:39.655,持续7s。因此,主备切换耗时长主要在于回放时间长,回放时间长是由于未开启流控,DN主备之间的RTO高。在升主时先要完成回放再执行升主操作。解决方案开启流控:gs_guc reload -Z datanode -N all -I all -c "recovery_time_target=60"补充说明流控原理说明:在备机回放日志的能力跟不上主机时,通过在walsender线程中进行一定时间的sleep来降低日志发送速度,让备机来得及回放已接收的日志。也就是当备机接收日志或者回放日志的能力跟不上主机时,通过强制降低主机的业务性能,来保证主备机的日志差异在一定目标范围。因此,开启流控,在主机业务压力过大时,会限制主机业务。流控为主机业务压力与RTO两者之间的综合选择,需要根据实际业务特点慎重配置。GaussDB关键日志目录介绍:l   GaussDB日志路径为$GAUSSLOG目录l   CN、DN运行日志路径:$GAUSSLOG/gs_logl   cm_server运行日志:$GAUSSLOG/cm/cm_serverl   cm_agent运行日志:$GAUSSLOG/cm/cm_agentl   升级、安装日志:$GAUSSLOG/om5.4 主机流控导致大量业务超时并且无法新建连接问题现象客户反馈,15:25之前是大量SQL执行超时,从15:25开始无法创建连接。分析思路l   突然出现SQL超时,可能是因为并发突增和、IO打满、资源打满等,可优先通过监控查看资源使用情况以及并发数。l   无法新建连接,可能是因为连接数满、连接不释放、中间件连接数满等情况。问题分析1.         获取业务报错信息。获取业务报错信息,根据业务连接池机制分析以下报错信息,业务连接池连接数为20,当连接被占满并长时间不释放,业务新建连接失败。因此怀疑业务连接池到数据库的连接未及时释放,继续分析数据库相关指标及日志。2024-06-13 15:25:02 [traceId:40093804-1545-4937-ab7e-5246d06de9b7] [ERROR] [http-nio-8015-exec-227] [com.cmfchina.fis.capital.apply.job.CapitalJobController:72] -- capitalStatusRefresh>>>fail org.springframework.transaction.CannotCreateTransactionException: Could not open JDBC Connection for transaction; nested exception is com.alibaba.druid.pool.GetConnectionTimeoutException: wait millis 60000, active 20, maxActive 20, creating 0, createErrorCount 12.         查看异常时间段数据库监控指标。−           首先查看资源使用情况,6月13日15:20分左右,cpu、内存使用率无显著突增,表明资源使用无异常。−           其次查看会话连接情况,6月13日15:20分左右,在线会话数略有升高,活跃会话数有显著升高,由15增加到35,表明数据库连接数增加。3.         查看SQL语句分布情况。dn_6001为主DN,根据SQL语句对比,dn_6001上98%的SQL语句为insert语句。当insert语句占比高的时候,通常可能产生流控,因此继续分析流控情况。4.         查看流控相关指标。异常时间段产生主机流控,流控时间达到180000s。  5.         查看DN运行日志。dn_6002,dn_6003均产生流控,同时根据日志,以dn_6002为例,备机接收日志位置为:362E/20A4A000,备机回放位置为:362C/BF72D920,因此表明,备机回放慢导致产生主机流控。6.         分析gs_asp采样数据以及wdr报告。查询gs_asp采样数据以及wdr报告,发现主要的等待事件为:LOGCTRL_SLEEP、wait wal sync,该等待事件表明产生主机流控。7.         查找SQL语句。跟踪WDR报告分析,执行次数最多的两条SQL语句为:3803763747、262602308。进一步根据unique_sql_id,定位到产生流控的主要SQL语句为:1、unique_sql_id为3803763747的INSERT INTO cmf_fis.wind_bondanninf语句;2、unique_sql_id为262602308的INSERT INTO cmf_fis.t_fis_news_port_rel_dm_v4语句。根本原因综上分析:由于大量的insert语句,主机产生xlog多,由于备机回放速率赶不上主机xlog产生速率,触发了主机流控,进而导致已有连接不释放,因此业务新建连接超时。解决措施l   临时解决方案:通常当产生主机流控,执行以下命令关闭流控,进行应急恢复:gs_guc reload -Z datanode -N all -I all -c "recovery_time_target=0"l   长期解决方案:a.         恢复流控参数阈值为30min。gs_guc reload -Z datanode -N all -I all -c "recovery_time_target=1800"b.         开启极致RTO,该参数设置后需要重启集群生效。gs_guc set -Z datanode -N all -I all -c "recovery_parse_workers=2"gs_guc set -Z datanode -N all -I all -c "recovery_redo_workers=4"补充说明l   流控原理说明在备机回放日志的能力跟不上主机时,通过在walsender线程中进行一定时间的sleep来降低日志发送速度,让备机来得及回放已接收的日志。也就是当备机接收日志或者回放日志的能力跟不上主机时,通过强制降低主机的业务性能,来保证主备机的日志差异在一定目标范围。因此,关闭流控,可能存在主备机之间的RTO增大,在主机故障时,主备机切换的时长可能增加。流控为主机业务压力与RTO两者之间的综合选择,需要根据实际业务特点慎重配置。l   极致RTO说明普通串行回放:极致RTO:xLog日志回放建立多级流水线,提高并发度,提升日志回放速度。问题实例CPU利用率均比较低,且产生流控根本原因为备机回放慢导致,因此评估开启极致RTO,可有效提高日志回放速率。5.5 业务分布键选择不合理导致数据分布不均匀问题现象数据磁盘使用率不均衡原因分析客户环境为分布式环境3C3D,从监控指标分析,dn_6001、dn_6002、dn_6003分片的磁盘使用率比其他2个分片高。怀疑是数据分布不均匀导致。分析过程1.         登录到数据库节点,执行如下命令查看数据盘使用率,数据目data1的使用率10%,其他数据目录均为2%。gs_ssh -c "df -h"2.         进入到数据目录data1下,执行如下命令查看文件大小,显示base目录占比最大,怀疑数据分布不均匀。du -sh *3.         执行如下SQL,查询倾斜率较大的表select * from pgxc_get_table_skewness order by skewratio desc limit 10;查询结果可以分析出表“t1”的数据倾斜率为100%,完全倾斜。(一般默认倾斜率大于10%,就代表数据已经倾斜)4.         执行如下SQL,查看表的数据分布情况select schemaname,tablename,nodename,pg_size_pretty(dnsize) dnsize,dnsize/(sum(dnsize) over ()) as percent from table_distribution('root','t1');根据查询结果可以分析出表“t1”的数据全部分布在dn_6001所在的分片5.         查看表“t1”的分布列为“a”,分布方式为hash分布。6.         查看表“t1”字段“a”的值,全部为固定值“1001”综上分析,表“t1”的分布键为固定值,导致数据全部被分布到dn_6001节点,导致该分片所对应的数据目录用率比其他节点高。处理方法建议业务调整分布键,使数据均匀的分布到所有节点,参考分布式表的设计规范:GaussDB 文档中心5.6 DN发生主备切换问题定位问题现象GaussDB 实例主备切换问题分析1.         16:53:14,DN6002与DN6001断联,同时查看DN 主节点,未发现进程异常重启相关文件生成(ffic_log,core文件)。2.         16:53:15,cms主与dn主节点,网络检查失败。3.         16:53:23,CMS主与DN主节点CMA断联,CMS与CMA的连接超时时间受wal_sender_timout参数控制,默认是超过6s连接不上,就会断开连接。4.         同时满足如上两个条件,触发6002升主5.         16:53:30,网络恢复,6001角色上报给cms为主,双主情况下留新主,CMS主下发重启6001命令问题原因网络闪断导致CMS主节点与 DN主节点CMA断联,dn6002与dn6001断联 触发了6002升主。网络恢复后,CMS留新主,重启原主。
  • [问题求助] GaussDB不能执行多个Bind/Describe/Execute然后在最后加一个Flush的操作么
    比如PG可以:GaussDB发现这样就会报EOF错误但是单个的,比如 >B/D/E/H就没事
  • [分享交流] 人形机器人未来发展趋势如何?
    人形机器人未来发展趋势如何?
  • [技术干货] 大数据干货合集(2025年11月)
    集群容灾cid:link_3备份恢复工具cid:link_4物理细粒度备份恢复基本流程cid:link_5物理细粒度备份恢复使用实践cid:link_6业界常用的容灾方案cid:link_7GaussDB(DWS)的容灾是如何实现的cid:link_8log目录结构cid:link_0定位步骤cid:link_9细粒度容灾cid:link_1容灾前准备cid:link_10容灾配置文件backupRestore.inicid:link_11主备集群倒换配置文件sw_backupRestore.inicid:link_2容灾配置文件backupRestore.inicid:link_12show-progress命令cid:link_13熔断策略https://bbs.huaweicloud.com/forum/thread-02126199798402272061-1-1.html
  • [技术干货] 熔断策略
    熔断配置推荐 空闲连接熔断 设置session_timeout为10min stream数量熔断 设置max_streams_per_query为100 执行时长熔断1) 已配置工作负载队列时,在各个工作负载队列配置执行时长,根据业务类型设置阈值。例如,实时查询业务配置600s,跑批分析类业务配置24h; 2) 未配置工作负载队列时,设置statement_timeout参数,根据业务类型设置阈值。例如,实时查询业务配置600s,跑批分析类业务配置24h。 内存熔断 1) 已配置工作负载队列时,管理员用户通过sql语句配置工作负载队列异常规则: ALTER RESOURCE POOL resource_pool_b1 EXCEPT RULE WITH(mem_limit='300MB'); 推荐值:工作负载队列总内存/工作负载队列最小并发。例如,资源池分配总内存为20GB,业务可容忍最小并发为4,则配置阈值为5GB。 工作负载队列总内存=max_process_memory * 工作负载队列内存百分比。 2) 未配置工作负载队列时,设置query_max_mem参数。 推荐值:max_process_memory / 最小并发。 单语句占用空间熔断 设置sql_use_spacelimit参数。 推荐值:空间总大小 * 10% / DN数量。 DN数量可通过select count(*) from pgxc_node where node_namelike '%DN%';进行获取。 单线程下盘空间熔断 设置temp_file_limit参数。 推荐值:空间总大小 * 5% / DN数量。 DN数量可通过select count(*) from pgxc_node where node_namelike '%DN%';进行获取。
  • [技术干货] show-progress命令
    show-progress命令显示的主要字段释义如下: priorKey:该备份集是基于这个backup key生成的。 actionType:备份集当前的操作类型。 取值包括如下: Backup,表示备份阶段。 Restore,表示恢复阶段。 progress:备份或恢复操作的进度。 currentStep:备份或恢复正在执行的步骤。 unrestoreKeys:待恢复的key列表。 failedStep:备份或恢复失败的步骤,初始值默认为INIT。 errorMsg:备份或恢复失败的错误信息,如果成功,该字段则显示成功的信息。 errorCode:备份或恢复的错误码,该字段为预留字段,暂未使用。 actionStartTime:当前操作的开始时间。 actionEndTime:当前操作的结束时间。 updateTime:当前操作进度的刷新时间。 backupState:当前备份状态(backuping/stopped/waiting/abnormal)。 restoreState: 当前恢复状态(restoring/stopped/waiting/abnormal)。 backupSuccessTime:上次成功备份结束的时间。 restoreSuccessTime:上次成功恢复结束的时间。 latestBarrierTime:上次主备集群一致点时间。 recovery point objective:rpo时间(当前主集群时间到最后一个恢复成功的备份集备份开始时间)。 failover recovery point time:failover未同步时间点。
  • [技术干货] 容灾配置文件backupRestore.ini
    standby-cluster-id=22222222-2222-2222-2222-222222222222 # Processes tables for which fine-grained disaster recovery is no longer performed # Value should be 'none', 'log-desync-table', 'drop-desync-table' desync-table-operation=drop-desync-table # Number of CPU cores that can be used by each DR process. Range is (1~1024). cpu-cores=8 # The max number of rch files that can be reserved on master cluster before sent to standby cluster. 0 means no limit. local-reserve-file-count=160# Media destination where the backup must be stored primary-media-destination=/DWS/data2/finedisaster/mediadata # Metadata destination where the metadata must be stored 
  • [技术干货] 主备集群倒换配置文件sw_backupRestore.ini
    primary-metadata-destination=/DWS/data2/finedisaster/metadata # The master-port in which the backup must be executed backup-port=XXXX # Logging level for the log contents of backup:FATAL,ERROR,INFO,DEBUG primary-cluster-logging-level=INFO # Time interval between each restore, uint: min restore-interval=2 # One of the restore hosts restore-host-ip=XXX.XXX.XXX.XX # Media destination where the backup contents must be stored in the standby cluster restore-media-destination=/DWS/data2/finedisaster/mediadata # Metadata destination where the backup contents must be stored in the standby cluster restore-metadata-destination=/DWS/data2/finedisaster/metadata # The master-port in which the restore must be executed restore-port=XXXX 
  • [技术干货] 容灾配置文件backupRestore.ini
    细粒度容灾的容灾备份过程支持与物理细粒度备份业务并行执行。可通过以下措施隔离: 1. 两个备份任务指定不同的metadata目录和media目录,实现备份数据隔离。容灾备份目录通过容灾配置文件(backupRestore.ini和sw_backupRestore.ini)中的参数primary-media-destination和primary-metadata-destination指定。 2. 细粒度容灾的容灾备份端口与物理细粒度备份的master-port指定为不同的值,实现备份进程端口的隔离。容灾的备份端口通过容灾配置文件(backupRestore.ini和sw_backupRestore.ini)中的参数backup-port指定。容灾配置文件backupRestore.ini 以下是backupRestore.ini文件示例,可根据具体业务场景修改配置参数值。 # Configuration file for SyncDataToStby tool# The backup life cycle life-cycle=10m # The table that records backups info backuprestoreinfo-file=backuprestoreinfo.csv # The cluster user name for cluster username=Ruby # The primary cluster env set primary-env= # The standby cluster env set standby-env= # Time interval between each full backup, uint: min full-backup-exec-time-interval=N/A # Time interval between each backup backup-exec-time-interval=2 # One of the backup hosts primary-host-ip=XXX.XXX.XXX.XX # The media type that restore backup files, DISK media-type=disk # The number of process that should be used. Range is (1~32) parrallel-process=4 # The compression level that should be used for backup. Range(0~9) compression-level=1 compression-type=2 # Media destination where the backup must be stored primary-media-destination=/DWS/data2/finedisaster/mediadata # Metadata destination where the metadata must be stored 
  • [技术干货] 容灾前准备
    前提条件 确保ssh服务打开。 确保ssh端口不会被防火墙关闭。 确保所有机器节点间网络畅通。 配置互信 1. 依次登录主备集群各节点沙箱外,执行步骤2-4。 2. 将主集群和备集群所有节点ip和hostname添加到/home/Ruby/.ssh/authorized_keys和/var/chroot/home/Ruby/.ssh/authorized_keys的from列表中。 3. 将主集群和备集群所有节点ip和hostname的映射添加到/etc/hosts和/var/chroot/etc/hosts文件中。 4. 遍历主集群和备集群所有节点ip和hostname,执行以下命令。校验互信 从主集群任一节点能免密ssh到备集群任一节点且从备集群任一节点能免密ssh到主集群任一节点,即代表互信已配置成功。 配置容灾配置文件 1. Ruby用户分别登录主备集群主节点沙箱内。 2. 创建容灾目录,假设目录为/DWS/data2/finedisaster 。 mkdir -p /DWS/data2/finedisaster 3. 在/DWS/data2/finedisaster目录下,创建容灾配置文件backupRestore.ini和主备集群倒换配置文件sw_backupRestore.ini。
  • [技术干货] 细粒度容灾
    当前数仓承载的客户业务越来越多,从而导致客户对于数仓的可靠性要求不断增加。尤其在金融领域,容灾备份机制是信息系统必须提供的能力之一。本文介绍了在云上环境的双集群(不跨Region不跨VPC)后台手动部署并使用细粒度容灾的主要步骤,使得用户能快速方便得搭建起细粒度容灾。对于MPPDB集群的容灾而言,目前业界的常见方案要么是部署两套规格配置同等的集群,要么通过逻辑双加载方式去实现,这两个方案缺点比较明显,存在架构复杂、建设成本高等问题,不仅使得灾备部署难度增大,还导致资源浪费。在此背景下,GaussDB(DWS)基于列存表实现细粒度容灾能力,既满足核心分析型业务在极端场景的业务连续性要求,同时也能大幅降低容灾方案的建设成本,而且容灾架构轻量化,容灾系统易运维、易操作、易演练,从而帮助用户迅捷、经济、按需构建核心业务的容灾系统。 相比于传统的容灾方案,细粒度容灾有以下优势: 主集群和备集群双活(Active-Active)(备集群除灾备表只读外,其余表可读写) 主备集群只需满足DN整数倍关系,降低备集群建设资源,方便灵活部署 利用列存表的数据和元数据分离的特点,通过元数据逻辑同步 + 数据物理同步的方式,同步增量,结合UDF的增量抽取/回放接口,保障表级数据一致性 粒度可控,支持表级、schema级、库级容灾 支持表DDL,部分DCL元数据同步,达到切换可用
  • [技术干货] 定位步骤
    1. 确定问题在备份侧还是恢复侧,查找双集群主结点上Sync日志,确定出错的模块。 2. 确定出错的层次,由于双集群执行过程是一个上下层调用及时序关系的方式,具体顺序参考: crontab -> SyncDataToStby.py -> GaussRoach.py -> gs_roach 3. 在各个模块都有较详细的日志描述过程,具体问题具体分析,大体有如下几个方面: 配置出错,用户、环境变量文文件 备份集群路径权限问题 由于集群状态非Normal导致备份失败 结点故障及备份集损坏导致恢复失败 4. 后续文章会按模块及错误类型来详细描述问题定位步骤。GaussDB(DWS)的双集群容灾功能是一个独立的复杂的分布式系统,涉及到三层工具的使用,因此在问题定位时会造成一些困惑。定位的方法需要先去理解架构、运行机制,然后根据时序关系去对应结点分析日志。后续会从各个模块的角度介绍一些典型的问题及修复方法。
  • [技术干货] log目录结构
    双集群的日志也是存放到$GAUSSLOG这个目录,并且有自己独立的目录 roach, 由这个目录同样是备份/恢复的对应的log路径。我们按调用关系从上到下的角度来介绍 1. frame目录 存放SyncDataToStby.py生成的log,涉及到双集群调度,备份集清理,状态显示,配置文件及命令行参数解析的功能。 2. controller目录 存放GaussRoach.py生成的log,涉及到备份、恢复准备工作一些操作,备份、恢复参数解析,备份集群的处理,错误处理等。controller目录下以disaster开头命令的文件是容灾的log。 3. agent目录 存放gs_roach工具生成的log,涉及到gs_roach连接gaussdb/gtm/cm发起备份/恢复,生成备份集/恢复备份集等操作。agent目录下以disaster开头命令的文件是容灾的log。 gs_roach工具功能:在备份侧完成将cn/dn/gtm/cm的数据文件按顺序打包成备份文件的功能,并生成备份集元信息文件; 恢复侧根据元信息文件将备份集文件解压到对应cn/dn/gtm/cm的数据目录中。
  • GaussDB(DWS)的容灾是如何实现的
    GaussDB(DWS)的容灾方案是一个双集群同步的架构,即两套独立集群定期同步数据以达到容灾的目的。目前数据同步的方式是通过roach(GaussDB(DWS)备份、恢复工具)定期做增量备份和恢复同步。双集群框架是一个复杂的分布式系统,在出现问题时,如何快速准确的定位问题及恢复服务是一个非常紧迫的问题,这个问题在云上会更突出。本文通过介绍双集群的架构、log结构、分析步骤来介绍双集群容灾的问题分析方法。 备份侧调用关系:SyncDataToStby.py -> GaussRoach.py -> gs_roach 恢复侧调用关系:SyncDataToStby.py -> GaussRoach.py -> gs_roachSyncDataToStby.py是整个双集群的调用起始,控制着双集群的正常运行,正常情况下是常驻内存的进程,如果异常退出后,后台会有crontab的来重新拉起双集群脚本: crontab -> SyncDataToStby.py -> GaussRoach.py -> gs_roach系统的各种log是我们了解运行机制,了解问题现场的有力工具,同样双集群的问题分析也依赖于log的分析,首先认识一下双集群对应的日志。
  • [技术干货] 业界常用的容灾方案
    从GaussDB(DWS)的角度去分析业界目前几种通用的容灾方案: 日志同步技术: 1. 列存数据不记日志无法通过日志来同步。 2. 支持列存xlog后会导致导入性能劣化,xlog数据量大,同时会影响日志同步效率。 备份增量同步技术: 1. 无法达到RPO = 0 2. 备集群只能读,无法支持写操作 逻辑数据同步技术: 1. 列存数据需要支持逻辑解码,需要从列存XLog的方向进行演进 2. 分布式事务,DDL等处理难度较大 备份/恢复 1. 不能马上提供服务,RTO时间较长 2. 需要较大空间保存备份集 应用层双写 1. 需要业务配合,对于业务侵入较多,不具有通用性,无法规模商用。GaussDB(DWS)当前在备份增量同步和备份/恢复两个方向进行演进,他们都是基于备份/恢复工具RoachGaussDB(DWS)需要解决四类问题: (1) 快速的备份恢复:高性能备份、恢复操作保证在较短的时间内将数据迁移到另一个集群,对于RPO/RTO要求不大的系统来说实现和使用非常简单。 (2) 备份恢复在集群可用的情况下即可进行,不受单点故障的影响:备份恢复在集群可用的情况下就可以进行,集群只需要保证有可用副本就可以持续的进行备份,并且可以正常恢复。 (3) 备份集的可靠性:备份集需要存储在可靠的存储上,类似OBS/NBU,由于磁盘故障率相对比较高,类似备份集保存在磁盘上也是一种可选的方案。 (4) 容灾支持程度:支持跨AZ级的容灾还是跨Region级的容灾,是否具有全场景下的容灾能力。