等待事务sync超时
1 Sync等待机制
1.1 什么是sync等待
GaussDB两阶段事务,其提交顺序为:先GTM提交,再CN提交,最后DN提交。同一个事务在不同节点提交次序有先后,会造成数据不一致的问题。因此我们引入了tuple级Sync等待机制:扫描到一条tuple时,如果该DN上tuple对应的事务未提交,等待该事务结束。
1.2 为什么要sync等待
考虑如下例子:
start transaction; insert into t1 values(tuple1,tuple2 on DN1;tuple3 on DN 2) commit; |
假设上面分配的事务id为10,在commit阶段,10事务现在gtm上结束,但是在DN上还未提交,假如此时有一个查询select * from t1;那么该查询从GTM中拿到的快照中10是已经结束的。
Case1:select 到 DN1上扫描到tuple1时,事务10还未在DN1上提交,故tuple1不可见;当在DN1上扫描到tuple2时,事务10已经提交,故tuple2可见。若无sync等待,现有逻辑会造成最终不一致。
Case2:select 到 DN1上扫描tuple1时候,事务10在DN1上已经提交,tuple1可见;select到 DN2上扫描tuple3时,事务10还未在DN2上提交,故tuple3不可见,此时造成瞬时不一致。
2 常用应急方法
从上面的介绍可以看出,等待事务sync超时的原因是某个节点的事务没有正常提交或回滚。所以解决办法就是找到这个事务的业务,分析不能正常提交的原因。不能正常提交可能的原因有:
l 事务残留
l 事务在等锁
l 磁盘IO异常,或通信、xlog日志等导致IO写满,事务提交慢
常用的解决办法有:
l 杀语句
l 找不到语句可以杀实例
l 找不到对应的实例可以重启
如果重启后,重新拉起业务,又出现该问题,说明可能是磁盘存在问题,或者系统参数存在问题,需要分析其他原因,修改相关参数。
3 定位方法
3.1 等待同一个事务超时
出现这种情况,通常是等锁或者事务残留,我们需要想办法找到持锁的线程或残留的线程,杀掉就可以了。
1. 连接CN查找事务id对应的pid:
select * from pgxc_running_xacts where gxid=xxxx or prepared_xid=xxxx or next_xid=xxxx; |
2. 如果pid不是0,执行步骤3;如果pid是0,执行步骤5
3. 根据查找到的pid找到查询的语句等信息
select * from pg_stat_activity where pid=xxxx; |
4. 根据query_id或者pid查找等待情况
select * from pg_thread_wait_status where tid=pid; (上面的pid) |
根据等待情况进行分析:
l 如果没有等待的语句,查看是否残留。确定是残留,后台杀掉该线程即可;
select * from pgxc_prepared_xacts; |
l 如果有等待,可以进一步分析,或者杀掉等待的线程。
5. 查看gs_clean日志,根据各节点的事务提交情况分析,找到与大部分实例事务状态不一致的实例,查看日志进一步分析。
这种情况下已经找不到对应的线程,可以考虑杀掉实例进行规避。
3.2 等待的事务号一直变化
出现这种情况,通常是IO过高或者其他原因,导致事务提交慢。可以根据2.1节内容初步排查,结合其他相关日志排查IO过高等影响事务提交速度的原因:
1. 查看OS日志,排查是否存在慢盘,导致io异常。
2. 查看磁盘IO情况,排查是否因为日志产生较多,将IO占满,导致事务提交很慢;
遇到这种情况,查看日志很多的实例,在postgresql.conf文件中找到生成大量日志相关的参数(例如logging_module),确认后关闭即可。
3. 查看等待超时附近的日志,是否存在其他报错,可能是其他原因导致事务不能正常提交(例如通信)。
出现等待事务sync超时的原因不仅限于以上几种,后续会根据新场景进行补充。
4 参考文献
MPPDB两阶段提交流程 :
http://3ms.huawei.com/hi/group/2191/wiki_5246767.html
- 点赞
- 收藏
- 关注作者
评论(0)