原文链接:www.gbase.cn/community/p…
更多精彩内容尽在南大通用GBase技术社区,南大通用致力于成为用户最信赖的数据库产品供应商。
本文介绍GBase 8c典型运维场景下,如何快速定位性能瓶颈。以扩缩容、backend线程卡顿场景为例。
1、扩缩容场景
扩缩容过程性能卡顿如何快速定位?从原理上分析,GBase 8c在使用gha_ctl进行扩缩容时,正常会分别输出两个success结果。第一个success表示检查输入参数全部正确且数据目录非空。若这步出现问题直接修改参数即可。而第二个success表示启动子进程执行扩容/缩容的结果,这一步是比较花时间的。
1.1 扩容原理
执行扩容是分下面几个阶段,通过gha_ctl get expand history -l $dcslist 命令的输出结果中phase可以知道卡在哪个阶段。
add_primary > prepare > execute > add_standby > clean_data
- add_primary阶段是dn节点的初始化,添加dn主机。
- prepare阶段是检查需要扩容的node group, 创建目标node group,设置扩容的源node group和目标node group。
- execute阶段是执行gs_redis工具进行数据重分布。
- add_standy阶段添加dn备机的过程。
- clean_data阶段是更改扩容状态到end。
1.2 缩容原理
缩容在第二步骤也分几个阶段, 通过gha_ctl get expand history -l $dcslist 命令的输出结果中phase可以知道是在那个阶段失败。缩容是不需要添加节点的,只会删除节点。
prepare > execute > drop_group > clean_data
- prepare阶段是检查需要缩容的node group, 创建目标node group,设置缩容的源node group和目标node group。
- execute阶段是执行gs_redis工具进行数据重分布。
- drop_group阶段是擅长缩容的datanode组。
- clean_data阶段是更改扩容状态到end。
1.3 解决方法
若在add_primary、add_standy、prepare阶段卡顿或失败时,在gha_server(多个gha_server时,在主gha_server上)上查看/var/log/messages和/tmp/gha_ctl/gha_ctl.log,以及在添加的dn节点上的日志目录gbase/om中查看gs_expansion类日志。
execute阶段失败的话,一般报错消息会显示”gs_redis failed on ...”,此时需要查看gs_redis工具的日志。gs_redis日志在某个CN的bin/gs_redis目录下。
gs_redis日志日志详细记录了失败的原因,然后可在cn的pg_log目录下查看失败原因。
1.4 定位案例
定位案例1
现象如下所示:
[gbase@gbase-82 script]$ ./gha_ctl expand datanode 'dn4 (dn4_1 100.0.0.84 30010 /home/gbase/data/dn4/dn4_1 8020)' -l http://100.0.0.82:2379,http://100.0.0.83:2379,http://100.0.0.84:2379 -u 40ac7d83-6be3-486c-83c4-8942a16d3590
{
"ret":0,
"msg":"Success"
}
[gbase@gbase-82 script]$ {
"ret":-1,
"msg":"Init fail"
}
定位步骤:
首先执行命令,查看一下是在哪个步骤失败:
./gha_ctl get expand history -l http://100.0.0.82:2379,http://100.0.0.83:2379,http://100.0.0.84:2379
例如返回:
{
"state":"idle",
"current":"",
"history":[
{
"time":"2024-12-29 10:27:59",
"uuid":"40ac7d83-6be3-486c-83c4-8942a16d3590",
"phase":"add_primary",
"status":"failed",
"info":{
"dn4":[
{
"name":"dn4_1",
"host":"100.0.0.84",
"port":"30010",
"work_dir":"/home/gbase/data/dn4/dn4_1",
"agent_port":"8020",
"role":"primary",
"agent_host":"100.0.0.84"
}
]
}
}
]
}
发现是在加节点时失败,此时需要检查一下84节点上的gs_expansion***日志,发现没有错误。
然后在gha_server上查看/tmp/gha_ctl/gha_ctl.log文件。
2024-12-29 10:28:04 gbasedb.py expansion 89 DEBUG 345309 Execute expansion command in [100.0.0.84]: source ~/.bashrc;gs_expansion -U gbase -G gbase -X /tmp/gs_gha_2024-12-29_10:28:02_796027/clusterconfig.xml -h 100.0.0.84 --from-gha --inst-name dn4_1 --group-name dn4
2024-12-29 10:28:08 command_util.py execute 249 DEBUG 345309 cmd:ssh -E /dev/null -p 22 gbase@100.0.0.84 "source ~/.bashrc;gs_expansion -U gbase -G gbase -X /tmp/gs_gha_2024-12-29_10:28:02_796027/clusterconfig.xml -h 100.0.0.84 --from-gha --inst-name dn4_1 --group-name dn4", status:1, output: Failed to verify SSH trust on these nodes:
gbase-82, gbase-83, gbase-84, 100.0.0.82, 100.0.0.83, 100.0.0.84 by individual user.
2024-12-29 10:28:08 instance.py init 1614 INFO 345309 Node dn4_1 init error:Failed to execute the command: source ~/.bashrc;gs_expansion -U gbase -G gbase -X /tmp/gs_gha_2024-12-29_10:28:02_796027/clusterconfig.xml -h 100.0.0.84 --from-gha --inst-name dn4_1 --group-name dn4. Error:
Run cmd failed:cmd[ssh -E /dev/null -p 22 gbase@100.0.0.84 "source ~/.bashrc;gs_expansion -U gbase -G gbase -X /tmp/gs_gha_2024-12-29_10:28:02_796027/clusterconfig.xml -h 100.0.0.84 --from-gha --inst-name dn4_1 --group-name dn4"], msg[[GBASE-51100] : Failed to verify SSH trust on these nodes:
gbase-82, gbase-83, gbase-84, 100.0.0.82, 100.0.0.83, 100.0.0.84 by individual user.]
2024-12-29 10:28:08 common.py add_one_node 190 ERROR 345309 init one node dn4_1 failed, code: -1, response: Init fail
我们看到是ssh没有配置互信,测试一下,发现84节点没有配置到其他节点的ssh互信。
解决方法:
配置互信后可以再次尝试扩容。
定位案例2
现象:
[gbase@gbase-82 script]$ ./gha_ctl expand datanode 'dn4 (dn4_1 100.0.0.84 30010 /home/gbase/data/dn4/dn4_1 8020)' -l http://100.0.0.82:2379,http://100.0.0.83:2379,http://100.0.0.84:2379 -u 40ac7d83-6be3-486c-83c4-8942a16d3590
{
"ret":0,
"msg":"Success"
}
[gbase@gbase-82 script]$ {
"ret":-1,
"msg":"gs_redis on cn1 failed"
}
定位步骤:
从错误内容看,是执行gs_redis的时候失败了,然后我们去cn1的bin/gs_redis下查看gs_redis日志。
tid[392445]: INFO: redistributing database "gbase"
tid[392445]: INFO: lock schema gbase.public
INFO: please do not close this session until you are done adding the new node
CONTEXT: referenced column: pgxc_lock_for_transfer
tid[392445]: INFO: redistributing table "spatial_ref_sys"
tid[392445]: INFO: ---- 1. setup table spatial_ref_sys ----
tid[392445]: ERROR: query failed: ERROR: dn4: relation "public.spatial_ref_sys" does not exist
DETAIL: query was: ALTER TABLE public.spatial_ref_sys SET (append_mode=on,rel_cn_oid =17324)
我们登陆到dn4上看检查gbase数据库,确实没有public.spatial。重新创建或导入即可。
2、backend线程
可能存在backend线程卡住的现象。此时可通过 pstack 命令或者 gdb attach 获取卡住的线程的id和栈。
从线面的线程栈上可以看出卡在了 LockAcquire,也就是获取锁的操作。
[Switching to thread 2 (Thread 0x7f6507bb6700 (LWP 29492))]
#0 0x00007f66511ac9a3 in select () from /lib64/libc.so.6
(gdb) bt
#0 0x00007f66511ac9a3 in select () from /lib64/libc.so.6
#1 0x00005568f686537d in pg_usleep(long) ()
#2 0x00005568f66a9022 in ProcSleep(LOCALLOCK*, LockMethodData const*, bool, int) ()
#3 0x00005568f669ca57 in ?? ()
#4 0x00005568f669ebec in ?? ()
#5 0x00005568f669f880 in LockAcquire(LOCKTAG const*, int, bool, bool, bool, int) ()
#6 0x00005568f669a067 in LockRelationOid(unsigned int, int) ()
#7 0x00005568f5548887 in RangeVarGetRelidExtended(RangeVar const*, int, bool, bool, bool, bool, void (*)(RangeVar const*, unsigned int, unsigned int, bool, void*), void*, StringInfoData*, unsigned int*) ()
#8 0x00005568f637120f in relation_openrv_extended(RangeVar const*, int, bool, bool, StringInfoData*) ()
#9 0x00005568f6371c7e in HeapOpenrvExtended(RangeVar const*, int, bool, bool, StringInfoData*) ()
#10 0x00005568f57316fa in parserOpenTable(ParseState*, RangeVar const*, int, bool, bool, bool) ()
#11 0x00005568f5731f79 in addRangeTableEntry(ParseState*, RangeVar*, Alias*, bool, bool, bool, bool, bool) ()
#12 0x00005568f570b2eb in transformFromClauseItem(ParseState*, Node*, RangeTblEntry**, int*, RangeTblEntry**, int*, List**, bool, bool, bool) ()
#13 0x00005568f570cd06 in transformFromClause(ParseState*, List*, bool, bool) ()
#14 0x00005568f56cc470 in transformStmt(ParseState*, Node*, bool, bool) ()
#15 0x00005568f56cdd89 in parse_analyze(Node*, char const*, unsigned int*, int, bool, bool) ()
#16 0x00005568f5f90d57 in pg_analyze_and_rewrite(Node*, char const*, unsigned int*, int) ()
#17 0x00005568f5f9241f in ?? ()
#18 0x00005568f5f9765d in gbaseMain(int, char**, char const*, char const*) ()
#19 0x00005568f5ef247e in ?? ()
#20 0x00005568f5f12b98 in int gbasedbThreadMain<(knl_thread_role)1>(knl_thread_arg*) ()
#21 0x00005568f5ef2505 in ?? ()
#22 0x00007f665148cea5 in start_thread () from /lib64/libpthread.so.0
#23 0x00007f66511b58dd in clone () from /lib64/libc.so.6
根因分析
将线程id 0x7f6507bb6700 换算成10进制的 140071898146560。
用gsql连接节点,查看 pg_locks 表,发现线程获取不到16958/21921 relastion的锁
select * from pg_locks where pid=140071898146560;
locktype | database | relation | page | tuple | bucket | virtualxid | transactionid | classid | objid | objsubid | virtualtransaction | pid | sessionid | mode
| granted | fastpath | locktag | global_sessionid
------------+----------+----------+------+-------+--------+------------+---------------+---------+-------+----------+--------------------+-----------------+-----------------+--------------
---+---------+----------+-------------------+------------------
virtualxid | | | | | | 11/160 | | | | | 11/160 | 140071898146560 | 140071898146560 | ExclusiveLock
| t | t | b:a0:0:0:0:7 | 0:11467#0
relation | 16958 | 21921 | | | | | | | | | 11/160 | 140071898146560 | 140071898146560 | AccessShareLo
ck | f | f | 423e:55a1:0:0:0:0 | 0:11467#0
(2 rows)
查看这个锁的实际持有者,发现实际持有锁的线程pid是0,说明这是个两阶段的事务。
select * from pg_locks where locktype='relation' and relation=21921;
locktype | database | relation | page | tuple | bucket | virtualxid | transactionid | classid | objid | objsubid | virtualtransaction | pid | sessionid | mode
| granted | fastpath | locktag | global_sessionid
----------+----------+----------+------+-------+--------+------------+---------------+---------+-------+----------+--------------------+-----------------+-----------------+----------------
-----+---------+----------+-------------------+------------------
relation | 16958 | 21921 | | | | | | | | | -1/22003 | | 140071506016000 | AccessExclusive
Lock | t | f | 423e:55a1:0:0:0:0 | 0:0#0
relation | 16958 | 21921 | | | | | | | | | 11/160 | 140071898146560 | 140071898146560 | AccessShareLock
| f | f | 423e:55a1:0:0:0:0 | 0:11467#0
(2 rows)
查看本地的两阶段事务列表,发现果然有这个未完成的两阶段事务, prepared 时间是02:51:19
gbase=# select * from pg_prepared_xacts;
transaction | gid | prepared | owner | database | participantids | participantxids
-------------+-------------+-------------------------------+-------+----------+----------------+-----------------
22003 | N474833_cn1 | 2024-12-22 02:51:19.493613+08 | test | gbase | |
(1 row)
查询这段时间 cn的日志,发现错误的日志
2024-12-22 02:51:43.801 63a341ec.3852 [unknown] 140072418014976 [unknown] 0 cn2 42809 0 [BACKEND] ERROR: 42809: could not read two-phase state from xlog at 0/4C52F50, errormsg: incorrect resource manager data checksum in record at 0/4C52F50, record info: xl_info=16, xl_prev=0/4C52F00, xl_rmid=1, xl_tot_len=3261, xl_xid= 22003
2024-12-22 02:51:43.801 63a341ec.3852 [unknown] 140072418014976 [unknown] 0 cn2 42809 0 [BACKEND] LOCATION: XlogReadTwoPhaseData, twophase.cpp:2631
2024-12-22 02:51:44.250 63a3468f.3059 gbase 140071621621504 [unknown] 0 cn2 00000 0 [BACKEND] LOG: 00000: statement: SELECT node_name, node_host, node_port, nodeis_central FROM pgxc_node
2024-12-22 02:51:44.250 63a3468f.3059 gbase 140071621621504 [unknown] 0 cn2 00000 0 [BACKEND] LOCATION: exec_simple_query, gbase.cpp:2378
2024-12-22 02:51:45.005 63a341ec.3852 [unknown] 140072418014976 [unknown] 0 cn2 42809 0 [BACKEND] ERROR: 42809: could not read two-phase state from xlog at 0/4C52F50, errormsg: incorrect resource manager data checksum in record at 0/4C52F50, record info: xl_info=16, xl_prev=0/4C52F00, xl_rmid=1, xl_tot_len=3261, xl_xid= 22003
2024-12-22 02:51:45.005 63a341ec.3852 [unknown] 140072418014976 [unknown] 0 cn2 42809 0 [BACKEND] LOCATION: XlogReadTwoPhaseData, twophase.cpp:2631
2024-12-22 02:51:46.211 63a341ec.3852 [unknown] 140072418014976 [unknown] 0 cn2 42809 0 [BACKEND] ERROR: 42809: could not read two-phase state from xlog at 0/4C52F50, errormsg: incorrect resource manager data checksum in record at 0/4C52F50, record info: xl_info=16, xl_prev=0/4C52F00, xl_rmid=1, xl_tot_len=3261, xl_xid= 22003
解决方法
未完成的两阶段事务占用了锁,导致backend线程卡住了。根据需要等待或回退事务。
原文链接:www.gbase.cn/community/p…
更多精彩内容尽在南大通用GBase技术社区,南大通用致力于成为用户最信赖的数据库产品供应商。