Hive Lock 那些事儿
0、背景
最近两天数据仓库中一张核心表遭遇了锁的问题,导致数据插入失败,影响挺大,之前一直没注意到这个问题,借此总结一下这块的知识和遇到的坑。
hive 在 0.7 版本之后开始支持并发,线上的环境默认是用 zookeeper 做 hive 的锁管理,Hive开启并发功能的时候自动开启锁功能。
1、Hive 锁的类型与关系
hive 目前主要有两种锁,SHARED(共享锁 S)和 Exclusive(排他锁 X)。共享锁 S 和 排他锁 X 它们之间的兼容性矩阵关系如下:
总结起来就是:
- 1)查询操作使用共享锁,共享锁是可以多重、并发使用的
- 2)修改表操作使用独占锁,它会阻止其他的查询、修改操作
- 3)可以对分区使用锁。
以下情况会出发锁,以及它的类型和锁定范围如下:
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 |
2、如何开启锁机制
修改hive-site.xml,配置如下:
<property>
<name>hive.zookeeper.quorum</name>
<value>zk1,zk2,zk3</value>
</property>
<property>
<name>hive.support.concurrency</name>
<value>true</value>
</property>
除此之外,还可以手动显式设置独占锁:
-- 1)锁表
hive> lock table t1 exclusive;
-- 表被独占锁之后,将不能执行查询操作:
hive> SELECT COUNT(*) FROM people;
conflicting lock present for default@people mode SHARED
FAILED: Error in acquiring locks: locks on the underlying objects
cannot be acquired. retry after some time
-- 2)解除锁
hive> unlock table t1;
注:Lock 是一种悲观的顺序化机制。它假设很可能发生冲突,因此在操作数据时,就加锁。 如果冲突的可能性很小,多数的锁都是不必要的。比如 Innodb 实现了一个延迟加锁的机制,来减少加锁的数量,提升性能,在代码中称为隐式锁(Implicit Lock),在本文中提到的 Hive锁默认都是隐式锁,除非手动加锁才是显式锁。
3、如何 debug lock
可以使用以下命令开始debug和排查锁问题:
SHOW LOCKS <TABLE_NAME>;
SHOW LOCKS <TABLE_NAME> EXTENDED;
SHOW LOCKS <TABLE_NAME> PARTITION (<PARTITION_DESC>);
SHOW LOCKS <TABLE_NAME> PARTITION (<PARTITION_DESC>) EXTENDED;
比如我们执行以下语句就可以知道是那个SQL锁Hive表了:
show locks hdp_ubu_zhuanzhuan_defaultdb.token extended
4、如何关闭锁
hive的锁在某些情况下会影响job的效率。在对数据一致性要求不高,或者已经明确了解到lock不会对job产生影响的情况下可以在session级别关闭lock的支持,又或者在表被任务循环持续读取时,insert 插入失败(建议脚本重跑一段时间范围数据时设置 sleep 间隔,避免长期持有锁,造成依赖表的任务调度失败)。我们可以通过 set hive.support.concurrency=false 参数在 session 中关闭锁,这个参数为 false 既能保证session忽略任何锁强行操作数据,又能保证session里的SQL对表不加任何锁。
- 场景1:离线下载分析商业cdn的qos job。
使用load data将数据导入hive中,hive的表按 dt,hour,domain进行明确分区,因此,是否有锁对数据的一致性影响不大,反而有了锁之后,job之间就会有锁竞争的问题(报错信息:conflicting lock present for table mode EXCLUSIVE)。
调整 job:
hive --database cdnlog -e "
set hive.support.concurrency=false;
load data local inpath 'file'
OVERWRITE into table chinanetcenter_log_origin
partition(dt='2013-12-17',hour='04',domain='xxx')
"
数据load时就不会有报错了,效率也高了不少
- 场景2:hive锁的几个配置,可以在锁冲突时 fail fast 或者 重试等待锁释放
hive.lock.numretries #重试次数
hive.lock.sleep.between.retries #重试时sleep的时间
hive默认的sleep时间是60s,比较长,在高并发场景下,可以减少这个的数值来提供job的效率。
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 来关闭锁,优先保证插入数据成功,虽然此时读数据会有问题。
Refer:
[1] Hive Concurrency Model:Locking
https://cwiki.apache.org/confluence/display/Hive/Locking
[2] Hive Locks -- Table/Partition Level
https://community.mapr.com/docs/DOC-1299
[3] hive lock的配置问题
http://caiguangguang.blog.51cto.com/1652935/1344453
[4] MySQL数据库InnoDB存储引擎中的锁机制
http://www.uml.org.cn/sjjm/201205302.asp
[5] mysql锁机制浅析(1)
https://segmentfault.com/a/1190000004507047
- Spart DataSet数据集
- (八)高性能服务器架构设计总结3——以flamigo服务器代码为例
- (八)高性能服务器架构设计总结4——以flamigo服务器代码为例
- SQL员工部门表综合查询60题
- 如何对Scala中集合(Collections)进行排序
- 小白教程——安装和使用PyCharm
- 如何在 Scala 中科学地操作 collection(一)集合类型与操作
- Redis 一二事(2) - 在spring中使用jedis 连接调试单机redis以及集群redis
- 用 Python 制作微信好友个性签名词云图
- 用 Python 查看微信好友位置信息
- 用 Python 分析微信好友性别比例
- FreeMarker静态模板结合spring展示
- 源码阅读之Vector
- 用 Python 实现聊天机器人
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- pip install时timeout设置
- 聊聊dubbo-go的TpsLimitFilter
- 聊聊dubbo-go的TokenFilter
- 你这磨人的小妖精——选中文本并标注的实现过程
- VUE跨页面传值的精妙
- 一文解决如何提取TCGA配对表达矩阵
- CSS中的伪类选择器、颜色、度量单位、文本字体及文本样式设置
- CSS盒模型、边框和背景、表格和列表、颜色和透明度、阴影和轮廓及长度单位rem
- C++核心准则CP.110:不要自已为初始化编写双重检查锁定代码
- BOSS直聘招聘信息获取之爬虫程序数据处理
- BOSS直聘招聘信息获取之爬虫程序分析
- 历时4个多月,学习了这 66 个CSS 特效
- ArrayList、LinkedList哪家强,据说90%人都不知道
- Windows创建克隆隐藏账号
- 学员分享-aspera踩坑记录