Hive ACID和事務表支持詳解


 

一、ACID介紹

ACID就是常見數據庫事務的四大特性:Atomicity(原子性)、Consistency(一致性)、Isolation(隔離性)、Durability(持久性)。

在Hive 0.13之前,Hive支持分區級別上原子性、一致性、持久性,隔離性可以通過hive提供的鎖機制來實現(通過zookeeper鎖或者內存鎖來鎖住一個分區的數據)。從Hive 0.13開始,Hive可以支持行級別上面的ACID語義了。因此我們可以在有其他程序讀取一個分區數據時往這個分區插入新的數據。

二、使用限制

  1. 不支持 BEGIN、COMMIT、ROLLBACK 等語句,所有的語句都是自動提交
  2. 僅支持ORC格式
  3. 事務的支持默認是關閉的,需要配置相關參數打開
  4. 表需要配置分桶,外部表不能設置成事務表,因為外部表的文件存儲格式不在hive的管理之中。(因為Hive事務的實現主要依賴於表分桶的存儲格式,如果表沒分桶,那么表底下的文件就會很散亂,hive的事務機制無法有效的讀取)
  5. 非 ACID 的會話不能讀寫ACID表,也就是說,需要在會話中手動set參數開啟hive事務管理支持后才可以操作ACID表
  6. 目前僅支持快照隔離級別,不支持臟讀、讀已提交、可重復讀、串行等隔離級別
  7. 現有的zk和內存鎖和事務不兼容
  8. 使用oracle作為metastore數據庫,以及設置了"datanucleus.connectionPoolingType=BONECP"的話,會導致一些間斷性的"No such lock.." 和 "No such transaction..."錯誤,這種情況建議將配置改成"datanucleus.connectionPoolingType=DBCP"
  9. 事務表不支持 LOAD DATA... 語句(在2.4.0 之前並沒有被禁止,語句還是可以執行的),主要還是由於LOAD DATA的方式加載數據會導致表中的數據文件格式亂掉,其實分桶表理論上也是不允許load data語句加載數據的。

三、支持的一些新的語法

  1. INSERT...VALUES 語句
  2. UPDATE 語句
  3. DELETE 語句
  4. SHOW TRANSACTIONS 語句,用於展示目前正在運行的所有事務
  5. SHOW COMPACTIONS 語句,用於展示目前正在運行的所有壓縮任務

四、主要設計和實現

HDFS本身是不支持直接修改文件的,也不能保證有人追加內容時的讀一致性。因此,為了支持ACID的特性,Hive只能使用其他數據倉庫常用的方法,也就是增量的形式記錄更新和刪除(也稱做讀時更新)。

存儲在事務表中的數據會被分成兩種類型的文件:

  1. base文件,用來存放平常的數據
  2. delta文件,用來存儲新增、更新、刪除的數據。每一個事務處理數據的結果都會單獨新建一個delta文件夾用來存儲數據

(會有定時任務定期的將delta文件合並成base文件,后面會詳細介紹)

在有用戶要讀取這個表的數據時,就會將base文件和delta文件都讀取到內存,然后進行合並(就是判斷哪些記錄有被修改,哪些記錄被刪除等)。

base和delta文件夾的基本結構

假設有一張表名為t,分桶數量只有2的表,那它表的數據結構可能如下:

hive> dfs -ls -R /user/hive/warehouse/t; drwxr-xr-x - ekoifman staff 0 2016-06-09 17:03 /user/hive/warehouse/t/base_0000022 -rw-r--r-- 1 ekoifman staff 602 2016-06-09 17:03 /user/hive/warehouse/t/base_0000022/bucket_00000 -rw-r--r-- 1 ekoifman staff 602 2016-06-09 17:03 /user/hive/warehouse/t/base_0000022/bucket_00001 drwxr-xr-x - ekoifman staff 0 2016-06-09 17:06 /user/hive/warehouse/t/delta_0000023_0000023_0000 -rw-r--r-- 1 ekoifman staff 611 2016-06-09 17:06 /user/hive/warehouse/t/delta_0000023_0000023_0000/bucket_00000 -rw-r--r-- 1 ekoifman staff 611 2016-06-09 17:06 /user/hive/warehouse/t/delta_0000023_0000023_0000/bucket_00001 drwxr-xr-x - ekoifman staff 0 2016-06-09 17:07 /user/hive/warehouse/t/delta_0000024_0000024_0000 -rw-r--r-- 1 ekoifman staff 610 2016-06-09 17:07 /user/hive/warehouse/t/delta_0000024_0000024_0000/bucket_00000 -rw-r--r-- 1 ekoifman staff 610 2016-06-09 17:07 /user/hive/warehouse/t/delta_0000024_0000024_0000/bucket_00001 

