greenplum在执行vacuum和insert产生死锁问题定位及解决方案
Posted yxly2008
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了greenplum在执行vacuum和insert产生死锁问题定位及解决方案相关的知识,希望对你有一定的参考价值。
首先声明:未经本人同意,请勿转载,谢谢!
本人使用自己编译的开源版本的greenplum数据库用于学习,版本为PostgreSQL 8.3.23 (Greenplum Database 4.3.99.00 build dev) on x86_64-unknown-linux-gnu, compiled by GCC gcc (GCC) 4.8.5 20150623
在使用的过程中遇到不少的问题,今天记录一下高并发的情况下,执行insert和vacuum操作造成的死锁,以及解决方案
一、问题描述:
在对ao分区表进行高并发测试的时候同时执行了vacuum的动作,发现会有死锁的问题产生,可以通过如下手段复现:
1)多个线程循环执行insert into t3 select * from XX(t3为本例中用于测试的分区表),为了提高问题复现的速度,可以仅对表中的一个分区进行操作
2)单个线程循环执行vacuum的动作
一段时间后会发现vacuum和insert都卡住,至此问题被复现出来。
二、结论:
该问题仅在AO分区表中会出现,产生的原因是由于数据库加锁的流程设计不合理导致(详情见分析过程)。
三、问题定位及解决方案
抛砖引玉,仅分享自己知道的一点点东西,如果有错误的地方还请指正,欢迎大家一起来讨论这个问题。
1)首先连接master执行:
select * from pg_stat_activity;
查到如下结果:
(图一)
发现有一个session是lock状态,为了弄清楚这里的lock的具体情况,则连接master和standby查看锁的具体情况,执行如下sql:
select a.locktype,b.relname,substring(c.current_query,1,50),c.xact_start,a.pid,a.mode,a.granted from pg_locks a,pg_class b,pg_stat_activity c where a.relation = b.oid and a.pid = c.procpid and relname like \'t3%\';
master:
(图二)
segment1:
(图三)
segment2:
(图四)
需要注意的是,这里图三和图四中在pg_stat_activity表中的current_query一列有<IDLE> in transaction,这里的值和我们平时看到的<IDLE>不是一回事,并不是一个空闲的连接,要弄清楚它的意义来看下官方文档:
(图五)
官方的文档里,对该值仅有这么一小段描述,这里并不能完全的表达出这个字段的意思,我们来看源码:
(图六)
源码里就可以看出这种状态说明该连接的事务是处于阻塞状态。
那么又是为什么会有锁等待的出现呢,因为同一时间,针对同一个对象,有些锁是不能够同时被不同的事务所持有的,如果一个事务持有了某个锁,另一个事务需要获取相同的锁或者是与这个锁冲突的锁,就会出现等待的情况,我们来看下锁之间的冲突情况:
(图七)
综合以上的所有信息,画出了如下的图:
(图七)
说明:
相同颜色的色块表示同一个连接(在物理机上,由ps -ef | grep $pid查到的con确定),红色的线表示等待关系。
create or replace function f_lock_level(i_mode text) returns integer as $$ begin RETURN (select case i_mode when \'INVALID\' then 0 when \'AccessShareLock\' then 1 when \'RowShareLock\' then 2 when \'RowExclusiveLock\' then 3 when \'ShareUpdateExclusiveLock\' then 4 when \'ShareLock\' then 5 when \'ShareRowExclusiveLock\' then 6 when \'ExclusiveLock\' then 7 when \'AccessExclusiveLock\' then 8 else 0 end ); end; $$ language plpgsql strict; --查询 with t_wait as (select a.mode,a.locktype,a.database,a.relation,a.page,a.tuple,a.classid,a.objid,a.objsubid, a.pid,a.virtualtransaction,a.virtualxid,a,transactionid,b.current_query,b.xact_start,b.query_start, b.usename,b.datname from pg_locks a,pg_stat_activity b where a.pid=b.procpid and not a.granted), t_run as (select a.mode,a.locktype,a.database,a.relation,a.page,a.tuple,a.classid,a.objid,a.objsubid, a.pid,a.virtualtransaction,a.virtualxid,a,transactionid,b.current_query,b.xact_start,b.query_start, b.usename,b.datname from pg_locks a,pg_stat_activity b where a.pid=b.procpid and a.granted) select r.locktype,r.mode r_mode,r.usename r_user,r.datname r_db,r.relation::regclass,r.pid r_pid, r.page r_page,r.tuple r_tuple,r.xact_start r_xact_start,r.query_start r_query_start, now()-r.query_start r_locktime,r.current_query r_query,w.mode w_mode,w.pid w_pid,w.page w_page, w.tuple w_tuple,w.xact_start w_xact_start,w.query_start w_query_start, now()-w.query_start w_locktime,w.current_query w_query from t_wait w,t_run r where r.locktype is not distinct from w.locktype and r.database is not distinct from w.database and r.relation is not distinct from w.relation and r.page is not distinct from w.page and r.tuple is not distinct from w.tuple and r.classid is not distinct from w.classid and r.objid is not distinct from w.objid and r.objsubid is not distinct from w.objsubid and r.transactionid is not distinct from w.transactionid and r.pid <> w.pid order by f_lock_level(w.mode)+f_lock_level(r.mode) desc,r.xact_start;
注意:上面的sql适用于文章开头部分greenplum内核版本,不同的版本会有些许差异,这个sql是我根据文章最后参考资料德哥给出的SQL自己修改的,如果您的环境中无法运行,请使用德哥给出的语句。
该sql会返回类似如下的结果(部分):
(图十)
以上是关于greenplum在执行vacuum和insert产生死锁问题定位及解决方案的主要内容,如果未能解决你的问题,请参考以下文章