使用phoenix踩的坑與設計思考

本文主要介紹在壓測HBase的二級索引phoenix時踩的一個坑,使用時需要特別注意,而且背後的原因也很有意思,可以看出HBase和Phoenix對元數據設計上的差異。

1.問題介紹

在做phoenix壓測時發現一個奇怪的現象。

壓測請求分佈非常均勻,但是有一臺機器的流量、負載都明顯高於其他機器。

如下圖所示。

請求均勻
在這裏插入圖片描述
資源利用率不均勻,單個節點明顯偏高。
在這裏插入圖片描述

2.排查思路

看到這個問題的第一反應,是去看下錶分佈是否均勻。

  • hbase表分佈是否均勻
  • 索引表分佈是否均勻

令人遺憾的是,確認後hbase表和索引表都是均勻分佈的,各個機器上的region數量、存儲用量都是一致,非常均勻。

然後在網上查相關資料,在官網上看到這樣一段描述。(http://phoenix.apache.org/language/index.html)

UPDATE_CACHE_FREQUENCY option (available as of Phoenix 4.7) determines how often the server will be checked for meta data updates (for example, the addition or removal of a table column or the updates of table statistics). Possible values are ALWAYS (the default), NEVER, and a millisecond numeric value. An ALWAYS value will cause the client to check with the server each time a statement is executed that references a table (or once per commit for an UPSERT VALUES statement). A millisecond value indicates how long the client will hold on to its cached version of the metadata before checking back with the server for updates.

大致的意思是,phoenix的表設計時有一個表級別參數UPDATE_CACHE_FREQUENCY,這個參數默認是ALWAYS,表示每次sql查詢都會先去請求meta數據。也可以設置爲一定頻率,表示多久去請求一次meta數據。

那我們大概能猜想到了,因爲設計表的時候沒有指定這個參數,所以爲默認的always,而phoenix的meta數據正好落在了那個機器上。

我們查驗了下系統表的位置,果然如此!

於是立刻做了變更

alter table xxx set UPDATE_CACHE_FREQUENCY = xxxxx。

效果顯著!

不僅流量、負載均勻了,而且整體負載下降了很多!!!
在這裏插入圖片描述

那爲什麼監控上請求量是均勻的呢?因爲phoenix需要訪問catalog表,然後這個表剛纔在core-2上,訪問這個表走的coprocessor,所以沒統計出請求數。

3.進一步思考

到上面爲止,問題的原因找到了,也解決了。

但是熟悉HBase的同學肯定會馬上有個疑問,跟我一樣。爲什麼會有這樣一個參數設置,HBase本身也有meta表,而HBase的meta表在客戶端緩存就可以。

下面,就讓我們來思考下。

1)phoenix爲什麼要這麼設計呢,而不是像hbase的meta表一樣?

這個問題得從phoenix的架構設計說起。

phoenix一直以來,都是重客戶端模式,即使是現在的輕客戶端版本,本質也是如此。只不過把客戶端放在了query server這個角色上,讓query server跑在服務端了。

在這裏插入圖片描述
但對hbase來說,phoenix的核心邏輯都在client側。元數據管理也是如此。phoenix和HBase不同的是,phoenix的元數據更復雜,如果元數據有變化,沒有拿到最新meta的客戶端不一定會拋錯。

舉個例子,比如一個查詢命中索引後會更高效。但是,某個客戶端它 不知道有這個索引表,於是就去查了主表,這個在phoenix上看也沒有毛病。

所以,關鍵原因是phoenix無法感知元數據是否發生了變化!而HBase可以。

因此,最初爲了解決元數據同步的問題,就採用了比較激進的每次刷新的方式。後來發現會影響性能,就加了一個週期性刷新的功能,來避免per request去刷meta數據。

2)那可以alter table時觸發meta更新嗎?

這個是不可以的。因爲客戶端可能比較多。而且,也不會有一個地方去記錄全局有哪些client。即使有這樣一個地方,那某個client掛了怎麼辦?沒有通知成功怎麼辦?此時,alter操作是成功還是不成功呢?

3)結論
所以這個參數是phoenix的設計,而不是缺陷。phoenix默認情況下,每個請求都會去校驗一次表的元數據信息,以避免因meta未刷新導致失敗。爲此,phoenix提供了一個表參數,來控制meta的刷新頻率,比如1分鐘刷一次,類似這種。

可以在建表的時候設定:

craete table if not exists ns.table_demo (
    id varchar not null primary key,
    f1.a varchar,
    f1.b varchar,
    f1.c varchar
)
TTL=86400,
UPDATE_CACHE_FREQUENCY=900000;

也可以變更表結構設定:

alter table xxx set UPDATE_CACHE_FREQUENCY = xxxxx; 

設一個你期望的刷新時間,就可以解決問題了。

當然,這樣帶來的副作用就是,如果未來你修改了這個表,比如add了一個新的列,或者新加了一個索引,最少要等待一個刷新週期才能生效。但是無關大局,一般表結構變更就屬於低頻操作,而且能夠接受一定延遲。

看到這裏了,原創不易,點個贊吧,你最好看了~

知識碎片重新梳理,構建Java知識圖譜:https://github.com/saigu/JavaKnowledgeGraph (歷史文章查閱非常方便)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章