天天看點

掃雷實用帖:HBase讀延遲的12種優化套路

任何系統都會有各種各樣的問題,有些是系統本身設計問題,有些卻是使用姿勢問題。hbase也一樣,在真實生産線上大家或多或少都會遇到很多問題,有些是hbase還需要完善的,有些是我們确實對它了解太少。總結起來,大家遇到的主要問題無非是full gc異常導緻當機問題、rit問題、寫吞吐量太低以及讀延遲較大。

full gc問題的解決方案目前主要有兩方面需要注意,一方面需要檢視gc日志确認是哪種full gc,根據full gc類型對jvm參數進行調優,另一方面需要确認是否開啟了bucketcache的offheap模式,建議使用lrublockcache的童鞋盡快轉移到bucketcache來。當然我們還是很期待官方2.0.0版本釋出的更多offheap子產品。

rit問題,我相信更多是因為我們對其不了解。解決方案目前有兩個,優先是使用官方提供的hbck進行修複(hbck本人一直想拿出來分享,但是目前案例還不多,等後面有更多案例的話再拿出來說),使用之後還是解決不了的話就需要手動修複檔案或者中繼資料表。

而對于寫吞吐量太低以及讀延遲太大的優化問題,筆者也和很多朋友進行過探讨,這篇文章就以讀延遲優化為核心内容展開,具體分析hbase進行讀延遲優化的那些套路,以及這些套路的具體原理。希望大家在看完之後能夠結合這些套路剖析自己的系統。

一般情況下,讀請求延遲較大通常存在三種場景,分别為:

1. 僅有某業務延遲較大,叢集其他業務都正常

2. 整個叢集所有業務都反映延遲較大

3. 某個業務起來之後叢集其他部分業務延遲較大

這三種場景是表象,通常某業務反應延遲異常,首先需要明确具體是哪種場景,然後針對性解決問題。下圖是對讀優化思路的一點總結,主要分為四個方面:用戶端優化、伺服器端優化、列族設計優化以及hdfs相關優化,下面每一個小點都會按照場景分類,文章最後進行歸納總結。下面分别進行詳細講解:

hbase用戶端優化  

和大多數系統一樣,用戶端作為業務讀寫的入口,姿勢使用不正确通常會導緻本業務讀延遲較高實際上存在一些使用姿勢的推薦用法,這裡一般需要關注四個問題:

1. scan緩存是否設定合理?

優化原理:

在解釋這個問題之前,首先需要解釋什麼是scan緩存,通常來講一次scan會傳回大量資料,是以用戶端發起一次scan請求,實際并不會一次就将所有資料加載到本地,而是分成多次rpc請求進行加載,這樣設計一方面是因為大量資料請求可能會導緻網絡帶寬嚴重消耗進而影響其他業務,另一方面也有可能因為資料量太大導緻本地用戶端發生oom。在這樣的設計體系下使用者會首先加載一部分資料到本地,然後周遊處理,再加載下一部分資料到本地處理,如此往複,直至所有資料都加載完成。資料加載到本地就存放在scan緩存中,預設100條資料大小。

通常情況下,預設的scan緩存設定就可以正常工作的。但是在一些大scan(一次scan可能需要查詢幾萬甚至幾十萬行資料)來說,每次請求100條資料意味着一次scan需要幾百甚至幾千次rpc請求,這種互動的代價無疑是很大的。是以可以考慮将scan緩存設定增大,比如設為500或者1000就可能更加合适。筆者之前做過一次試驗,在一次scan掃描10w+條資料量的條件下,将scan緩存從100增加到1000,可以有效降低scan請求的總體延遲,延遲基本降低了25%左右。

優化建議:

大scan場景下将scan緩存從100增大到500或者1000,用以減少rpc次數。

2. get請求是否可以使用批量請求?

hbase分别提供了單條get以及批量get的api接口,使用批量get接口可以減少用戶端到regionserver之間的rpc連接配接數,提高讀取性能。另外需要注意的是,批量get請求要麼成功傳回所有請求資料,要麼抛出異常。

使用批量get進行讀取請求。

3. 請求是否可以顯示指定列族或者列?

hbase是典型的列族資料庫,意味着同一列族的資料存儲在一起,不同列族的資料分開存儲在不同的目錄下。如果一個表有多個列族,隻是根據rowkey而不指定列族進行檢索的話不同列族的資料需要獨立進行檢索,性能必然會比指定列族的查詢差很多,很多情況下甚至會有2倍~3倍的性能損失。

可以指定列族或者列進行精确查找的盡量指定查找。

4. 離線批量讀取請求是否設定禁止緩存?

