GaussDB锁问题
- 故障现象
出现会话等锁、等锁超时、死锁、并发更新性能下降等。
- 故障原因
可能原因有以下:
- 行锁等待,业务逻辑问题,对数据的并发处理顺序有问题,导致死锁、等锁超时或者并发更新同一行。
- 页面锁等待,常见由于数据库内核资源争抢导致。
- IO锁等待,常见由于数据在内存和磁盘之间置换存在并发导致。
- 处理方法
死锁或所等待超时分析
步骤 1 登录CN节点,进入CN日志目录cd $GAUSSLOG/pg_log/cn_xxxx,搜索死锁或锁等待超时关键词。
步骤 2 检查对应报错时间段是否存在死锁:
grep "deadlock detected" postgresql-******.log
说明:
若日志被压缩,则执行zgrep "deadlock detected" postgresql-******.log。
步骤 3 检查对应报错时间段是否存在锁等待超时:
grep "Lock wait timeout" postgresql-******.log
说明:
若日志被压缩,则执行zgrep "Lock wait timeout" postgresql-******.log。
步骤 4 找到死锁或等锁超时触发的语句,若是死锁,则需要从语句和事务逻辑分析,联系业务排查是否有不合理并发;若是等锁超时,需要结合gs_asp分析,历史会话中对应的持锁和等锁语句的行为,可以参考性能劣化问题分析。
----结束
性能劣化问题分析
说明:
本步骤主要分析锁超时导致的整体性能劣化问题。
步骤 1 gsql连接数据库。
gsql -d postgres -p port -U user -W password -r
说明:
分布式需要连接CN节点,集中式需要登录主DN节点。
分布式:
execute direct on all 'select current_timestamp - query_start as runtime,datname,usename,sessionid,substr(query,0,100) from pg_stat_activity where state != ''idle'' and datname in(''$database'') and usename in (''$user'') and extract(epoch from current_timestamp-xact_start)/60 > 1 order by 1 desc;';
集中式:
select current_timestamp - query_start as runtime,datname,usename,sessionid,substr(query,0,100) from pg_stat_activity where state != 'idle' and datname in('$database') and usename in ('$user') and extract(epoch from current_timestamp-xact_start)/60 > 1 order by 1 desc;
说明:
1. $user和$database需根据实际情况修改。
2. extract(epoch from current_timestamp-xact_start)/60 > 1表示查询执行时间大于1min的SQL,可根据实际情况修改。
步骤 3 查询业务是否被锁阻塞,以下为查询阻塞业务的SQL语句,即锁持有者。
若是因为SQL语句慢导致持有锁而阻塞业务,则需要优化该SQL语句,参照单SQL性能慢-计划分析。
若是因为业务逻辑不合理,导致锁问题,参照步骤5。
分布式:
execute direct on all 'select substr(w.query,0,100),l.granted,w.pid,w.sessionid,w.usename from pg_stat_activity w join pg_locks l on w.pid = l.pid where state != ''idle'' and w.datname in(''$database'') and w.usename in (''$user'') and l.granted=true;';
集中式:
select substr(w.query,0,100),l.granted,w.pid,w.sessionid,w.usename from pg_stat_activity w join pg_locks l on w.pid = l.pid where state != 'idle' and w.datname in('$database') and w.usename in ('$user') and l.granted=true;
说明:
$user和$database需根据实际情况修改,建议和步骤2中的条件保持一致。
步骤 4 若要结束该阻塞语句,执行以下SQL。
分布式:
execute direct on all 'select pg_terminate_session(w.pid,w.sessionid),w.pid,w.sessionid from pg_stat_activity w join pg_locks l on w.pid = l.pid where state != ''idle'' and w.datname in(''$database'') and w.usename in (''$user'') and l.granted=true;';
集中式:
select pg_terminate_session(w.pid,w.sessionid),,w.pid,w.sessionid from pg_stat_activity w join pg_locks l on w.pid = l.pid where state != 'idle' and w.datname in('$database') and w.usename in ('$user') and l.granted=true;
说明:
$user和$database需根据实际情况修改,建议和步骤2中的条件保持一致。
须知:结束会话语句为高危操作,执行前需联系业务及华为技术支持确认。
步骤 5 紧急处理后可继续分析,若整体业务逻辑不合理,需业务修改应用程序逻辑,同时优化锁相关参数,涉及参数如下:
1、deadlock_timeout
参数说明:设置死锁超时检测时间,以毫秒为单位。当申请的锁超过设定值时,系统会检查是否产生了死锁。
默认值:1s
2、lockwait_timeout
参数说明:控制单个锁的最长等待时间。当申请的锁等待时间超过设定值时,系统会报错。
默认值:20min
3、update_lockwait_timeout
参数说明:允许并发更新参数开启情况下,该参数控制并发更新同一行时单个锁的最长等待时间。当申请的锁等待时间超过设定值时,系统会报错。
默认值:120000(2min)
4、max_locks_per_transaction
参数说明:控制每个事务能够得到的平均的对象锁的数量。
共享的锁表的大小是以假设任意时刻最多只有max_locks_per_transaction*(max_connections+max_prepared_transactions) 个独立的对象需要被锁住为基础进行计算的。不超过设定数量的多个对象可以在任一时刻同时被锁定。当在一个事务里面修改很多不同的表时,可能需要提高这个默认数值。只能在数据库启动的时候设置。
增大这个参数可能导致GaussDB Kernel请求更多的System V共享内存,有可能超过操作系统的缺省配置。
当运行备机时,请将此参数设置不小于主机上的值,否则,在备机上查询操作不会被允许。
默认值:256
5、max_pred_locks_per_transaction
参数说明:控制每个事务允许断定锁的最大数量,是一个平均值。
共享的断定锁表的大小是以假设任意时刻最多只有max_pred_locks_per_transaction*(max_connections+max_prepared_transactions) 个独立的对象需要被锁住为基础进行计算的。不超过设定数量的多个对象可以在任一时刻同时被锁定。当在一个事务里面修改很多不同的表时,可能需要提高这个默认数值。只能在服务器启动的时候设置。
增大这个参数可能导致GaussDB Kernel请求更多的System V共享内存,有可能超过操作系统的缺省配置。
默认值:64
须知:修改锁相关参数为高危操作,修改前需联系华为技术支持确认。
----结束
- 点赞
- 收藏
- 关注作者
评论(0)