天天看点

分布式DB锁问题排查方法 - 阿里云HybridDB for PostgreSQL最佳实践

postgresql , greenplum , 锁 , segment不一致 , gp_session_role=utility , gp_dist_random

greenplum(gpdb)是一个分布式数据库,分布式数据库的锁管理比单机更加复杂。例如在加锁时,需要对所有节点加锁(包括master和所有的segment节点),在释放锁时,则需要释放所有节点的锁。

如果在释放过程中,master的锁释放了,而segment锁没有释放,会造成什么问题呢?

不用说,会有很诡异的问题出现。例如某个会话锁了某一张表,但是会话退出时,主节点的锁释放了,segnemt节点的锁没有释放。

那么用户在发起新的会话后,如果加载与之冲突的锁,当然要等待了。但是在master节点你观察不到到底它在等待谁,你只能观察到它在等待。是不是很诡异呢?

当你遇到堵塞时,可以另外开启一个会话查看是谁堵塞了谁?

<a href="https://github.com/digoal/blog/blob/master/201705/20170521_01.md">《postgresql 锁等待监控 珍藏级sql - 谁堵塞了谁》</a>

但是本案例通过这个方法,你会发现,只有未赋予的等待,没有已赋予的灵异事件。原因是这个查询没有反馈segment上的锁等待。查询的是gpdb主节点的pg_locks。

正常情况下通过这种方法很容易排查问题,灵异事件需要特殊对待。

greenplum提供了一个函数接口gp_dist_random,当调用这个函数时,会下发到所有segment执行。

gp_dist_random函数的参数是对象名,换句话说说,会在所有segment查询这个对象。在select子句中可以输入一些函数调用,也会下发到segment节点执行。

我们在gpdb的源码中,可以看到大量gp_dist_random的使用。

进入排查阶段。

假设digoal.test这张表的truncate被堵塞了,通过前面的锁sql,没有找到堵塞对象。所以我们需要通过gp_dist_random接口,去segment里面找找锁堵塞的原因。

1、到所有segment执行,找到堵塞digoal.test的query。

sql如下,发现有大量的copy to stdou的查询,看样子是用户断开了master节点的copy操作,但是segment节点的copy还在继续。并且这个事务是2天前发起的,期间还不知道锁了多少其他对象呢。它就是堵塞digoal.test的罪魁祸首。

2、查看segment配置,通过dbid字段和gp_execution_dbid可以匹配到对应的segment。

3、观察一下这些pid都锁了哪些对象。

4、杀死这些segment上的procpid。

注意,数据会重分布到所有节点后再执行pg_terminate_backend,所以pid很可能被重分布到另一个segment,然后调用pg_terminate_backend,因为pid不是当前segment的pid,所以根本杀不掉。

所以手段一仅仅适合排查问题,不能解决问题。

segment节点是不能直接连接的,需要设置一个参数,就可以连接了。

手段一帮助我们找到了持锁的segment,手段二则登陆对应的主机,直连segment去terminate对应的process。

直连到segment后,可以在这里看到持锁的sql,这个sql是coy to stdou,显然是master中断这个sql后,而segment没有中断造成的。属于gpdb本身的bug,需要修复。

杀掉所有segment的持锁会话后,恢复业务。

<a href="https://www.postgresql.org/docs/8.2/static/runtime-config-developer.html">https://www.postgresql.org/docs/8.2/static/runtime-config-developer.html</a>

<a href="https://github.com/digoal/blog/blob/master/201603/20160309_01.md">《greenplum通过gp_dist_random('gp_id') 在所有节点调用某个函数》</a>