作者简介:李磊,Cloudera售前技术经理,资深解决方案顾问,10年Java大型软件开发经验,5年大数据平台开发,规划和设计经验。长期从事数据存储、处理、分析等相关工作,熟悉分布式系统开发及设计,精通Hadoop等开源产品的大数据技术。最近5年,在Cloudera和Intel负责大型运营商,银行,制造业,政府等Hadoop平台的实施、咨询、软件开发、架构设计以及性能调优等相关工作。 原文链接:http://www./cn/articles/guide-of-hive-transaction-management ◆◆◆ 1.简介 Hive作为Hadoop家族历史最悠久的组件之一,一直以其优秀的兼容性支持和稳定性而著称,越来越多的企业将业务数据从传统数据库迁移至Hadoop平台,并通过Hive来进行数据分析。但是我们在迁移的过程中难免会碰到如何将传统数据库的功能也迁移到Hadoop的问题,比如说事务。事务作为传统数据库很重要的一个功能,在Hive中是如何实现的呢?Hive的实现有什么不一样的地方呢?我们将传统数据库的应用迁移到Hive如果有事务相关的场景我们该如何去转换并要注意什么问题呢? 本文会通过很多真实测试案例来比较Hive与传统数据库事务的区别,并在文末给出一些在Hive平台上使用事务相关的功能时的指导和建议。 2.ACID与实现原理 为了方便解释和说明后面的一些问题,这里重提传统数据库事务相关的概念,以下内容来源于网络。 2.1 ACID说明 何为事务?就是一组单元化操作,这些操作要么都执行,要么都不执行,是一个不可分割的工作单位。 事务(transaction)所应该具有的四个要素:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability)。这四个基本要素通常称为ACID特性。 原子性(Atomicity) 一个事务是一个不可再分割的工作单位,事务中的所有操作要么都发生,要么都不发生。 一致性(Consistency) 事务开始之前和事务结束以后,数据库的完整性约束没有被破坏。这是说数据库事务不能破坏关系数据的完整性以及业务逻辑上的一致性。 隔离性(Isolation) 多个事务并发访问,事务之间是隔离的,一个事务不影响其它事务运行效果。这指的是在并发环境中,当不同的事务同时操作相同的数据时,每个事务都有各自完整的数据空间。事务查看数据更新时,数据所处的状态要么是另一事务修改它之前的状态,要么是另一事务修改后的状态,事务不会查看到中间状态的数据。 事务之间的相应影响,分别为:脏读、不可重复读、幻读、丢失更新。 持久性(Durability) 意味着在事务完成以后,该事务锁对数据库所作的更改便持久的保存在数据库之中,并不会被回滚。 2.2 ACID的实现原理 事务可以保证ACID原则的操作,那么事务是如何保证这些原则的?解决ACID问题的两大技术点是: 预写日志(Write-ahead logging)保证原子性和持久性 锁(locking)保证隔离性 这里并没有提到一致性,是因为一致性是应用相关的话题,它的定义一个由业务系统来定义,什么样的状态才是一致?而实现一致性的代码通常在业务逻辑的代码中得以体现。 注:锁是指在并发环境中通过读写锁来保证操作的互斥性。根据隔离程度不同,锁的运用也不同。 3.测试环境 操作系统 CentOS 6.5 JDK jdk1.7.0_67 CDH 5.9 Hadoop 2.6.0 Hive 1.1.0 4.Hive的ACID测试 4.1 Hive中的锁(不开启事务) Hive中定义了两种锁的模式:共享锁(S)和排它锁(X),顾名思义,多个共享锁(S)可以同时获取,但是排它锁(X)会阻塞其它所有锁。在本次测试中,CDH5.9的Concurrency参数是默认开启的(hive.support.concurrency=true),以下分别对开启Concurrency和关闭进行相关测试。 首先在测试之前,创建一个普通的hive表: create table test_notransaction(user_id Int,name String); 向test_transaction表中插入测试数据: insert into test_notransaction values(1,'peach1'),(2,'peach2'),(3, 'peach3'),(4, 'peach4'); 查看插入的数据: 4.1.1 开启Concurrency 1. 对catalog_sales表进行并发select操作 执行的sql语句:select count(*) from catalog_sales; 执行单条sql查询时,获取一个共享锁(S),sql语句正常执行 同时执行两条sql查询是,获取两个共享锁,并且sql语句均正常执行 分析:由此对比可得出hive在执行sql查询时获取Share锁,在并发的情况下可获取多个共享锁。 2. 对test表进行并发Insert操作 创建表: create table test(name string, id int); 执行sql语句: insert into test values('test11aaa1',1252); 执行单条insert语句时,获取一个X锁,sql语句正常执行 同时执行两条insert语句时,只能获取一个test表X锁,第一条insert语句正常执行,第二条insert语句处于等待状态,在第一条insert语句释放test表的X锁,第二条sql语句正常执行. 分析:由此对比可得出hive在执行insert操作时,只能获取一个X锁且锁不能共享,只能在sql执行完成释放锁后,后续sql方可继续执行。 3. 对test表执行select的同时执行insert操作 执行sql语句: select count(*) from test; 步骤: 1) 执行select语句,在select未运行完时,在新的窗口同时执行insert语句观察两条sql执行情况,select语句正常执行,insert语句处于等待状态。 2) 此时查看test表锁状态 在步骤1的执行过程中,获取到test表的锁为共享锁(S) 3) 在select语句执行完成后,观察insert语句开始正常执行,此时获取test表锁为排它锁(X)。注意:在select语句执行完成后,大概过40s左右insert语句才正常执行,这是由hive.lock.sleep.between.retries参数控制,默认60 分析: 由上述操作可得出,hive中一个表只能有一个排它锁(X)且锁不能共享,在获取排它锁时,表上不能有其它锁包括共享锁(S),只有在表上所有的锁都释放后,insert操作才能继续,否则处于等待状态。 对注意部分进行参数调整,将hive.lock.sleep.between.retries设置为10s,再次进行测试发现,在select语句执行完成后,大概过6s左右insert语句开始执行,通过两次测试发现,等待时间均在10s以内,由此可以得出此参数影响sql操作获取锁的间隔(在未获取到锁的情况下),如果此时未到获取锁触发周期,执行其它sql则,该sql会优于等待的sql执行。 4. 对test表执行insert的同时执行select操作 执行sql语句: insert into test values("test123",123); 操作步骤: 1) 在命令窗口执行insert语句,在insert操作未执行完成时,在新的命令窗口执行select语句,观察两个窗口的sql执行情况,insert语句正常执行,select语句处于等待状态。 2) 此时查看test表锁状态,只有insert操作获取的排它锁(X) 3) 在insert语句执行完成后,观察select语句开始正常执行,此时查看test表锁状态为共享锁(S),之前的insert操作获取的排它锁(X)已被释放 分析:在test表锁状态为排它锁(X)时,所有的操作均被阻塞处于等待状态,只有在排它锁(X)释放其它操作可继续进行。 5. 测试update和delete修改test表数据 sql语句: update test set name='aaaa' where id=1252; 1) 表中数据,更新前 2) 在beeline窗口执行update操作 执行update操作报错,异常提示“Attempt to do update or delete using transaction manager that does not support these operations”,在非事务模式下不支持update 和 delete。 4.1.2 关闭Concurrency 1. 执行insert操作的同时执行select操作 sql语句: insert into test_notransaction values(1,'peach1'),(2,'peach2'),(3, 'peach3'),(4, 'peach4'); 操作sql前,查看表数据 查看test_notransaction表获取情况,show locks; hive在未开启concurrency 的情况下,show locks不能正常获取表的锁,同时对同一张表执行insert和select操作时并发执行,获取数据取决于sql执行速度,因此在select 的时候未获取到插入数据。 2. 执行select操作的同时执行insert操作 sql语句: select count(*) from test_notransaction; insert into test_notransaction values(1,'peach1'),(2,'peach2'),(3, 'peach3'),(4, 'peach4'); 在执行select的同时执行insert操作,操作可以同时并行操作,未产生阻塞等待的过程。 3. 同时执行多条insert操作 sql语句: insert into test_notransaction values(1,'peach1'),(2,'peach2'),(3, 'peach3'),(4, 'peach4'); insert into test_notransaction values(1,'peach1'),(2,'peach2'),(3, 'peach3'),(4, 'peach4'); 同时执行insert操作时,可同时执行未产生阻塞等待的过程。 4. 执行update操作,将表中user_id为2的用户名修改为peach22 sql语句: update test_notransaction set name='peach22' where user_id=2; 执行update操作,执行结果如下: 在未配置hive的Transaction和ACID时,不支持update操作。 5. 执行delete操作,将表中user_id为1信息删除 sql语句: delete from test_notransaction where user_id=1; 执行delete操作,执行结果如下: hive未配置Transaction和ACID,不支持delete操作。 6. 查看表获取锁类型 show locks; 无法正常执行; 4.2 Hive的事务4.2.1 Hive的事务配置Hive从0.13开始加入了事务支持,在行级别提供完整的ACID特性,Hive在0.14时加入了对INSERT...VALUES,UPDATE,and DELETE的支持。对于在Hive中使用ACID和Transactions,主要有以下限制:
为了使Hive支持事务操作,需将以下参数加入到hive-site.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> 可以在Cloudera Manager进行以下配置: 为了让beeline支持还需要配置: ◆◆◆ 请点击“阅读全文”进入微站 (更多技术干货、行业动态,请关注【微站】,不定时更新) |
|