Hive 並發模型
使用案例
並發支持 (http://issues.apache.org/jira/browse/HIVE-1293) 是數據庫的必須,而且他們的使用案例很好懂。至少,我們要盡可能支持並發讀和寫。添加幾個發現當前已經鎖定的鎖,是有用的。這里沒有一個直接的需求添加一個API顯式獲取鎖,所以,所有鎖都是隱式獲取的。
hive定義一下模式的鎖(注意不需要意向鎖)
- 共享 (S)
- 排他 (X)
見名知意,多個共享鎖可以同時獲取,而排他鎖會阻塞其他鎖。
兼容性列表如下:
|
Existing Lock | S | X |
Requested Lock |
|
|
|
S |
|
True | False |
X |
|
False | False |
對於一些操作,鎖的性質是有層次的。例如,一些分區操作,表也是被鎖定(例如,保證表的分區正在創建時,表不能被刪除)
鎖模式獲取背后的原理如下:
對於非分區表,鎖定模式相當直觀。當表正在讀取時,一個S鎖被獲取。而對其他操作(插入數據到表,修改表的任何屬性)就要獲取X鎖。
對於分區表,原理如下:
當讀取表分區時,會獲取表的S鎖。對於其他操作,會獲取分區的X鎖。但是,如果修改僅僅是針對新分區,就會獲取表的S鎖,而修改是針對所有分區,會獲取表的X鎖。
所以,當舊分區讀寫時,新分區也可以被轉換為RCFile。
無論何時,分區被鎖定時,會獲取所有的它的父節點的S鎖。
基於這,操作的鎖獲取如下:
Hive Command | Locks Acquired |
select .. T1 partition P1 | S on T1, T1.P1 |
insert into T2(partition P2) select .. T1 partition P1 | S on T2, T1, T1.P1 and X on T2.P2 |
insert into T2(partition P.Q) select .. T1 partition P1 | S on T2, T2.P, T1, T1.P1 and X on T2.P.Q |
alter table T1 rename T2 | X on T1 |
alter table T1 add cols | X on T1 |
alter table T1 replace cols | X on T1 |
alter table T1 change cols | X on T1 |
alter table T1 add partition P1 | S on T1, X on T1.P1 |
alter table T1 drop partition P1 | S on T1, X on T1.P1 |
alter table T1 touch partition P1 | S on T1, X on T1.P1 |
*alter table T1 set serdeproperties * | S on T1 |
*alter table T1 set serializer * | S on T1 |
*alter table T1 set file format * | S on T1 |
*alter table T1 set tblproperties * | X on T1 |
drop table T1 | X on T1 |
為了避免死鎖,這里提出一個非常簡單的計划.所有鎖定的對象按照字典排序,然后在按照鎖定模式獲取。注意一些場景,對象列表可能不知道——例如,動態分區,編譯時不知道正在修改的分區列表。所以,列表會保守生成,由於分區的數量可能不知道,所以會在表或所知的前綴上獲取排他鎖。
添加兩個可配置的參數,決定鎖嘗試時,鎖嘗試次數和等待時間。如果重試的次數是非常高的,它可以導致一個活鎖。參考zookeeper recipes(http://hadoop.apache.org/zookeeper/docs/r3.1.2/recipes.html#sc_recipes_Locks),理解如何使用zookeeper apis實現read/write鎖。需要注意的是,不是等待的鎖請求將被拒絕。存在的鎖將會釋放,然后等待的鎖會在嘗試周期后繼續嘗試。
因為鎖的分層特性,上面列出的規定recipe將無法正常工作:
表T的S鎖規定如下:
調用create( ),創建一個路徑名為"/warehouse/T/read-"的節點。協議中,這個鎖定的節點會在后面使用。保證設置序列和臨時標志。
在鎖定的節點調用getChildren( ),不設置watch的標記
如果已經有一個子節點,路徑名以"write-"和一個更小的序列號數字開頭,已經被獲取了,那么這個鎖不能被獲取。刪除第一步驟創建的節點,返回。
否則授權鎖。
表T的X鎖規定如下:
調用create( ),創建一個路徑名為"/warehouse/T/write-"的節點。協議中,這個鎖定的節點會在后面使用。保證設置序列和臨時標志。
在鎖定的節點調用getChildren( ),不設置watch的標記
如果已經有一個子節點,路徑名以"read-"或者"write-"和一個更小的序列號數字開頭,已經被獲取了,那么這個鎖不能被獲取。刪除第一步驟創建的節點,返回。
否則授權鎖。
擬定的計算,為了讀飢餓了寫,如果遇到長時間的讀,會導致寫的飢餓。
這個默認hive行為不會改變,並發不會支持。
關閉並發
關閉並發,可以修改下面的變量為false: hive.support.concurrency
調試
查看表的鎖,可以執行下面的命令:
SHOW LOCKS <TABLE_NAME>; SHOW LOCKS <TABLE_NAME> extended; SHOW LOCKS <TABLE_NAME> PARTITION (<PARTITION_DESC>); SHOW LOCKS <TABLE_NAME> PARTITION (<PARTITION_DESC>) extended;
翻譯自 https://cwiki.apache.org/confluence/display/Hive/Locking