基礎
事務和ACID
何為事務澡腾?
事務就是一組單元化操作凯亮,這些操作要么都執(zhí)行,要么都不執(zhí)行须尚,是一個不可分割的工作單位崖堤。
事務(transaction)所應該具有的四個要素:原子性(Atomicity)、一致性(Consistency)耐床、隔離性(Isolation)密幔、持久性(Durability)。這四個基本要素通常稱為ACID特性撩轰。
- 原子性(Atomicity)
一個事務是一個不可再分割的工作單位胯甩,事務中的所有操作要么都發(fā)生,要么都不發(fā)生堪嫂。 - 一致性(Consistency)
事務開始之前和事務結(jié)束以后偎箫,數(shù)據(jù)庫的完整性約束沒有被破壞。這是說數(shù)據(jù)庫事務不能破壞關系數(shù)據(jù)的完整性以及業(yè)務邏輯上的一致性溉苛。 - 隔離性(Isolation)
多個事務并發(fā)訪問,事務之間是隔離的弄诲,一個事務不影響其它事務運行效果愚战。這指的是在并發(fā)環(huán)境中,當不同的事務同時操作相同的數(shù)據(jù)時齐遵,每個事務都有各自完整的數(shù)據(jù)空間寂玲。事務查看數(shù)據(jù)更新時,數(shù)據(jù)所處的狀態(tài)要么是另一事務修改它之前的狀態(tài)梗摇,要么是另一事務修改后的狀態(tài)拓哟,事務不會查看到中間狀態(tài)的數(shù)據(jù)。
事務之間的相應影響伶授,分別為:臟讀断序、不可重復讀流纹、幻讀、丟失更新违诗。 - 持久性(Durability)
意味著在事務完成以后漱凝,該事務鎖對數(shù)據(jù)庫所作的更改便持久的保存在數(shù)據(jù)庫之中,并不會被回滾诸迟。
ACID的實現(xiàn)原理
事務可以保證ACID原則的操作茸炒,那么事務是如何保證這些原則的?解決ACID問題的兩大技術點是:
- 預寫日志(Write-ahead logging)保證原子性和持久性
- 鎖(locking)保證隔離性
這里并沒有提到一致性阵苇,是因為一致性是應用相關的話題壁公,它的定義一個由業(yè)務系統(tǒng)來定義,什么樣的狀態(tài)才是一致绅项?而實現(xiàn)一致性的代碼通常在業(yè)務邏輯的代碼中得以體現(xiàn)紊册。
注:鎖是指在并發(fā)環(huán)境中通過讀寫鎖來保證操作的互斥性。根據(jù)隔離程度不同趁怔,鎖的運用也不同湿硝。
Hive的事務
Hive事務應用場景
Hive 0.13以前,原子性润努,一致性关斜,和持久性都只支持到分區(qū)的級別。隔離性可以通過zookeeper或內(nèi)存的鎖機制來實現(xiàn)铺浇。在0.13以后痢畜,Hive支持行級別的ACID語義,這樣一個應用在同一分區(qū)下可以添加數(shù)據(jù)行不會干擾其他應用的數(shù)據(jù)讀取鳍侣。
Hive的ACID語義可以完成以下使用場景
- 流數(shù)據(jù)的接入丁稀。許多用戶都使用 Apache Flume, Apache Storm, or Apache Kafka 將流式數(shù)據(jù)導入Hadoop集群。 這些工具都是每秒百萬行級的數(shù)據(jù)寫入倚聚,而Hive只能每十五分鐘到一個小時添加一次分區(qū)线衫。快速的增加分區(qū)會對表中的分區(qū)數(shù)量形成壓力惑折。當然可以事先創(chuàng)建好分區(qū)再將數(shù)據(jù)導入授账,但這樣會引起臟讀,而且目錄下生成的小文件會對namenode造成很大的壓力惨驶。而新特性可以很好的解決上述問題
- 減少維度的變化白热。 減少多維表的變化
- 數(shù)據(jù)的更新。INSERT, UPDATE
- 通過SQL MERGE 批量的更新粗卜。
限制條件
- BEGIN, COMMIT, ROLLBACK 暫時不支持屋确,所有操作自動提交
- 目前只支持ORC 的文件格式。參考:ORC File Format存儲格式 和 ORC file format
- 默認事務是關閉的,需要設置開啟
- 要是使用這些特性攻臀,表必須是分桶的
- 必須這是事務管理器 org.apache.hadoop.hive.ql.lockmgr.DbTxnManager 焕数,否則事務表無法工作
- 目前支持快照級別的隔離。就是當一次數(shù)據(jù)查詢時茵烈,會提供一個數(shù)據(jù)一致性的快照
- 已有的zookeeper和內(nèi)存的鎖管理和Hive的事務不沖突
- LOAD DATA. 語句目前在事務表中暫時不支持
流式APIs
Hive提供數(shù)據(jù)數(shù)據(jù)接入和修改的api
- Hive HCatalog Streaming API
- HCatalog Streaming Mutation API (available in Hive 2.0.0 and later)
語法上的修改
- 加入了 INSERT...VALUES, UPDATE, and DELETE 參考: LanguageManual DML
- SHOW TRANSACTIONS 百匆,顯示事務信息。Show Transactions
- SHOW COMPACTIONS呜投,顯示數(shù)據(jù)合并信息加匈。 Show Compactions
- SHOW LOCKS,顯示鎖信息仑荐。Show Locks
- ALTER TABLE雕拼,可以通過該命令來請求表和分區(qū)的的數(shù)據(jù)合并。一般情況下系統(tǒng)會自動發(fā)現(xiàn)并實施合并數(shù)據(jù)粘招,當合并數(shù)據(jù)關閉時啥寇,可以通過該命令開啟。Alter Table/Partition Compact
- ABORT TRANSACTIONS洒扎,丟棄事務辑甜。Abort Transactions
基礎設計
HDFS是不支持文件的修改,并且當有數(shù)據(jù)追加到文件袍冷,HDFS不對讀數(shù)據(jù)的用戶提供一致性的磷醋。為了在HDFS上支持以上的特性,我們借鑒了其他數(shù)據(jù)倉庫工具的方法胡诗。表和分區(qū)的數(shù)據(jù)都被存在base files邓线。 新的記錄和更新,刪除都存在delta files煌恢。一次事務操作創(chuàng)建一系列的delta files骇陈。在讀取的時候,將基礎文件和修改瑰抵,刪除合并你雌,最后返回給查詢。
Base and Delta Directories
如表t的base files and delta directory
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
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_00000Compactor
Compactor是運行Metastore 里以支持ACID的一系列的后臺操作二汛。它包括婿崭,Initiator, Worker, Cleaner, AcidHouseKeeperService等等。
可以通過SHOW COMPACTIONS的命令查看當前和最近合并的操作Delta File 合并
隨著對表的數(shù)據(jù)的修改习贫,會產(chǎn)生越來越多的delta files. 為了保持性能逛球,需要對這些文件進行合并千元。分為Minor compaction和Major compaction
Minor compaction :將已有的delta files重寫到一個單獨的delta file苫昌,每個分桶一個。
Major compaction: 將delta文件和base 重寫到一個新的base file,每個分桶一個祟身。 這個合并操作的代價更大奥务。
所有的合并操作都是后臺進行,不會影響并行的數(shù)據(jù)讀取和寫入袜硫。合并完成之后氯葬,系統(tǒng)會等到所以的讀操作完成再刪除舊的文件。Initiator(初始化器)
這個模塊負責發(fā)現(xiàn)表和分區(qū)中需要數(shù)據(jù)合并婉陷。這個可以在Metastore 中通過設置hive.compactor.initiator.on=true 進行開啟帚称。 在事務表的配置有一些屬性可以控制合并任務的數(shù)目,一個合并任務負責一個partition秽澳。同時也可以配置任務失敗時重試的次數(shù)闯睹。Worker
一個Worker處理一個合并任務,一個合并任務是一個MapReduce job担神。每個worker提交一個job給集群楼吃,并排隊處理。hive.compactor.worker.threads 確定每個Metastore中Worker的個數(shù)妄讯。Cleaner
該進程刪除合并之后不再需要的delta filesAcidHouseKeeperService
該進程檢查在 hive.txn.timeout 內(nèi)沒有心跳的事務并丟棄孩锡。對于一個初始化過事務的client,如果心跳停止了亥贸,它所鎖住的資源會被釋放躬窜。事務/鎖管理
與之前的庫/表/分區(qū)的鎖管理器(默認是:hive.lock.manager=org.apache.hadoop.hive.ql.lockmgr.zookeeper.ZooKeeperHiveLockManager)不同,hive引入了事務管理器砌函。 事務管理器是為了管理事務中的鎖斩披。在舊版本中默認的DummyTxnManager,不支持事務讹俊,通過使用hive.lock.manager屬性的配置垦沉,為庫/表/分區(qū)創(chuàng)建鎖管理器。而新加入的DbTxnManager 通過DbLockManager 在hive的metastore 中管理所有的鎖和事務仍劈。(鎖和事務的信息是持久化存儲的厕倍,即便server掛掉也不會有影響)這也意味著,一旦開啟式了事務贩疙,之前在zookeeper中的鎖行為也不在支持讹弯。為了防止客戶端因為掛掉而導致事務和鎖無法釋放,在鎖的持有者和事務的初始化器到server的metastore 間會維持一個周期性的心跳这溅。一旦心跳超時组民,鎖和事務就會被釋放。
從hive 1.30起悲靴,DbLockManger 持續(xù)獲取鎖的周期可以通過 hive.lock.numretires 和 hive.lock.sleep.between.retries. 兩個屬性設置臭胜。如果DbLockManger 獲取鎖失敗,過一段時間之后會進行重試。為了支持短查詢同時不對metastore造成負擔耸三,DbLockManger 在每次重試后加倍等待時長乱陡。
注意:DbTxnManager 可以獲取所有的表的鎖,即便那些沒有設置transactional=true屬性的表仪壮。默認對一個非事務表的插入操會獲取一個排他鎖從而阻止其他的插入和讀取憨颠。技術上正確的,但是這背離了hive之前的工作方式积锅。為了向后兼容爽彤,可以設置hive.txn.strict.locking.mode 屬性來使鎖管理器在對非事務表的插入操作時,獲取共享鎖缚陷。保留之前的語義淫茵,還有一個好處就是能防止表在讀取是被刪除。而對于事務表蹬跃,插入總是獲取的共享鎖匙瘪。是因為這些表實現(xiàn)了MVCC的架構(gòu),在存儲的底層實現(xiàn)了很強的讀一致性(快照隔離的方式)蝶缀,甚至能應對并發(fā)的修改操作丹喻。
(共享鎖【S鎖】
又稱讀鎖,若事務T對數(shù)據(jù)對象A加上S鎖翁都,則事務T可以讀A但不能修改A碍论,其他事務只能再對A加S鎖,而不能加X鎖柄慰,直到T釋放A上的S鎖鳍悠。這保證了其他事務可以讀A,但在T釋放A上的S鎖之前不能對A做任何修改坐搔。
排他鎖【X鎖】
又稱寫鎖藏研。若事務T對數(shù)據(jù)對象A加上X鎖,事務T可以讀A也可以修改A概行,其他事務不能再對A加任何鎖蠢挡,直到T釋放A上的鎖。這保證了其他事務在T釋放A上的鎖之前不能再讀取和修改A凳忙。)
具體的鎖操作細節(jié)业踏,參考:Hive事務管理避坑指南
配置
為了開啟hive的事務支持,以下是需要開啟的最少的hive配置:
- 客戶端
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 – a positive number
表屬性
如果一個表需要使用ACID 的數(shù)據(jù)操作涧卵,表屬性一定要設置 "transactional=true" 勤家,一旦被設置為事務表是不可以被撤銷的。
如果不需要系統(tǒng)對表進行數(shù)據(jù)合并柳恐,可以設置表屬性 "NO_AUTO_COMPACTION"伐脖。 通過可以通過Alter Table/Partition Compact 命令手動處理合并
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", -- MRjob的屬性
"compactorthreshold.hive.compactor.delta.num.threshold"="4", -- 超過4個deta目錄觸發(fā)小合并
"compactorthreshold.hive.compactor.delta.pct.threshold"="0.5" -- 如果deta文件的大小超過base文件的50%觸發(fā)大合并
);
ALTER TABLE table_name COMPACT 'minor'
WITH OVERWRITE TBLPROPERTIES ("compactor.mapreduce.map.memory.mb"="3072");
ALTER TABLE table_name COMPACT 'major'
WITH OVERWRITE TBLPROPERTIES ("tblprops.orc.compress.size"="8192");
參考文章:
Hive事務管理避坑指南
Hive Transactions
Streaming Data Ingest
HCatalog Streaming Mutation API
HCatalog UsingHCat