GaussDB 动态内存过高处理办法
1 问题现象
数据库单节点或多节点动态内存使用率达100%。
tpops监控大盘动态内存单节点使用率99.83
2 问题影响
业务执行SQL可能报错:ERROR:memory is temporarily unavailable。
3 处理思路
动态内存使用率过高,可能由以下三种原因造成,根据不同的内存占用选择不同的应急处理。
- 全局内存占用高
- 线程内存占用高
- session内存占用高
4 解决步骤
步骤 1:使用gsql连接系统库。
gsql -d postgres -p 8000 -U user -r
user需替换为实际的系统管理员账号,此处需要输入密码。
步骤2:在CN或DN节点执行SQL语句,查询实时内存统计信息。
select * from pg_total_memory_detail;
1) CN节点
如下图所示,是当前节点CN的内存使用情况。
2) DN节点
如下图所示,为当前节点DN的内存使用情况。
视图 | 结果 |
process_used_memory | 数据库进程所使用的内存大小。 |
dynamic_used_memory | 已使用的动态内存。 |
dynamic_used_shrctx | 全局内存上下文已使用的动态内存。 |
shared_used_memory | 已使用的共享内存。 |
other_used_memory | 其他已使用的内存大小,包含进程释放后被缓存的内存。 |
- 如果dynamic_used_memory较大,dynamic_used_shrctx较小,则可以确认是线程和session上内存占用较多,则执行步骤3。
- 如果dynamic_used_memory较大,dynamic_used_shrctx和dynamic_used_memory相差不大,则执行步骤6。
- 如果只有shared_used_memory占用较大,则可以确认是共享内存占用较多,忽略即可。
- 如果是other_used_memory较大,一般是由于出现了频繁的内存申请和释放的业务导致内存碎片缓存过多,此时需要继续定位解决。
步骤3: 查看数据库进程所有线程和session的内存上下文占用大小,按照内存上下文分类从大到小排序,选择排序Top10的数据。记录内存占用高的上下文。
1) 线程
分布版
select contextname,sum(totalsize)/1024/1024 totalsize, sum(freesize)/1024/1024 freesize,count(*) sumfrom pv_thread_memory_contextgroup by contextname order by sum desc limit 10;
主备版
select contextname, sum(totalsize)/1024/1024 totalsize, sum(freesize)/1024/1024 freesize, count(*) sum
from gs_thread_memory_context
group by contextname
order by sum desc limit 10;
2)session
分布版
selectcontextname,sum(totalsize)/1024/1024 totalsize,sum(freesize)/1024/1024 freesize,count(*) sum
from pv_session_memory_context
group by contextname
order by sum desc limit 10;
主备版
select contextname, sum(totalsize)/1024/1024 totalsize, sum(freesize)/1024/1024 freesize, count(*) sum
from gs_session_memory_context
group by contextname
order by sum desc limit 10;
、
步骤4:确认内存占用高的SQL语句。
1) 线程
分布版
execute direct on all
'select current_timestamp - query_start as runtime,datname, usename, pid, sessionid, substr(query,0,100)
from pg_stat_activity
where pid in (select tid from pv_thread_memory_context where contextname=''contextname'')
and datname !=''postgres''
and datname =''database''
and usename =''user''';
主备版
select current_timestamp - query_start as runtime, datname,usename, pid, sessionid, substr(query,0,100)
from pg_stat_activity
where pid in (select tid from gs_thread_memory_context where contextname='contextname')
and datname !='postgres'
and datname ='database'
and usename ='user';
注:contextname需要替换为步骤3中记录的上下文名称,其他条件需要根据实际情况修改。
2) session
分布版
execute direct on all
'select current_timestamp - query_start as runtime, datname, usename, pid, sessionid, substr(query,0,100)
from pg_stat_activity
where pid in (select threadid '
from pv_session_memory_context where contextname=''contextname'')
and datname !=''postgres''
and datname =''database''
and usename =''user''';
主备版
select current_timestamp - query_start as runtime, datname, usename, pid, sessionid, substr(query,0,100)
from pg_stat_activity
where pid in (select threadid
from gs_session_memory_context
where contextname='contextname')
and datname !='postgres'
and datname ='database'
and usename ='user';
注:contextname需要替换为步骤3中记录的上下文名称,其他条件可根据实际情况修改。
步骤5:查杀内存占用高的SQL语句
执行以下命令查杀状态为idle以及idle in transaction的会话,如果业务未恢复,可继续查杀状态为active的会话。
1) 线程
分布版
execute direct on coordinator
'select pg_terminate_session(pid,sessionid),pid,sessionid
from pg_stat_activity
where pid in (select tid from pv_thread_memory_context where contextname=''contextname'')
and state=''idle''
and datname !=''postgres''
and datname =''database''
and usename =''user''';
主备版
select pg_terminate_session(pid,sessionid),pid,sessionid
from pg_stat_activity
where pid in (select tid from gs_thread_memory_context where contextname='contextname')
and state='idle'
and datname !='postgres'
and datname ='database'
and usename ='user';
2) session
分布版
execute direct on coordinator
'select pg_terminate_session(pid,sessionid),pid,sessionid
from pg_stat_activity
where pid in (select threadid from pv_session_memory_context where contextname=''contextname'')
and datname !=''postgres''
and datname =''database''
and usename =''user''';
主备版
select pg_terminate_session(pid,sessionid),pid,sessionid
from pg_stat_activity
where pid in (select threadid from gs_session_memory_context where contextname='contextname')
and datname !='postgres'
and datname ='database'
and usename ='user';
注:
- contextname需要替换为步骤3中记录的上下文名称,其他条件需要根据实际情况修改。
- SQL查杀为高危操作,执行前需要联系客户确认。
步骤6:查看数据库进程全局的内存上下文占用大小,按照内存上下文分类从大到小排序,选择排序Top10的数据。
分布版:
select
contextname,
sum(totalsize)/1024/1024 totalsize,
sum(freesize)/1024/1024 freesize,
count(*) sum
from pg_shared_memory_detail
group by contextname
order by sum desc limit 10;
主备版:
select contextname, sum(totalsize)/1024/1024 totalsize, sum(freesize)/1024/1024 freesize, count(*) sum
from gs_shared_memory_detail
group by contextname
order by sum desc limit 10;
如果以上排序靠前的totalsize值占用总动态内存80%以上,freesize接近0,则表明全局内存占用大量的动态内存,一般是内存堆积长时间不释放导致,参考以下步骤触发主备切换。
1. 登录动态内存占用高的节点。
2. 执行命令,查询集群状态,确认当前节点的主DN。
cm_ctl query -Cv
如图示例,当前节点主DN为dn_6001。
3. 获取主DN进程号。
ps ux|grep dn_6001
记录pid。
4. 执行命令,终止主DN的进程。
kill -9 pid
5. 执行命令,确认集群主备切换成功。
cm_ctl query -Cv
6. 确认动态内存使用率恢复正常水平。