更新时间:2024-03-12 GMT+08:00

Hive支持事务

操作场景

Hive在表以及分区级别支持事务,开启事务模式下,能够增量更新、删除、读取事务表,实现了对事务表操作的原子性、隔离性、一致性和永久性。

本章节适用于MRS 3.x及后续版本。

事务特性介绍

事务(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

排他锁。执行该操作时无法对当前表或分区执行其他任何操作。

如果写操作中存在锁机制引发的冲突,优先持有锁的操作将成功,其他操作将失败。

操作步骤

开启事务

  1. 登录FusionInsight Manager界面,具体请参见访问FusionInsight Manager(MRS 3.x及之后版本),选择“集群 > 待操作的集群 > 服务 > Hive > 配置 > 全部配置 > MetaStore(角色) > 事务”。
  2. 将“metastore.compactor.initiator.on”设置为true。
  3. 将“metastore.compactor.worker.threads”设置为大于0的正整数。

    “metastore.compactor.worker.threads”:在MetaStore上运行压缩程序工作线程个数。请根据实际业务设置合适的值,该值过小会引起事务压缩任务执行慢,过大会导致MetaStore执行性能变低。

  4. 登录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;

创建事务表

  1. 执行以下命令创建事务表。

    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'
    • 只能在事务模式下读写事务表。

使用事务表

  1. 执行命令使用事务表。以acidTbl表为例:

    • 向已有事务表中插入数据。

      INSERT INTO acidTbl VALUES(1,1);

    • 更新已有事务表

      UPDATE acidTbl SET b = 10 where a = 1;

      acidTbl内容变更为:

    • 合并新旧事务表:

      acidTbl_update表中已有数据:

      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;命令用以规避。

    • 删除事务表记录:

      DELETE FROM acidTbl where a = 2;

查看事务执行状态

  1. 执行以下命令查看事务执行状态。

    • 查看锁:

      show locks;

    • 查看压缩任务:

      show compactions;

    • 查看事务执行状态:

      show transactions;

    • 中断事务:

      abort transactions TransactionId;

      其中“TransactionId”即是执行•查看事务执行状态:命令后,结果中“Transaction ID”所在列的参数值。

配置压缩功能

HDFS不支持文件的就地更改,对于新增内容,它也不为用户提供读取的一致性。为了在HDFS上提供这些特性,遵循了在其他数据仓库工具中使用的标准方法:表或分区的数据存储在一组基本文件中,新增、更新和删除的记录存储在增量文件中。每个事务都创建一组新的增量文件以更改表或分区。在读取时,合并基础文件和增量文件并应用更新或删除的变化。

写事务表将在HDFS上产生部分小文件,Hive提供合并这些小文件的Major压缩和Minor压缩策略。

自动执行压缩操作步骤

  1. 登录FusionInsight Manager界面,具体请参见访问FusionInsight Manager(MRS 3.x及之后版本),选择“集群 > 待操作的集群 > 服务 > Hive > 配置 > 全部配置 > MetaStore(角色) > 事务”。
  2. 根据实际要求配置以下参数:

    表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。

  3. 登录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线程完成清理后文件被批量删除。