【phoenix-開發(fā)】phoenix構建二級索引及探索

官網(wǎng):http://phoenix.apache.org/secondary_indexing.html
測試環(huán)境:phoenix4.14.1 hbase1.1.1

一、索引配置

建立非事務性、可變索引表需要在hbase-site.xml添加如下配置:

<property>
    <name>hbase.regionserver.wal.codec</name>
    <value>org.apache.hadoop.hbase.regionserver.wal.IndexedWALEditCodec</value>
</property>
<property>
    <name>hbase.region.server.rpc.scheduler.factory.class</name>
    <value>org.apache.hadoop.hbase.ipc.PhoenixRpcSchedulerFactory</value>
    <description>Factory to create the Phoenix RPC Scheduler that uses separate queues for index and metadata updates</description>
</property>
<property>
    <name>hbase.rpc.controllerfactory.class</name>
    <value>org.apache.hadoop.hbase.ipc.controller.ServerRpcControllerFactory</value>
    <description>Factory to create the Phoenix RPC Scheduler that uses separate queues for index and metadata updates</description>
</property>

注意:
若hive整合了hbase,需要在hive的lib中添加phoenix-core-x.x.x-HBase-x.x.jar,否則在創(chuàng)建hive映射hbase的表時報如下錯:
Caused by: java.lang.ClassNotFoundException: org.apache.hadoop.hbase.ipc.controller.ServerRpcControllerFactory

在phoenix4.8以下還需添加如下配置:

<property>
    <name>hbase.master.loadbalancer.class</name>
    <value>org.apache.phoenix.hbase.index.balancer.IndexLoadBalancer</value>
</property>
<property>
    <name>hbase.coprocessor.master.classes</name>
    <value>org.apache.phoenix.hbase.index.master.IndexMasterObserver</value>
</property>
<property>
    <name>hbase.coprocessor.regionserver.classes</name>
    <value>org.apache.hadoop.hbase.regionserver.LocalIndexMerger</value>
</property>

二、索引介紹

  1. 全局索引
    全局索引為默認索引類型。適用于大量讀少量寫的場景,由于全局索引會攔截(DELETE, UPSERT VALUES and UPSERT SELECT)數(shù)據(jù)更新并更新索引表,而索引表是分布在不同的數(shù)據(jù)節(jié)點上的,跨節(jié)點的數(shù)據(jù)傳輸帶來了較大的性能消耗。
CREATE INDEX my_index ON my_table (v1,v2)

注意
1、假設數(shù)據(jù)表tb1(A pk,B,C,D,E) 創(chuàng)建全局索引表tb_idx(B,C),若查詢列(select B,C,D)包含非索引列D則該查詢不會走索引表??梢越?strong>覆蓋索引tb_idx(B,C)include(D)或 使用本地索引 或 用Hint 強制指定走索引,eg:SELECT /*+ INDEX(my_table my_index) */ v2 FROM my_table WHERE v1 = 'foo'
2、本段摘自:https://m.aliyun.com/yunqi/articles/633486?spm=a2c4e.11155435.0.0.d6644db40AFswl
創(chuàng)建如下組合索引。之前我們已經(jīng)提到索引表中的Row key是字典序存儲的,什么樣的查詢適合這樣的索引結構呢?
CREATE INDEX B_C_D_IDX ON DATA_TABLE(B,C,D);
所有字段條件以=操作符為例:


注:上表查詢中and條件不一定要和索引組合字段順序一致,可以任意組合。
在實際使用中我們也只推薦使用1 ~ 4,遵循前綴匹配原則,避免觸發(fā)掃全表。5 ~ 7條件就要掃描全表數(shù)據(jù)才能過濾出來符合這些條件的數(shù)據(jù),所以是極力不推薦的。

其它
  • 對于order by字段或者group by字段仍然能夠使用二級索引字段來加速查詢。
  • 盡量通過合理的設計數(shù)據(jù)表的主鍵規(guī)避建更多的索引表,因為索引表越多寫放大越嚴重。
  • 使用了ROW_TIMESTAMP特性后不能使用全局索引
  • 對索引表適當是的使用加鹽特性能提升查詢寫入性能,避免熱點。
  1. 本地索引
    本地索引適用于少讀多寫的場景,因為本地索引的索引數(shù)據(jù)和表數(shù)據(jù)共同駐留在同一服務器上,防止寫操作期間出現(xiàn)任何網(wǎng)絡開銷。與全局索引不同,即使查詢中引用的所有列不在索引中也本地索引將使用索引表。因為默認情況下,表和索引數(shù)據(jù)位于同一區(qū)域服務器的核心,因此可以確保查找是本地的。
