HIVE 新特性 ACID 初试

本文介绍如何在Hive 0.14版本中配置ACID特性和事务支持,包括数据库初始化步骤、hive-site.xml的配置项调整、创建具备ACID特性的表的具体语法等。

在 Hive 0.14 之前,Hive QL 一直不支持insert、update、delete 操作,这显然很不方便,尤其是在构建数据仓库的过程中,一个比较常见的例子是维度表经常需要更新某列,在 Hive 中需要更新历史所有数据,这显然是不合理的。

在 Hive 0.14 版本,支持了行级别的 ACID 与 Transactions,这也就解决了上面的问题。

本文主要讲解如何在 Hive 0.14 配置,使得支持上述两个特性,相关原理及性能分析后面再单独写一篇文章来分析。

相关软件说明:

  • Hive 1.1.0
  • mysql 5.6(存储 metastore )

1. 初始化数据库

mysql> create database metastore_db;
mysql> USE metastore_db;  
mysql> SOURCE $HIVE_HOME/scripts/metastore/upgrade/mysql/hive-schema-1.1.0.mysql.sql
mysql> SOURCE $HIVE_HOME/scripts/metastore/upgrade/mysql/hive-txn-schema-0.13.0.mysql.sql
mysql> CREATE USER 'hive'@'localhost' IDENTIFIED BY 'mypassword';  
mysql> grant all privileges on metastore_db.* to hive@'%' identified by 'hive';
mysql> FLUSH PRIVILEGES;  
mysql> quit;  

这里需要注意的是,必须source txn相关的表,否则后面创建表是会报下面几种错误:

FAILED: Execution Error, return code 1 from org.apache.hadoop.hive.ql.exec.DDLTask. MetaException(message:javax.jdo.JDODataStoreException: Schema Transaction threw exception "Add classes to Catalog "metastore_db", Schema """
    at org.datanucleus.api.jdo.NucleusJDOHelper.getJDOExceptionForNucleusException(NucleusJDOHelper.java:451)
    at org.datanucleus.api.jdo.JDOPersistenceManager.jdoMakePersistent(JDOPersistenceManager.java:732)
    at org.datanucleus.api.jdo.JDOPersistenceManager.makePersistent(JDOPersistenceManager.java:752)
    at org.apache.hadoop.hive.metastore.ObjectStore.createTable(ObjectStore.java:794)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at org.apache.hadoop.hive.metastore.RawStoreProxy.invoke(RawStoreProxy.java:98)
    at com.sun.proxy.$Proxy6.createTable(Unknown Source)
    at org.apache.hadoop.hive.metastore.HiveMetaStore$HMSHandler.create_table_core(HiveMetaStore.java:1393)
    at org.apache.hadoop.hive.metastore.HiveMetaStore$HMSHandler.create_table_with_environment_context(HiveMetaStore.java:1426)

2. 配置 hive-site.xml

<property>
    <name>hive.support.concurrency</name>
    <value>true</value>
</property>
<property>
    <name>hive.txn.manager</name>
    <value>org.apache.hadoop.hive.ql.lockmgr.DbTxnManager</value>
</property>
<property>
    <name>hive.enforce.bucketing</name>
    <value>true</value>
</property>
<property>
    <name>hive.compactor.initiator.on</name>
    <value>true</value>
</property>
<property>
    <name>hive.compactor.worker.threads</name>
    <value>2</value>
</property>
<property>
    <name>hive.exec.dynamic.partition.mode</name>
    <value>nonstrict</value>
</property>
<property>
    <name>hive.compactor.initiator.on</name>
    <value>true</value>
</property>

<!-- mysql 相关 -->
<property>  
   <name>javax.jdo.option.ConnectionURL</name>  
   <value>jdbc:mysql://localhost:3306/metastore?createDatabaseIfNotExist=true</value>  
    <description>Enter your JDBC connection string. </description>  
</property>  
<property>  
    <name>javax.jdo.option.ConnectionDriverName</name>  
    <value>com.mysql.jdbc.Driver</value>  
</property>  
<property>  
    <name>javax.jdo.option.ConnectionUserName</name>  
    <value>hive</value>
</property>  
<property>  
    <name>javax.jdo.option.ConnectionPassword</name>  
    <value>hive</value>  
</property>  
<property>  
    <name>datanucleus.autoCreateSchema</name>  
    <value>false</value>  
</property>  
<property>  
    <name>datanucleus.fixedDatastore</name>  
    <value>true</value>  
</property>

3. 创建具备ACID及Transactions的表

这里的表需要具备下面几个条件:
1. 必须以 ORC 格式存储
2. 必须分 bucket,且不能 sort
3. 必须显式声明transations

大致如下面模版所述:

create table T(...) 
clustered by (a) into 2 buckets
stored as orc TBLPROPERTIES ('transactional'='true');

知道了限定条件,我们来创建一个表做个测试:

create table goods_info (
    shop_id int,
    created_time string,
    title string
)
clustered by (shop_id) into 3 buckets
stored as orc TBLPROPERTIES ('transactional'='true');

之后insert两条数据

insert into table goods_info values (1, '2016-04-02 21:00:00', 'HIVE 7天入门'), (2, '2016-04-02 21:01:00', 'SICP');

回车后,会运行一个MR去插入数据,之后就可以查询了

hive (default)> select * from goods_info;
OK
1   2016-04-02 21:00:00 HIVE 7)e�
2   2016-04-02 21:01:00 SICP
Time taken: 0.116 seconds, Fetched: 2 row(s)