通常離線批量讀取資料會進行一次性全表掃描,一方面資料量很大,另一方面請求隻會執行一次。這種場景下如果使用scan預設設定,就會将資料從hdfs加載出來之後放到緩存。可想而知,大量資料進入緩存必将其他實時業務熱點資料擠出,其他業務不得不從hdfs加載,進而會造成明顯的讀延遲毛刺。

離線批量讀取請求設定禁用緩存,scan.setblockcache(false)。

hbase伺服器端優化  

一般服務端端問題一旦導緻業務讀請求延遲較大的話,通常是叢集級别的,即整個叢集的業務都會反映讀延遲較大。可以從4個方面入手:

5. 讀請求是否均衡?

極端情況下假如所有的讀請求都落在一台regionserver的某幾個region上,這一方面不能發揮整個叢集的并發處理能力,另一方面勢必造成此台regionserver資源嚴重消耗(比如io耗盡、handler耗盡等),落在該台regionserver上的其他業務會是以受到很大的波及。可見,讀請求不均衡不僅會造成本身業務性能很差,還會嚴重影響其他業務。當然,寫請求不均衡也會造成類似的問題,可見負載不均衡是hbase的大忌。

觀察确認:

觀察所有regionserver的讀請求qps曲線,确認是否存在讀請求不均衡現象。

rowkey必須進行散列化處理(比如md5散列),同時建表必須進行預分區處理。

6. blockcache是否設定合理?

blockcache作為讀緩存,對于讀性能來說至關重要。預設情況下blockcache和memstore的配置相對比較均衡(各占40%),可以根據叢集業務進行修正,比如讀多寫少業務可以将blockcache占比調大。另一方面,blockcache的政策選擇也很重要,不同政策對讀性能來說影響并不是很大,但是對gc的影響卻相當顯著,尤其bucketcache的offheap模式下gc表現很優越。另外,hbase 2.0對offheap的改造(hbase-11425)将會使hbase的讀性能得到2~4倍的提升,同時gc表現會更好!

觀察所有regionserver的緩存未命中率、配置檔案相關配置項一級gc日志,确認blockcache是否可以優化。

jvm記憶體配置量 < 20g,blockcache政策選擇lrublockcache;否則選擇bucketcache政策的offheap模式;期待hbase 2.0的到來!

7. hfile檔案是否太多?

hbase讀取資料通常首先會到memstore和blockcache中檢索(讀取最近寫入資料&熱點資料),如果查找不到就會到檔案中檢索。hbase的類lsm結構會導緻每個store包含多數hfile檔案,檔案越多,檢索所需的io次數必然越多,讀取延遲也就越高。檔案數量通常取決于compaction的執行政策,一般和兩個配置參數有關:hbase.hstore.compactionthreshold和hbase.hstore.compaction.max.size,前者表示一個store中的檔案數超過多少就應該進行合并,後者表示參數合并的檔案大小最大是多少,超過此大小的檔案不能參與合并。這兩個參數不能設定太’松’(前者不能設定太大,後者不能設定太小),導緻compaction合并檔案的實際效果不明顯,進而很多檔案得不到合并。這樣就會導緻hfile檔案數變多。

觀察regionserver級别以及region級别的storefile數,确認hfile檔案是否過多。

優化建議:hbase.hstore.compactionthreshold設定不能太大,預設是3個;設定需要根據region大小确定,通常可以簡單的認為hbase.hstore.compaction.max.size = regionsize / hbase.hstore.compactionthreshold。

8. compaction是否消耗系統資源過多?

compaction是将小檔案合并為大檔案,提高後續業務随機讀性能,但是也會帶來io放大以及帶寬消耗問題(資料遠端讀取以及三副本寫入都會消耗系統帶寬)。正常配置情況下minor compaction并不會帶來很大的系統資源消耗,除非因為配置不合理導緻minor compaction太過頻繁,或者region設定太大情況下發生major compaction。

觀察系統io資源以及帶寬資源使用情況,再觀察compaction隊列長度,确認是否由于compaction導緻系統資源消耗過多。

minor compaction設定:hbase.hstore.compactionthreshold設定不能太小,又不能設定太大,是以建議設定為5~6;hbase.hstore.compaction.max.size = regionsize / hbase.hstore.compactionthreshold

major compaction設定:大region讀延遲敏感業務( 100g以上)通常不建議開啟自動major compaction,手動低峰期觸發。小region或者延遲不敏感業務可以開啟major compaction,但建議限制流量;

期待更多的優秀compaction政策,類似于stripe-compaction盡早提供穩定服務。