CREATE LOCAL INDEX my_index ON my_table (v1)
  1. 覆蓋索引
    覆蓋索引是基于全局索引和本地索引的擴展。創(chuàng)建索引時將查詢需要返回的列包含(include),此時被包含的列也會被寫進索引表。索引列和原rowkey拼接作為索引表rowkey,被包含的列做為索引表的列,列簇名和原表相同。查詢數(shù)據(jù)時匹配到索引表后直接返回數(shù)據(jù),不用再去查詢原表。
CREATE INDEX my_index ON my_table (v1,v2) INCLUDE(v3)

存儲結構示例:


  1. 函數(shù)索引
    函數(shù)索引也是基于全局索引和本地索引的擴展?;赑hoenix封裝的函數(shù)(function)表達式構建索引,以改函數(shù)表達式結果和原rowkey拼接作為索引表rowkey。
CREATE INDEX UPPER_NAME_IDX ON EMP (UPPER(FIRST_NAME||' '||LAST_NAME))
# 查詢使用
SELECT EMP_ID FROM EMP WHERE UPPER(FIRST_NAME||' '||LAST_NAME)='JOHN DOE'

存儲結構示例:


三、索引狀態(tài)

索引表狀態(tài)有如下幾種,在SYSTEM.CATALOG表中可以查看,或者使用!tables命令時可以查看到。

狀態(tài)名 描述
DISABLE ("x") 索引將處于不可用的維護狀態(tài),同時將不能用于查詢中。
REBUILD ("r") 索引將完成重建,同時一旦重建完成此索引將能被在此用于查詢中。
BUILDING ("b") 將從索引不可用的時間戳處重建索引直到重建完成。
INACTIVE ("i") / UNUSABLE ("d") 索引不能用于查詢中,但索引仍然在不可用的維護狀態(tài)。
ACTIVE ("a")/USABLE ("e") 索引表能被正常使用于查詢中。
PENDING_ACTIVE (phoenix 4.11+)索引處于自動rebuild狀態(tài)中,即將轉換為active狀態(tài)。
PENDING_DISABLE (phoenix 4.11+)寫索引失敗,正在進行重試操作,即將轉換為disable狀態(tài)。
參考來自阿里瑾謙同學的圖

注意:必須維持索引表處于active狀態(tài),才能確保索引數(shù)據(jù)的完整一致。

四、異步索引

默認情況下創(chuàng)建的索引表是同步的,在數(shù)據(jù)量大的情況下是不可行的。從4.5開始,索引的初始填充可以通過在索引創(chuàng)建DDL語句中包含ASYNC關鍵字來異步完成。必須通過以下兩步才能完成異步索引的構建。
第一步:

CREATE INDEX async_index ON my_schema.my_table (v) ASYNC

另外,填充索引表的map reduce作業(yè)必須通過HBase命令行單獨啟動。只有當map reduce作業(yè)完成時,索引才會被激活并開始在查詢中使用。作業(yè)對于客戶端退出是有彈性的可恢復的。output-path選項用于指定用于將HFiles寫入的HDFS目錄。
第二步:

${HBASE_HOME}/bin/hbase org.apache.phoenix.mapreduce.index.IndexTool
  --schema MY_SCHEMA --data-table MY_TABLE --index-table ASYNC_IDX
  --output-path ASYNC_IDX_HFILES

實例:

hbase org.apache.phoenix.mapreduce.index.IndexTool --schema TEST2 --data-table SIMUL_DAY_ELEC_OUT --index-table SIMUL_DAY_ELEC_OUT_INDEX --output-path ASYNC_IDX_HFILES

Build同步全局索引,如數(shù)據(jù)量較大需要在客戶端配置如下超時參數(shù),防止因為鏈接超時中斷:
1、 phoenix.query.timeoutMS
2、 hbase.rpc.timeout
3、 hbase.client.scanner.timeout.period
或者使用異步索引。

異步索引表遇到的一些問題

五、不可變索引

對于數(shù)據(jù)只寫入一次且從未就地更新的表,可以建立非可變表進行優(yōu)化,以減少增量維護的寫入時開銷。
通過IMMUTABLE_ROWS=true屬性開啟不可變表。

CREATE TABLE my_table (k VARCHAR PRIMARY KEY, v VARCHAR) IMMUTABLE_ROWS=true

修改不可變表為可變表

ALTER TABLE my_table SET IMMUTABLE_ROWS=false