这里的中文貌似有乱码问题,这里先不做处理了。
在 hdfs 上生产的文件为:

210  /user/hive/warehouse/goods_info/delta_0000005_0000005/bucket_00000
810  /user/hive/warehouse/goods_info/delta_0000005_0000005/bucket_00001
781  /user/hive/warehouse/goods_info/delta_0000005_0000005/bucket_00002

在创建表时,我遇到了下面的问题

FAILED: Execution Error, return code 1 from org.apache.hadoop.hive.ql.exec.DDLTask. MetaException(message:javax.jdo.JDODataStoreException: An exception was thrown while adding/validating class(es) : Specified key was too long; max key length is 767 bytes
com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Specified key was too long; max key length is 767 bytes
    at sun.reflect.GeneratedConstructorAccessor31.newInstance(Unknown Source)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:422)
    at com.mysql.jdbc.Util.handleNewInstance(Util.java:377)
    at com.mysql.jdbc.Util.getInstance(Util.java:360)
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:978)
    at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3887)
    at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3823)
    at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2435)
    at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2582)
    at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2526)
    at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2484)
    at com.mysql.jdbc.StatementImpl.execute(StatementImpl.java:848)
    at com.mysql.jdbc.StatementImpl.execute(StatementImpl.java:742)
    at com.jolbox.bonecp.StatementHandle.execute(StatementHandle.java:254)

这时由于 mysql 自身对索引字段字符长度的限制,我数据库用的是utf8编码,767/3=255.6,这也就是说索引字段的varchar不能大于255,对于 mysql5.6以及以后的版本,可以通过在/etc/my.conf中添加如下配置解决

[mysqld]
innodb_file_format=BARRACUDA
innodb_large_prefix=on
innodb_file_per_table=true

相关原理可见:

