【Hive】Hive锁机制分析及任务问题处理

发布于:2023-01-26 ⋅ 阅读:(19) ⋅ 点赞:(0) ⋅ 评论:(0)

1.背景

在数据仓库开发中,遇到了读取数据任务导致锁表问题,发现是因为补数据或月度大任务跨天运行,此时凌晨定时的写入操作就会被阻塞进入等待状态(如果超过最大等待时间会失败),直到读取任务完成写入任务才可以继续运行,导致当天结果层数据输出延迟。因此分析并总结下锁表机制原理以及解决方式。

2.锁机制及原理分析

Hive 目前主要有两种锁,SHARED(共享锁 S)和 Exclusive(排他锁 X),同时又分表锁与分区锁,分区锁为最小粒度;共享锁 S 和  排他锁 X 它们之间的兼容性矩阵关系如下:

0

解释:

  • 1)表锁与分区锁,分区锁为最小粒度(如果表锁未锁写入的分区,是可以执行写入任务的)
  • 2)查询操作使用共享锁(S锁),共享锁是可以多重、并发使用的(就是说其他查询也可以挂S锁,并发查询不会阻塞修改会阻塞)
  • 3)修改表操作使用独占锁(X锁),它会阻止其他的查询、修改操作
  • 4)S锁和X锁同时出现会出现死锁情况(查询和写入不可同时发生)

以下情况会出发锁,以及它的类型和锁定范围如下:

Hive Command

Locks Acquired

select .. T1 partition P1

S on T1, T1.P1

insert into T2(partition P2) select .. T1 partition P1

S on T2, T1, T1.P1 and X on T2.P2

insert into T2(partition P.Q) select .. T1 partition P1

S on T2, T2.P, T1, T1.P1 and X on T2.P.Q

alter table T1 rename T2

X on T1

alter table T1 add cols

X on T1

alter table T1 replace cols

X on T1

alter table T1 change cols

X on T1

alter table T1 concatenate

X on T1

alter table T1 add partition P1

S on T1, X on T1.P1

alter table T1 drop partition P1

S on T1, X on T1.P1

alter table T1 touch partition P1

S on T1, X on T1.P1

alter table T1 set serdeproperties

S on T1

alter table T1 set serializer

S on T1

alter table T1 set file format

S on T1

alter table T1 set tblproperties

X on T1

alter table T1 partition P1 concatenate

X on T1.P1

drop table T1

X on T1

3.解决方式

Hive锁机制会影响我们数据仓库输出效率,如果在已知表/分区的解锁对正运行的任务没有影响情况下我们可以在session 中关闭锁,通常我们会在X锁操作任务加上set hive.support.concurrency=false; 这个参数为 false 既能保证session忽略任何锁强行操作数据,又能保证session里的SQL对表不加任何锁;非分区表慎用由于不加锁写入时候同时读取会导致数据一致性问题。

排查及解决流程:

show locks tableName; #查看表锁

show locks tableName partition(dt='2014-04-01'); #查看分区锁

unlock table; unlock table partition(dt='2014-04-01'); #解锁表

set hive.support.concurrency=false; #在 session 中关闭锁默认为true,

4.拓展分析

排查锁问题方式

SHOW LOCKS <TABLE_NAME>; #查看HIVE表是否被锁
SHOW LOCKS <TABLE_NAME> EXTENDED;#查看哪一个SQL锁了HIVE表 
SHOW LOCKS <TABLE_NAME> PARTITION (<PARTITION_DESC>); #查看HIVE表分区是否被锁 
SHOW LOCKS <TABLE_NAME> PARTITION (<PARTITION_DESC>) EXTENDED;#查看哪一个SQL锁了HIVE表分区

hive锁的几个配置,可以在锁冲突时 fail fast 或者 重试等待锁释放

(hive默认的sleep时间是60s,比较长,在高并发场景下,可以减少这个的数值来提供job的效率)

hive.lock.numretries #重试次数
hive.lock.sleep.between.retries #重试时sleep的时间

Hive(CDH4.2.0)的锁处理流程:

1.首先对query进行编译,生成QueryPlan

2.构建读写锁对象(主要两个成员变量:LockObject,Lockmode)
  对于非分区表,直接根据需要构建S或者X锁对象
  对于分区表:(此处是区分input/output)
If S mode:
    直接对Table/related partition 构建S对象
Else:
    If 添加新分区:
        构建S对象
    Else
        构建X对象
End

3.对锁对象进行字符表排序(避免死锁),对于同一个LockObject,先获取Execlusive

4.遍历锁对象列表,进行锁申请
While trynumber< hive.lock.numretries(default100):
    创建parent(node)目录,mode= CreateMode.PERSISTENT
    创建锁目录,mode=CreateMode.EPHEMERAL_SEQUENTIAL
    For Child:Children
        If Child已经有写锁:
            获取child写锁seqno
        If mode=X 并且 Child 已经有读锁
            获取child读锁seqno
        If childseqno>0并且小于当前seqno
            释放锁
        Trynumber++
    Sleep(hive.lock.sleep.between.retries:default1min)

5.总结:

避免Hive因为锁导致的读写任务阻塞等待或失败:

1、建议表设置分区,因为锁可以到分区粒度,防止大字典表,单张全量表类似表长时间锁表,导致长时间阻塞读写任务。

2、如果新分区被锁可以通过 set hive.support.concurrency=false 来关闭锁机制,保证新分区写入数据成功。非分区表慎用由于不加锁写入时候同时读取会导致数据一致性问题。

3、脚本重跑一段时间范围数据时设置 sleep 间隔,避免长期持有锁,造成依赖此表的下游任务调度失败(这种方式需要根据下游任务分析运行状态时间)。

6.参考资料:

[1] Hive官方文档:锁

Locking - Apache Hive - Apache Software Foundation

[2] hive lock的配置

hive lock的配置问题_weixin_34239169的博客-CSDN博客