上一篇介紹了Phoenix基於HBase的二級索引的基本知識,這一篇介紹一下和索引相關的一致性和優化相關內容。
一致性的保證
Phoenix客戶端在成功提交一個操作並且得到成功響應后,就代表你所做的操作已經成功應用到原表和相關的索引表中。換句話說,索引表的維護和處理原表數據是同步的,並且各自是強一致性保證的。但是因為索引表和原表是在不同的表中,根據表的屬性和索引的類型,當服務端崩潰導致一次提交失敗時,原表和索引表中的數據就會有一些變化。所以在使用二級索引的時候,就要根據需求個用例充分考慮。
下面列出了一些不同級別的一致性保證供你選擇。
1. 事務表
如果把表定義成事務表(Transactional),你將獲得最高級別的一致性保證。原表的操作和索引表的操作完全就是一個原子操作。如果提交失敗,原表和索引表的數據都不會被更新,如果啟用了這種級別的一致性,你的原表和索引表永遠都保持同步。目前這個功能還是beta版本階段,它是實現依賴於另一個Apache項目Apache Tephra。它是一個分布式事務框架。
那為什么不把所有的表都設置能事務的呢?特別是一些被聲明了是不可變的表(只寫一次,不修改的表),因為這個時候事務的損耗是非常小的。但是一旦你的表中的數據會變化,那么你就要承擔一些沖突檢測和事務管理器的開銷;同時做事務表中建二級索引,會潛在的降低系統的可用性,因為原表和二級索引表都必須可用行,不然都會失敗。
2. 不可變表
不可變表中的數據之寫入一次,之后就再也不會被更新了。對於這種表,Phoenix會做特別的優化,降低寫入的損耗和增量維護的損耗。這類數據通常就是一些時間序列的數據,比如日志、事件、或者傳感器的周期數據等等。這類表結構需要在見表的時候加上 IMMUTABLE_ROWS=true 語句,這樣數據表就會被優化。默認建表是可變的。
CREATE TABLE HAO2 (k VARCHAR PRIMARY KEY, v VARCHAR) IMMUTABLE_ROWS=true;
在不可變表上面建的所有的索引都是不可變的。對於全局的不可變索引來說,索引全部由客戶端來維護,原表的數據變化會觸發索引的修改。本地索引在服務端維護。需要注意的是,Phoenix沒有強制在一張申明了不可變的原表上修改數據,索引將不再與原表同步。
如果你有一個已經存在的表,想把不可變索引修改成可變索引的話,可以用如下語句實現:
alter table HAO2 set IMMUTABLE_ROWS = false;
另外,非事務性、不可變表的索引沒有自動處理提交失敗的機制。保持表和索引之間的一致性留給客戶端處理。因為更新是冪等的,最簡單的解決方案是客戶端不斷嘗試直到成功。
3. 易變的表
對於非事務的可變表,我們通過添加索引更新到原表的WAL日志里來維護索引信息的更新。只有當WAL同步后,才會去真的更新索引或原表。Phoenix寫索引文件是並行的,這樣有助於性能的提高,吞吐量增大。如果我們正在更新索引的時候,服務器掛了,我們會找到對應的WAL,重新執行所有的更新。更新的冪等性保證了數據的准確性。
不過需要注意一下幾點:
1. 由於是非事務表,有時候也可能出現原表和索引表的數據不同步。
2. 就像上文所說,Phoenix是有可能在很短暫的時間里數據和索引不一致的,但是這是一個很短的過程,一般來說不會有影響。
3. HBase保證了每一個數據行或索引行都保證要么寫入,要么丟失,你不可能看到一條數據有部分列寫入而部分列沒有寫入。
4. 數據是先入HBase原表,然后再插入索引表。
為了保證易變的表和索引同步,Phoenix主要提供三種級別:
1. 如果不一致,禁止原表寫入
這是最高級別的一致性級別,需要也別設置。當索引表更新出錯的時候,原表會暫時禁用,不能寫或更新數據。這個時候索引會自動重建,等索引和原表同步后,索引和原表才能恢復使用。
主要有兩個配置項配置在服務端:
- phoenix.index.failure.block.write:是否禁止原表的寫入,這個需要設置成true,不然索引的重建追不上原表數據的增加。
- phoenix.index.failure.handling.rebuild:默認true,在索引表出錯后,是否自動啟動后台任務,重建索引。
2. 如果不一致,禁用索引表
這是Phoenix的默認級別。如果寫入索引表失敗,索引表會標記成失效並且禁用索引,然后啟動后台任務重建部分索引,等到完成之后再次激活索引。這種級別下,索引的失效和重建不會影響HBase原表的操作,只是在查詢的時候索引不能使用了。
主要有二個服務端配置項:
- phoenix.index.failure.handling.rebuild:默認是true,是否在索引操作失敗后自動后台重建索引。
- phoenix.index.failure.handling.rebuild.interval:檢測是否要部分重建索引的時間間隔,多少毫秒檢測一次。默認值是:10000,也就是10秒。
3. 如果不一致,需要人工重建索引
這是最低級別的同步策略。如果寫入索引失敗,Phoenix不會自動重建,而是需要人工命令重建索引。
服務端配置如下:
- phoenix.index.failure.handling.rebuild:需要設置成false,不自動重建。
索引重建
Phoenix的索引重建是把索引表清空后重新裝配數據。入上文所說,重建有可能是某個操作失敗后系統后台自動的行為,也可以是人工來重建。人工重建的語法如下:
alter index index1_local on hao1 rebuild;
索引性能調優
一般來說,索引已經很快了,不需要特別的優化。這里也提供了一些方法,讓你在面對特定的環境和負載的時候可以進行一些調優。下面的這些需要在hbase-site.xml文件中設置,針對所有的服務器。
1. index.builder.threads.max
創建索引時,使用的最大線程數。
默認值: 10。
2. index.builder.threads.keepalivetime
創建索引的創建線程池中線程的存活時間,單位:秒。
默認值: 60
3. index.writer.threads.max
寫索引表數據的寫線程池的最大線程數。
更新索引表可以用的最大線程數,也就是同時可以更新多少張索引表,數量最好和索引表的數量一致。
默認值: 10
4. index.writer.threads.keepalivetime
索引寫線程池中,線程的存活時間,單位:秒。
默認值:60
5. hbase.htable.threads.max
每一張索引表可用於寫的線程數。
默認值: 2,147,483,647
6. hbase.htable.threads.keepalivetime
索引表線程池中線程的存活時間,單位:秒。
默認值: 60
7. index.tablefactory.cache.size
允許緩存的索引表的數量。
增加此值,可以在寫索引表時不用每次都去重復的創建htable,這個值越大,內存消耗越多。
默認值: 10
8. org.apache.phoenix.regionserver.index.handler.count
處理全局索引寫請求時,可以使用的線程數。
默認值: 30