### Hive ACID 特性详解及实现机制 Hive在0.13版本之后引入了ACID(Atomicity, Consistency, Isolation, Durability)事务特性,并在后续版本中不断完善,以支持包括INSERT、UPDATE和DELETE在内的事务操作。这一特性使得Hive能够更好地支持数据仓库中常见的实时或近实时数据更新需求,例如维度表的增量更新等场景[^1]。 #### 1. ACID特性的核心概念 Hive中的ACID特性为事务表提供了数据一致性、事务支持和并发控制等能力,使其在多用户并发访问时能够保持数据的完整性与一致性。具体包括以下特性: - **原子性(Atomicity)**:事务中的所有操作要么全部成功,要么全部失败,保证数据的完整性[^1]。 - **一致性(Consistency)**:事务执行前后,数据库的完整性约束(如主键、外键等)保持不变。 - **隔离性(Isolation)**:多个事务并发执行时,彼此之间不会互相干扰,确保每个事务的执行结果符合预期。 - **持久性(Durability)**:事务一旦提交,其对数据的修改将被永久保存,即使系统发生故障也不会丢失。 #### 2. 实现机制 HiveACID特性依赖于HDFS的文件系统特性以及Hive自身的事务管理机制。具体实现包括以下几个关键部分: ##### 2.1 事务管理器 Hive使用`org.apache.hadoop.hive.ql.lockmgr.DbTxnManager`作为事务管理器,负责事务的开始、提交和回滚操作。该事务管理器通过数据库存储事务元数据,确保事务的隔离性和一致性[^4]。 ##### 2.2 文件存储格式 Hive ACID事务表必须使用特定的存储格式,例如ORC(Optimized Row Columnar)。ORC文件格式支持高效的压缩和编码,同时支持事务日志(delta文件)的写入,以记录数据的更新操作。Hive通过合并delta文件和原始数据文件来实现最终一致性[^2]。 ##### 2.3 事务日志(Delta Files) Hive事务表通过delta文件记录INSERT、UPDATE和DELETE操作的变化。这些delta文件存储在HDFS的子目录中,每个事务会生成一个对应的delta文件。当事务提交后,Hive会将delta文件与原始数据文件进行合并,以生成新的数据版本。这种机制确保了事务的隔离性和一致性[^2]。 ##### 2.4 合并器(Compactor) Hive提供了一个名为Compactor的组件,用于定期合并delta文件和原始数据文件。Compactor包括两个主要线程: - **Initiator**:负责检测是否需要合并delta文件。 - **Worker**:负责执行实际的文件合并操作。 通过配置`hive.compactor.initiator.on`和`hive.compactor.worker.threads`参数,可以启用并控制Compactor的行为[^4]。 #### 3. 配置要求 为了启用HiveACID特性,需要在`hive-site.xml`中进行以下配置: ```xml <property> <name>hive.support.concurrency</name> <value>true</value> </property> <property> <name>hive.enforce.bucketing</name> <value>true</value> </property> <property> <name>hive.exec.dynamic.partition.mode</name> <value>nonstrict</value> </property> <property> <name>hive.txn.manager</name> <value>org.apache.hadoop.hive.ql.lockmgr.DbTxnManager</value> </property> <property> <name>hive.compactor.initiator.on</name> <value>true</value> </property> <property> <name>hive.compactor.worker.threads</name> <value>1</value> </property> ``` 这些配置确保Hive支持并发事务操作,并启用Compactor以优化存储性能[^4]。 #### 4. 事务表的创建与操作 创建事务表时,需要指定表的存储格式为ORC,并启用事务特性。以下是一个示例: ```sql CREATE TABLE sales ( id INT, product STRING, amount DOUBLE ) CLUSTERED BY (id) INTO 4 BUCKETS STORED AS ORC TBLPROPERTIES (&#39;transactional&#39;=&#39;true&#39;); ``` 事务表支持INSERT、UPDATE和DELETE操作。例如: ```sql -- 插入数据 INSERT INTO TABLE sales VALUES (1, &#39;Product A&#39;, 100.0); -- 更新数据 UPDATE sales SET amount = 150.0 WHERE id = 1; -- 删除数据 DELETE FROM sales WHERE id = 1; ``` #### 5. ACID特性的影响 启用ACID特性后,Hive事务表在存储格式、元数据管理和性能方面都会受到影响: - **存储格式**:事务表必须使用ORC格式,并且需要额外存储delta文件,这会增加存储开销。 - **元数据管理**:事务表的元数据需要存储在关系型数据库中,以支持事务管理器的运行。 - **性能影响**:由于需要维护事务日志和执行文件合并操作,事务表的写入性能可能会下降。此外,查询性能也可能受到影响,尤其是在delta文件较多的情况下[^2]。 尽管如此,HiveACID特性为数据仓库提供了更强的数据一致性保障,适用于需要频繁更新数据的场景。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值