hbase列族設計優化  

hbase列族設計對讀性能影響也至關重要,其特點是隻影響單個業務,并不會對整個叢集産生太大影響。列族設計主要從兩個方面檢查:

9. bloomfilter是否設定?是否設定合理?

bloomfilter主要用來過濾不存在待檢索rowkey或者row-col的hfile檔案,避免無用的io操作。它會告訴你在這個hfile檔案中是否可能存在待檢索的kv,如果不存在,就可以不用消耗io打開檔案進行seek。很顯然,通過設定bloomfilter可以提升随機讀寫的性能。

bloomfilter取值有兩個,row以及rowcol,需要根據業務來确定具體使用哪種。如果業務大多數随機查詢僅僅使用row作為查詢條件,bloomfilter一定要設定為row,否則如果大多數随機查詢使用row+cf作為查詢條件,bloomfilter需要設定為rowcol。如果不确定業務查詢類型,設定為row。

任何業務都應該設定bloomfilter,通常設定為row就可以,除非确認業務随機查詢類型為row+cf,可以設定為rowcol。

hdfs相關優化  

hdfs作為hbase最終資料存儲系統,通常會使用三副本政策存儲hbase資料檔案以及日志檔案。從hdfs的角度望上層看,hbase即是它的用戶端,hbase通過調用它的用戶端進行資料讀寫操作,是以hdfs的相關優化也會影響hbase的讀寫性能。這裡主要關注如下三個方面:

10. short-circuit local read功能是否開啟?

目前hdfs讀取資料都需要經過datanode,用戶端會向datanode發送讀取資料的請求,datanode接受到請求之後從硬碟中将檔案讀出來,再通過tpc發送給用戶端。short circuit政策允許用戶端繞過datanode直接讀取本地資料。

開啟short circuit local read功能。

11. hedged read功能是否開啟?

hbase資料在hdfs中一般都會存儲三份,而且優先會通過short-circuit local read功能嘗試本地讀。但是在某些特殊情況下,有可能會出現因為磁盤問題或者網絡問題引起的短時間本地讀取失敗,為了應對這類問題,社群開發者提出了補償重試機制 – hedged read。該機制基本工作原理為:用戶端發起一個本地讀,一旦一段時間之後還沒有傳回,用戶端将會向其他datanode發送相同資料的請求。哪一個請求先傳回,另一個就會被丢棄。

優化建議:開啟hedged read功能。

12. 資料本地率是否太低?

資料本地率:

hdfs資料通常存儲三份,假如目前regiona處于node1上,資料a寫入的時候三副本為(node1,node2,node3),資料b寫入三副本是(node1,node4,node5),資料c寫入三副本(node1,node3,node5),可以看出來所有資料寫入本地node1肯定會寫一份,資料都在本地可以讀到,是以資料本地率是100%。現在假設regiona被遷移到了node2上,隻有資料a在該節點上,其他資料(b和c)讀取隻能遠端跨節點讀,本地率就為33%(假設a,b和c的資料大小相同)。

資料本地率太低很顯然會産生大量的跨網絡io請求,必然會導緻讀請求延遲較高,是以提高資料本地率可以有效優化随機讀性能。資料本地率低的原因一般是因為region遷移(自動balance開啟、regionserver當機遷移、手動遷移等),是以一方面可以通過避免region無故遷移來保持資料本地率,另一方面如果資料本地率很低,也可以通過執行major_compact提升資料本地率到100%。

避免region無故遷移,比如關閉自動balance、rs當機及時拉起并遷回飄走的region等;在業務低峰期執行major_compact提升資料本地率。

hbase讀性能優化歸納  

在本文開始的時候提到讀延遲較大無非三種常見的表象,單個業務慢、叢集随機讀慢以及某個業務随機讀之後其他業務受到影響導緻随機讀延遲很大。了解完常見的可能導緻讀延遲較大的一些問題之後,我們将這些問題進行如下歸類,讀者可以在看到現象之後在對應的問題清單中進行具體定位:

hbase讀性能優化總結  

性能優化是任何一個系統都會遇到的話題,每個系統也都有自己的優化方式。 hbase作為分布式kv資料庫,優化點又格外不同,更多地融入了分布式特性以及存儲系統優化特性。文中總結了讀優化的基本突破點,有什麼不對的地方還望指正,有補充的也可以一起探讨交流!

作者介紹  範欣欣

網易杭州研究院背景技術中心資料庫技術組,專注于hbase的開發運維,熱衷于mysql等相關資料庫技術。

原文釋出時間為:2016-11-21 

本文來自雲栖社群合作夥伴dbaplus