Hive支持事务
操作场景
Hive在表以及分区级别支持事务,开启事务模式下,能够增量更新、删除、读取事务表,实现了对事务表操作的原子性、隔离性、一致性和永久性。
事务特性介绍
事务(transaction)是一组单元化操作,这些操作要么都执行,要么都不执行,是一个不可分割的工作单位。事务的四个基本要素通常被称为ACID特性,分别为:
- 原子性(Atomicity):一个事务是一个不可再分割的工作单位,事务中的所有操作要么都发生,要么都不发生。
- 一致性(Consistency):事务开始之前和事务结束以后,数据库的完整性约束没有被破坏。
- 隔离性(Isolation):多个事务并发访问,事务之间是隔离的,一个事务不影响其它事务运行效果。事务之间的影响有:脏读、不可重复读、幻读、丢失更新。
- 持久性(Durability):在事务完成以后,该事务锁对数据库所做的更改将永久保存在数据库中。
事务执行特点:
- 一条语句可以写入多个分区或多个表。如果操作失败,则用户看不到部分写入或插入。即使频繁更改数据,仍然能够快速执行操作。
- Hive能够自动压缩ACID事务文件,而不会影响并发查询。当查询许多小分区文件时,自动压缩可提高查询性能和元数据占用量。
- 读取语义包括快照隔离。当读取操作开始时,Hive在逻辑上处于锁定仓库的状态。读操作不受操作期间发生的任何更改的影响。
锁机制
事务通过以下两点实现ACID特性:
- 预写日志(Write-ahead logging)保证原子性和持久性。
- 锁(locking)保证隔离性。
操作 |
持有锁类型 |
---|---|
Insert overwrite |
hive.txn.xlock.iow=true时持有排他锁,hive.txn.xlock.iow=false时持有半共享锁。 |
Insert |
共享锁。执行该操作时能够对当前表或分区执行读写操作。 |
Update/delete |
半共享锁。执行该操作时能够执行持有共享锁的操作,不能执行持有排他锁或半共享锁的操作。 |
Drop |
排他锁。执行该操作时无法对当前表或分区执行其他任何操作。 |
如果写操作中存在锁机制引发的冲突,优先持有锁的操作将成功,其他操作将失败。
操作步骤
开启事务
- 登录FusionInsight Manager界面,具体请参见访问FusionInsight Manager,选择“集群 > 待操作的集群 > 服务 > Hive > 配置 > 全部配置 > MetaStore(角色) > 事务”。
- 将“metastore.compactor.initiator.on”设置为true。
- 将“metastore.compactor.worker.threads”设置为大于0的正整数。
“metastore.compactor.worker.threads”:在MetaStore上运行压缩程序工作线程个数。请根据实际业务设置合适的值,该值过小会引起事务压缩任务执行慢,过大会导致MetaStore执行性能变低。
- 登录Hive客户端,执行命令开启以下参数,具体操作请参考使用Hive客户端。
set hive.support.concurrency=true;
set hive.exec.dynamic.partition.mode=nonstrict;
set hive.txn.manager=org.apache.hadoop.hive.ql.lockmgr.DbTxnManager;
创建事务表
- 执行以下命令创建事务表。
CREATE TABLE [IF NOT EXISTS] [db_name.]table_name (col_name data_type [COMMENT col_comment], ...) [ROW FORMAT row_format] STORED AS orc ...... TBLPROPERTIES ('transactional'='true'[,'groupId'='group1' ... ] );
例如:
CREATE TABLE acidTbl (a int, b int) STORED AS ORC TBLPROPERTIES ('transactional'='true');
- 当前事务仅支持orc格式。
- 不支持外表。
- 不支持sorted table。
- 创建事务表必须增加表属性'transactional'='true'。
- 只能在事务模式下读写事务表。
使用事务表
- 执行命令使用事务表。以acidTbl表为例:
- 向已有事务表中插入数据。
- 更新已有事务表
UPDATE acidTbl SET b = 10 where a = 1;
acidTbl内容变更为:
- 合并新旧事务表:
MERGE INTO acidTbl AS a
USING acidTbl_update AS b ON a.a = b.a
WHEN MATCHED THEN UPDATE SET b = b. b
WHEN NOT MATCHED THEN INSERT VALUES (b.a, b.b);
acidTbl内容变更为:
执行merge命令时,如果出现“Error evaluating cardinality_violation”异常。请检查连接键是否有重复,或者执行set hive.merge.cardinality.check=false;命令用以规避。
查看事务执行状态
- 执行以下命令查看事务执行状态。
配置压缩功能
HDFS不支持文件的就地更改,对于新增内容,它也不为用户提供读取的一致性。为了在HDFS上提供这些特性,我们遵循了在其他数据仓库工具中使用的标准方法:表或分区的数据存储在一组基本文件中,新增、更新和删除的记录存储在增量文件中。每个事务都创建一组新的增量文件以更改表或分区。在读取时,合并基础文件和增量文件并应用更新或删除的变化。
写事务表将在HDFS上产生部分小文件,Hive提供合并这些小文件的Major压缩和Minor压缩策略。
自动执行压缩操作步骤
- 登录FusionInsight Manager界面,具体请参见访问FusionInsight Manager,选择“集群 > 待操作的集群 > 服务 > Hive > 配置 > 全部配置 > MetaStore(角色) > 事务”。
- 根据实际要求配置以下参数:
表1 参数配置 参数
描述
hive.compactor.check.interval
压缩线程的执行间隔时间。单位:秒。默认值:300。
hive.compactor.cleaner.run.interval
清理线程的执行间隔时间。单位:毫秒。默认值:5000。
hive.compactor.delta.num.threshold
触发Minor压缩的增量文件个数阈值。默认值:10。
hive.compactor.delta.pct.threshold
触发Major压缩的增量文件(delta)大小总和占 base文件大小比例阈值,0.1表示delta文件大小之和与base文件大小之比为10%时触发Major压缩。 默认值:0.1。
hive.compactor.max.num.delta
压缩器将在单个作业中尝试处理的最大增量文件数。默认值:500。
metastore.compactor.initiator.on
是否在此MetaStore实例上运行启动程序线程和清理程序线程。开启事务值必须为true。默认值:false。
metastore.compactor.worker.threads
在MetaStore上运行多少个压缩程序工作线程。设置为0表示不执行压缩,使用事务必须在MetaStore服务的一个或多个实例上将此值设置为正数。单位:秒。默认值:0。
- 登录Hive客户端,执行压缩,具体操作请参考使用Hive客户端。
CREATE TABLE table_name ( id int, name string ) CLUSTERED BY (id) INTO 2 BUCKETS STORED AS ORC TBLPROPERTIES ("transactional"="true", "compactor.mapreduce.map.memory.mb"="2048", -- 指定紧缩map作业的属性 "compactorthreshold.hive.compactor.delta.num.threshold"="4", -- 如果有超过4个增量目录,则触发轻度紧缩 "compactorthreshold.hive.compactor.delta.pct.threshold"="0.5" -- 如果增量文件的大小与基础文件的大小的比率大于50%,则触发深度紧缩 );
或
ALTER TABLE table_name COMPACT 'minor' WITH OVERWRITE TBLPROPERTIES ("compactor.mapreduce.map.memory.mb"="3072"); -- 指定紧缩map作业的属性 ALTER TABLE table_name COMPACT 'major' WITH OVERWRITE TBLPROPERTIES ("tblprops.orc.compress.size"="8192"); -- 更改任何其他Hive表属性
执行压缩后小文件不会被立即删除,cleaner线程完成清理后文件被批量删除。