其中delta_0000023_0000023_0000中,0000023表示對應事務的ID,0000表示序號。

從上面的表中我們可以看到有兩個事務的數據還未合並成base。

事務表的讀取

假設我們要讀取上面表”t“的數據,由於它的分桶數量是2,因此正常情況下,它的並行度應該也是2。

hive會啟動兩個task,一個task讀取base_0000022/bucket_00000、delta_0000023_0000023_0000/bucket_00000、delta_0000024_0000024_0000/bucket_00000然后進行合並,另一個task則讀取base_0000022/bucket_00001、delta_0000023_0000023_0000/bucket_00001、delta_0000024_0000024_0000/bucket_00001然后進行合並。所以和正常的表相比,事務表在讀取分桶數據時需要再讀取delta文件夾下面對應分桶數據。因此我們也要保證delta文件的數量不會太大太多,這就需要delta文件的壓縮機制了。

delta文件的壓縮

Compactor是一個在Hive Metastore上運行的一系列后台線程,主要包括Initiator, Worker, Cleaner, AcidHouseKeeperService 以及一些其他的組件。

1、 壓縮類型

  • minor 壓縮:將多個delta文件合並成一個delta文件 (維度是分桶級別)
  • major 壓縮:將多個delta文件和base文件合並成一個新的base文件 (維度是分桶級別)

所有的壓縮任務都在后台運行,並且不會影響到數據的讀寫。當壓縮完,壓縮任務會等待舊文件的讀取完畢后才刪除該舊文件。(由於讀取的時候需要指定一系列的事務id然后進行讀取,因此因合並而生成的base文件或者delta文件並不會被讀者看到並誤讀)

2、Initiator 組件

這個組件主要是用於發現哪些表或者分區需要進行壓縮。這個組件需要修改Metastore中的配置hive.compactor.initiator.on來開啟。同時Hive新提供了幾個" *.threshold"的參數用於判斷是否要對表/分區進行壓縮以及進行哪種類型的壓縮。一個壓縮任務只會壓縮一個分區(如果表沒有分區那就是直接壓縮表的數據),如果對一個分區壓縮失敗次數達到了 hive.compactor.initiator.failed.compacts.threshold 的次數,那么后面將不會再對該分區進行壓縮。

3、 Worker

每個Worker對應一個壓縮任務。這個壓縮任務其實就是一個MapReduce任務,任務名稱格式為 <hostname>-compactor-<db>.<table>.<partition>。Worker會提交MapReduce任務到集群,並等待該任務完成(可以通過hive.compactor.job.queue指定提交的隊列)。

hive.compactor.worker.threads 決定了有多少個任務運行在每個Metastore實例中。整個Hive集群的Worker數量決定了整個壓縮任務的並行度。

4、Cleaner

整個組件是用來刪除壓縮完的delta文件的,另外,如果一個delta文件被認為不再需要了,也會被這個組件刪除。

5、 AcidHouseKeeperService

這個組件主要用來監聽事務開啟后客戶端的心跳,如果客戶端在開啟一個事務后,有 hive.txn.timeout 時間沒有發送心跳過來,這個組件就會關閉這個事務並釋放相關的鎖。

6、 SHOW COMPACTIONS

這個命令可以列出正在運行的壓縮任務的信息以及近期的一些歷史任務的信息。

事務表的隱藏字段

如果我們直接用orc api讀取事務表的數據文件,會發現hive在事務表中添加了很多隱藏字段。假設我們創建一個表,有兩個id和name兩個字段,這時候我們讀取該表的某個數據文件,會發現各字段列如下:

operation
originalTransaction
bucket
rowId
currentTransaction
row

