hive表中的锁

任务报错:ERROR : FAILED: Error in acquiring locks: Lock acquisition for LockRequest

场景:

在执行insert into或insert overwrite任务时,中途手动将程序停掉,会出现卡死情况(无法提交MapReduce),只能执行查询操作,而drop insert操作均不可操作。

原因:

hive表被锁或者某个分区被锁,需要解锁

如何查看锁:

show locks 表名

如何解锁:

unlock table 表名; — 解锁表 ,测试这个命令没什么用,表依然处于无法操作状态
unlock table 表名 partition(dt=’2020-04-01’); — 解锁某个分区
注意:

  • 表锁和分区锁是两个不同的锁,对表解锁,对分区是无效的,分区需要单独解锁
  • 高版本hive默认插入数据时,不能查询,因为有锁

    解决办法:

    关闭锁机制
    报错的sql中加入以下语句
    set hive.txn.manager = org.apache.hadoop.hive.ql.lockmgr.DummyTxnManager;
    或者下列语句
    set hive.support.concurrency=false;// 默认为true,可强制忽略锁,但为了数据完整性,不建议常用此操作。
    **

    终极解决办法:

    修改 hive-site.xml 配置文件
    1. [hadoop@hadoop01 ~]$ find / -name hive-site.xml
    2. [hadoop@hadoop01 conf]$ vi hive-site.xml
    3. <property>
    4. <name>set hive.txn.manager</name>
    5. <value>org.apache.hadoop.hive.ql.lockmgr.DummyTxnManager</value>
    6. </property>

注:hive-site.xml中如有下列配置可以不配置,默认为true,如果设置成false则会报错!

<property>
   <name>set hive.support.concurrency</name>
   <value>true</value>
</property>

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

hive.lock.numretries #重试次数
hive.lock.sleep.between.retries #重试时sleep的时间
hive默认的sleep时间是60s,比较长,在高并发场景下,可以减少这个的数值来提供job的效率

HIVE锁原理

Hive中锁类型:

  • 共享锁(Share)
  • 互斥锁(Exclusive)
    不同锁之间的兼容性如下图:
    hive表中的锁 - 图1

锁的基本机制:

  • 元信息和数据的变更需要互斥锁,它会阻止其他的查询、修改操作
  • 数据的读取需要共享锁,共享锁是可以多重、并发使用的

关闭锁机制的影响:

  • 并发读写同一份数据时,读操作可能会随机失败
  • 并发写操作的结果在随机出现,后完成的任务覆盖之前完成任务的结果
  • SHOW LOCKS, UNLOCK TABLE 会报错

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)

    总结:

    想要避免 Hive 锁报错,可以注意以下3点:
    1、表建议设置分区,锁的粒度可以到分区,否则容易遭遇长时间锁表,尤其大字典表、单张全量表要注意。
    2、建议脚本重跑一段时间范围数据时设置 sleep 间隔,避免长期持有锁,造成依赖表的任务调度失败。
    3、我们可以通过 set hive.support.concurrency=false 来关闭锁,优先保证插入数据成功,虽然此时读数据会有问题。