使用IMMUTABLE_ROWS=true聲明的表上的所有索引都被認為是不可變的(注意,默認情況下,表被認為是可變的)。對于全局不可變索引,索引完全在客戶端上維護,當數(shù)據(jù)表發(fā)生更改時生成索引表。另一方面,本地不可變索引是在服務器端維護的。請注意,沒有適當?shù)谋Wo措施來強制聲明為不可變的表實際上不會改變數(shù)據(jù)(因為這會抵消所獲得的性能收益)。如果不可變的表發(fā)生數(shù)據(jù)更改,索引將不再同步。、

總結:Mutable表的索引同步是在server端完成,適用于索引強一致要求,索引數(shù)據(jù)有更新的業(yè)務需求。Immutable表索引同步在客戶端維護,索引數(shù)據(jù)無更新,適用于時序、日志數(shù)據(jù)場景。

六、索引一致性

對于非事務性可變表,我們通過將索引更新添加到主表行的Write-Ahead-Log (WAL)條目來維護索引更新的持久性。只有在成功地將WAL條目同步到磁盤之后,我們才嘗試更新索引/主表。默認情況下,我們并行編寫索引更新,這導致了非常高的吞吐量。如果在編寫索引更新時服務器崩潰,我們將在WAL恢復過程中將所有索引更新重放到索引表中,并依賴于更新的冪等性來確保正確性。因此,非事務性可變表上的索引只在主表后面進行過一次批量編輯。(前提:開啟WAL)

三種級別一致性保證方式
a、禁止表寫,直到可變索引是一致的(最高級別)
更新索引失敗的情況下,應該暫時禁用對數(shù)據(jù)表的寫入直到索引恢復聯(lián)機并與數(shù)據(jù)表同步為止。索引將保持活動狀態(tài),并像往常一樣繼續(xù)供查詢使用。在phoenix服務端修改如下配置:

phoenix.index.failure.block.write必須為true,才能在提交失敗時使對數(shù)據(jù)表的寫操作失敗,直到索引能夠跟上數(shù)據(jù)表為止。
phoenix.index.failure.handling.rebuild必須為true(默認值),才能在提交失敗時在后臺重新構建可變索引。

b、在寫入失敗時禁用可變索引,直到一致性恢復(中等級別)
在phoenix服務端修改如下配置:

phoenix.index.failure.handling.rebuild 必須為true(默認值),才能在提交失敗時在后臺重新構建可變索引。
phoenix.index.failure.handling.rebuild.interval 控制服務器檢查是否需要部分重新構建可變索引以趕上對數(shù)據(jù)表的更新的毫秒頻率。默認值是10000或10秒。
phoenix.index.failure.handling.rebuild.overlap.time 控制從發(fā)生故障的時間戳返回到執(zhí)行部分重建時返回的毫秒數(shù)。默認值是1。

c、在寫失敗時禁用可變索引,手動重新構建(最低級別)
當對輔助索引的寫入失敗時,索引將被標記為禁用,需要手動重新構建索引以使查詢能夠再次使用該索引。

phoenix.index.failure.handling.rebuild必須設置為false,以便在提交失敗時禁用在后臺重建可變索引。

七、索引常見問題及建議

  1. 什么時候刪除重建disable狀態(tài)的索引比直接rebuild更快
    當查看SYSTEM.CATALOG中索引表對應的INDEX_DISABLE_TIMESTAMP字段值為0時直接重建。

  2. 對phoenix映射的hbase表創(chuàng)建索引,直接使用hbase API寫Hbase表,索引不會同步
    只有通過phoenix語法寫入才能使用二級索引同步機制。不建議手動讀寫索引表,容易造成索引數(shù)據(jù)不一致。

  3. 使用同步索引表快還是使用MR的異步填充索引快
    如果數(shù)據(jù)量在10億以內(nèi),并且RS配置相對較高,推薦使用同步方式,但集群負載會較高。異步方式對HBASE集群影響較小,因為可以直接寫hdfs。

  4. 怎么避免發(fā)生 ERROR 2008:Unableto find cached index metadata
    核心原因是客戶端寫壓力大,建議減小batch和并發(fā)數(shù)?;蛟趕erver端調(diào)phoenix.coprocessor.maxServerCacheTimeToLiveMsphoenix.coprocessor.maxMetadataCacheTimeToLiveMs兩個參數(shù)

  5. 為什么索引狀態(tài)經(jīng)常不可用或頻繁發(fā)生ERROR 1120:Writes to table blocked until index can be updated異常
    檢查集群狀態(tài)是否穩(wěn)定,GC情況是否正常,負載壓力是否正常等

  6. 索引表一直處于BUILDING狀態(tài)
    可能是索引填充時存在非法數(shù)據(jù)(如時間戳類型的值偶爾會遇見這種情況)或其他造成索引填充失敗的原因存在。

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容