其中row字段是一個struct類型,包含的就是我們實際的字段。另外,operation=0表示是新增數據,operation=1表示更新,operation=2表示刪除的數據。

我們再把他的schema直接輸出,可以看到:

struct<
    operation:int, originalTransaction:bigint, bucket:int, rowId:bigint, currentTransaction:bigint, row:struct< _col1:int, _col2:string > > 

所以事務表的每一條數據都會存儲它的事務id,行號、以及分桶id。

五、相關配置

要開啟對事務表的支持,我們至少需要修改以下的配置:

客戶端方面的修改

(會話中設置或者修改HiveServer2的配置文件):

  • hive.support.concurrency – true
  • hive.enforce.bucketing – true (Hive 2.0之后就不用專門設置了)
  • hive.exec.dynamic.partition.mode – nonstrict
  • hive.txn.manager – org.apache.hadoop.hive.ql.lockmgr.DbTxnManager

服務端方面

主要修改MetaStore上的配置

  • hive.compactor.initiator.on – true
  • hive.compactor.worker.threads – 壓縮任務的數量

為事務新增的相關配置

https://cwiki.apache.org/confluence/display/Hive/Hive+Transactions#HiveTransactions-NewConfigurationParametersforTransactions

一些舊的配置修改

Configuration key Must be set to
hive.enforce.bucketing true (default is false) (Hive 2.0 開始就不需要了)
hive.exec.dynamic.partition.mode nonstrict (default is strict)
hive.support.concurrency true (default is false)

六、事務表的創建

注意,事務表創建后就不能再改成非事務表了。並且需要在會話中設置 ”hive.txn.manager=org.apache.hadoop.hive.ql.lockmgr.DbTxnManager “后,才可以對事務表進行增刪改查。

如果不想事務表自動繼續內壓縮,可以在創建事務表時添加配置"NO_AUTO_COMPACTION"。

下面是創建一個事務表的demo:

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", -- specify compaction map job properties "compactorthreshold.hive.compactor.delta.num.threshold"="4", -- trigger minor compaction if there are more than 4 delta directories "compactorthreshold.hive.compactor.delta.pct.threshold"="0.5" -- trigger major compaction if the ratio of size of delta files to -- size of base files is greater than 50% ); 

針對事務表的壓縮類型進行一些修改

ALTER TABLE table_name COMPACT 'minor' WITH OVERWRITE TBLPROPERTIES ("compactor.mapreduce.map.memory.mb"="3072"); -- specify compaction map job properties ALTER TABLE table_name COMPACT 'major' WITH OVERWRITE TBLPROPERTIES ("tblprops.orc.compress.size"="8192"); -- change any other Hive table properties 

七、一些問題的解答

1. 執行update、delete會生成job提交到集群嗎?性能如何,能否hold住大量的更新操作?

可以把每次的UPDATE和DELETE操作理解為一次查詢然后寫入一個新的文件的過程。因此如果涉及大量的修改刪除操作,性能可能會很差。

2. 隱藏字段會導致數據文件變大,增量是多少?

因為隱藏字段大多都是int類型,在orc文件中壓縮比會很好,因此實際並不會占用太大空間。

做了個測試,100M的數據文件大概會因為隱藏字段而膨脹到120M,增量大概是20%。

3. 什么場景下適合用這個特性?

如果對於行級更新刪除需求比較頻繁的,可以考慮使用事務表,但平常的hive表並不建議使用事務表。因為事務表的限制很多,加上由於hive表的特性,也很難滿足高並發的場景。

另外,如果事務表太多,並且存在大量的更新操作,metastore后台啟動的合並線程會定期的提交MapReduce Job,也會一定程度上增重集群的負擔。

所以,結論是,除非有非常迫切的行級更新需求,又只能用hive表來做,才需要去考慮事務表。

4. 目前Hive ACID的活躍度如何?

社區不是很活躍,雖然hive從0.13就開始支持ACID了。但是現在Hive版本已經到3.x了,根據在調研過程搜索到的資料來看,真正用的人應該不會太多。

八、參考資料



作者:瘋狂的哈丘
鏈接:https://www.jianshu.com/p/b4a8011b2b5d
來源:簡書
簡書著作權歸作者所有,任何形式的轉載都請聯系作者獲得授權並注明出處。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM