58 HBase 平臺實踐和應用-平臺建設篇
HBase 是一個基於 Hadoop 的分散式、面向列的 Key-Value 儲存系統,可以對需 要實時讀寫、隨機訪問大規模資料集的場景提供高可靠、高效能的服務,在大數 據相關領域應用廣泛。HBase 可以對資料進行透明的切分,使得儲存和計算本身 具有良好的水平擴充套件性。
在 58 的業務場景中,HBase 扮演重要角色。例如帖子資訊等公司基礎資料都是 通過 HBase 進行離線儲存,併為各個業務線提供隨機查詢及更深層次的資料分 析。同時 HBase 在 58 還大量用於使用者畫像、搜尋、推薦、時序資料和圖資料等 場景的儲存和查詢分析。
HBase 在 58 的應用架構:
**
HBase 在 58 的應用架構如上圖所示,主要內容包括以下幾個部分:**
- 多租戶支援:包括 SCF 限流、RSGroup、RPC 讀寫分離、HBase Quota 、ACL;
- 資料讀寫介面:包括 SCF 代理 API、原生 Java API 以及跨語言訪問 Thrift Server;
- HBase 資料匯入匯出:包括資料批量匯入工具 BulkLoad,資料批量匯出工具
SnapshotMR; - OLAP:多維分析查詢的 Kylin 平臺;
- 時序資料庫:時序資料儲存和查詢的時序資料庫 Opentsdb;
- 圖資料庫:圖關係資料儲存和查詢的圖資料庫 JanusGraph;
- SQL on HBase:支援二級索引和事務的 Phoenix,以及 Spark SQL 等;
- HBase 在 58 的應用業務場景包括:全量帖子資料、使用者畫像、搜尋、推薦、
使用者行為、智慧監控以及風控反欺詐等的資料儲存和分析; - 監控平臺:HBase 平臺的監控實現。
本文將從多租戶支援、資料讀寫介面、資料匯入匯出和平臺優化四個方面來重點 講解 58HBase 平臺的建設。
說明:下文中所有涉及到 RegionServer 的地方統一使用 RS 來代替。
1. HBase 多租戶支援
HBase 在 1.1.0 版本之前沒有多租戶的概念,同一個叢集上所有使用者、表都是同 等的,導致各個業務之間干擾比較大,特別是某些重要業務,需要在資源有限的 情況下保證優先正常執行,但是在之前的版本中是無法保證的。從 HBase 1.1.0 開始,HBase 的多租戶特性逐漸得到支援,我們的 HBase 版本是 1.0.0-cdh5.4.4, 該版本已經集成了多租戶特性。
以下是 58 使用者訪問 HBase 的流程圖:
我們從多個層面對 HBase 多租戶進行了支援,主要分為以下兩個大的方面:
- 資源限制:
a) SCF Quota;
b) HBase Quota。
- 資源隔離:
a) RS RPC 讀寫分離;
b) HBase ACL 許可權隔離;
c) RSGroup 物理隔離。
**1.1 資源限制
(1)SCF Quota**
SCF 是公司自研的 RPC 框架,我們基於 SCF 封裝了原生 HBase API,使用者根據應 用需要申請 HBase SCF 服務呼叫時,需要根據應用實際情況填寫 HBase 的每分 鐘調用量(請求次數),在呼叫量超限時,SCF 管理平臺可以實現應用級的限流, 這是全侷限流。缺點是隻能對呼叫量進行限制,無法對讀寫資料量大小限制。
以下是使用者申請 HBase SCF 服務呼叫時需要填寫的呼叫量:
(2)HBase Quota
HBase 的 Quota 功能可以實現對使用者級、表級和名稱空間級的資源進行限制。這 裡的資源包括請求資料量大小、請求次數兩個維度,這兩個維度基本涵蓋了常見 的資源限制。目前 HBase 的 Quota 功能只能限制到 RS 這一級,不是針對整個集 群的。但是因為可以對請求的資料量大小進行限制,一定程度上可以彌補了 SCF Proxy 應用級限流只能對請求次數進行限制的不足。
開啟 Quota 的配置如下:
在開啟了 HBase 的 Quota 後,Quota 相關的元資料會儲存到 HBase 的系統表 hbase:quota 中。
在我們的 HBase 叢集中之前遇到過個別使用者讀寫資料量過大導致 RS 節點頻寬被 打滿,甚至觸發 RS 的 FGC,導致服務不穩定,影響到了其他的業務,但是應用級的呼叫量並沒有超過申請 SCF 時設定的值,這個時候我們就可以通過設定 HBase Quota,限制讀寫表級資料量大小來解決這個問題。
以下是設定 HBase Quota 資訊,可以通過命令列進行設定和檢視:
1.2 資源隔離
(1)RS RPC 讀寫分離
預設場景下,HBase 只提供一個 RPC 請求佇列,所有請求都會進入該佇列進行 優先順序排序。這樣可能會出現由於讀問題阻塞所有 handler 執行緒導致寫資料失敗, 或者由於寫問題阻塞所有 handler 執行緒導致讀資料失敗,這兩種問題我們都遇到過,在後續篇幅中會提到,這裡不細述。
通過設定引數 hbase.ipc.server.callqueue.handler.factor 來設定多個佇列,佇列個數等於該引數 * handler 執行緒數,比如該引數設定為 0.1,總的 handler 執行緒數為200,則會產生 20 個獨立佇列。 獨立佇列產生之後,可以通過引數 hbase.ipc.server.callqueue.read.ratio 來設定讀寫佇列比例,比如設定 0.6,則表示會有 12 個佇列用於接收讀請求,8 個用於接收寫請求;另外,還可以進一步 通過引數 hbase.ipc.server.callqueue.scan.ratio 設定 get 和 scan 的佇列比例,比 如設定為 0.2,表示 2 個佇列用於 scan 請求,另外 10 個用於 get 請求,進一步還將 get 和 scan 請求分開。
RPC 讀寫分離設計思想總體來說實現了讀寫請求佇列資源的隔離,達到讀寫互不干擾的目的,根據 HBase 叢集服務的業務型別,我們還可以進一步配置長時 scan 讀和短時 get 讀之間的佇列隔離,實現長時讀任務和短時讀任務互不干擾。
(2)HBase ACL 許可權隔離
HBase 叢集多租戶需要關注的一個核心問題是資料訪問許可權的問題,對於一些重 要的公共資料,或者要進行跨部門訪問資料,我們只開放給經過許可權申請的使用者 訪問,沒有許可權的使用者是不能訪問的,這就涉及到了 HBase 的資料許可權隔離了, HBase 是通過 ACL 來實現許可權隔離的。
基於 58 的實際應用情況,訪問 HBase 的使用者都是 Hadoop 計算叢集的使用者,而 且 Hadoop 使用者是按部門分配的,所以 HBase 的使用者也是到部門而不是到個人, 這樣的好處是維護的使用者數少了,便於管理,缺點是有的部門下面不同子部門之 間如果也要進行資料許可權隔離就比較麻煩,需要單獨申請開通子部門賬號。
要開啟 HBase 的 ACL,只需要在配置檔案 hbase-site.xml 中關於 Master、 RegionServer 和 Region 的協處理器都加上 org.apache.hadoop.hbase.security.access.AccessController 類就可以了。
具體 HBase ACL 的配置項如下圖所示:
HBase 的訪問級別有讀取(R)、寫入(W)、執行(X)、建立(C)、管理員(A),而許可權作 用域包括超級使用者、全域性、名稱空間、表、列族、列。訪問級別和作用域的組合 建立了可授予使用者的可能訪問級別的矩陣。在生產環境中,根據執行特定工作所 需的內容來考慮訪問級別和作用域。
在 58 的實際應用中,我們將使用者和 HBase 的名稱空間一一對應,建立新使用者時, 建立同名的名稱空間,並賦予該使用者對同名名稱空間的所有許可權(RWCA)。以下 以新使用者 zhangsan 為例,建立同名名稱空間並授權:
(3)RSGroup 物理隔離
雖然 SCF Quota 和 HBase Quota 功能可以做到對使用者的讀寫進行限制,一定程度上能降低各業務讀寫資料的相互干擾,但是在我們的實際業務場景中,存在兩類特殊業務,一類是消耗資源非常大,但是不希望被限流,另外一類是非常重要, 需要高優先順序保證服務的穩定。對於這兩種情況下,我們只能對該業務進行物理隔離,物理隔離既能保證重要業務的穩定性,也避免了對其他業務的干擾。我們使用的物理隔離方案是 RSGroup,也即 RegionServer Group。
RSGroup 整體架構:
RSGroup 有以下幾個特點:
- 不同 RS 和表劃分到不同的 RSGroup;
- 同一個 RS 只能屬於一個 RSGroup;
- 同一個表也只能屬於一個 RSGroup;
- 預設所有 RS 和表都屬於“default”這個 RSGroup。
RSGroup 實現細節:
從以上 RSGroup 實現細節中看出,RSGroup 的功能主要包含兩部分,RSGroup 元資料管理以及 Balance。
RSGroup 開啟的配置項:
- 資料讀寫介面
目前我們提供了三種 HBase 的資料讀寫介面以便於使用者使用,包括 SCF 代理、 Java 原生 API 和 Thrift Server。以下分別進行說明:
2.1 SCF Proxy
SCF 是 58 架構部自研的 RPC 框架,我們基於 SCF 封裝了原生的 Java API,以 SCF RPC 介面的方式暴露給使用者使用,其中以這種方式提供給使用者的介面多達 30 個。 由於 SCF 支援跨語言訪問,很好的解決了使用非 Java 語言使用者想要訪問 HBase 資料的問題,目前使用者使用最多的是通過 Java、Python 和 PHP 這三種語言來訪問這些封裝的介面。
SCF proxy 介面整體架構:
資料讀寫流程:使用者通過 RPC 連線到 SCF 服務管理平臺,通過 SCF 服務管理平 臺做服務發現,找到 58 雲端計算平臺上部署的服務節點,服務節點最終通過訪問 HBase 實現使用者資料的讀寫操作。
使用 SCF Proxy 介面的優勢:
- 避免使用者直連 HBase 叢集,降低 zk 的壓力。之前經常遇到因為使用者程式碼存 在 bug,導致 zk 連線數暴漲的情況。
- 針對大量一次性掃描資料的場景,提供單獨訪問介面,並在介面中設定 scan 的 blockcache 熟悉為 false,避免了對後端讀快取的干擾。
- 通過服務管理平臺的服務發現和服務治理能力,結合業務的增長情況以及基 於 58 雲端計算平臺彈性特點,我們很容易對服務節點做自動擴容,而這一切對使用者是透明的。
- 通過服務管理平臺可以實現對使用者的訪問做應用級限流,規範使用者的讀寫操作。
- 服務管理平臺提供了呼叫量、查詢耗時以及異常情況等豐富的圖表,使用者可以很方便檢視。
以下是我們的 SCF 服務在服務管理平臺展示的呼叫量和查詢耗時圖表:
由於 SCF Proxy 介面的諸多優勢,我們對於新接的業務都要求通過申請這種方式 來訪問 HBase。
2.2 Java API
由於歷史原因和個別特殊的新業務還採用 Java 原生的 API 外,其他新業務都通 SCF Proxy 介面來訪問。
**
2.3 Thrift Server**
也是由於歷史原因,個別使用者想使用非 Java 語言來訪問 HBase,才啟用了 Thrift Server,由於 SCF proxy 介面支援多語言,目前這種跨語言訪問的問題都通過 SCF Proxy 來解決了。
3. 資料匯入匯出 3.1 BulkLoad
3.1 BulkLoad
HBase 相對於其他 KV 儲存系統來說比較大的一個優勢是提供了強大的批量匯入 工具 BulkLoad,通過 BulkLoad,我們很容易將生成好的幾百 G,甚至上 T 的 HFile 檔案以毫秒級的速度匯入 HBase,並能馬上進行查詢。所以對於歷史資料和非實 時寫入的資料,我們會建議使用者通過 BulkLoad 的方式匯入資料。
3.2 SnapshotScanMR
針對全表掃描的應用場景,HBase 提供了兩種解決方案,一種是 TableScanMR, 另一種就是 SnapshotScanMR,這兩種方案都是採用 MR 來並行化對資料進行掃描,但是底層實現原理確是有很大差別,以下會進行對比分析。
TableScanMR 的實現原理圖:
TableScanMR 會將 scan 請求根據 HBase 表的 region 分界進行分解,分解成多個 sub-scan(一個 sub-scan 對應一個 map 任務),每個 sub-scan 內部本質上就是一個 ScanAPI。假如 scan 是全表掃描,那這張表有多少 region,就會將這個 scan 分解成多個 sub-scan,每個 sub-scan 的 startkey 和 stopkey 就是 region 的 startkey 和 stopkey。這種方式只是簡單的將 scan 操作並行化了,資料讀取鏈路 和直接 scan 沒有本質區別,都需要通過 RS 來讀取資料。
SnapshotScanMR 的實現原理圖:
SnapshotScanMR 總體來看和 TableScanMR 工作流程基本一致,不過 SnapshotScanMR 的實現依賴於 HBase 的 snapshot,通過 shapshot 的元資料資訊,SnapshotScanMR 可以很容易知道當前全表掃描要訪問那些 HFile以及這些 HFile 的 HDFS 路徑,所以 SnapshotScanMR 構造的 sub-scan 可以繞過 RS,直接 借用 Region 中的掃描機制直接掃描 HDFS 中資料。
SnapshotScanMR 優勢:
- 避免對其他業務的干擾:SnapshotScanMR 繞過了 RS,避免了全表掃描對其 他業務的干擾。
- 極大的提升了掃描效率:SnapshotScanMR 繞過了 RS,減少了一次網路傳輸, 對應少了一次資料的序列化和反序列化操作;TableScanMR 掃描中 RS 很可 能會成為瓶頸,而 SnapshotScanMR 不需要擔心這一點。
基於以上的原因,在全部掃描,以及全部資料匯出的應用場景中,我們選擇了 SnapshotScanMR,並對原生的 SnapshotScanMR 進行了進一步的封裝,作為一個通用工具提供給使用者。
4. 平臺優化
在使用 HBase 的過程中,我們遇到了很多問題和挑戰,但最終都一一克服了,以下是我們遇到一部分典型問題及優化:
4.1 CLOSE_WAIT 偏高優化
問題描述:在一次排查 HBase 問題的時候發現 RS 程序存在大量的 CLOSE_WAIT, 最多的達到了 6000+,這個問題雖然還沒有直接導致 RS 掛掉,但是也確實是個 不小的隱患。
從 socket 的角度分析產生 CLOSE_WAIT 的原因:對方主動關閉連線或者網路異 常導致連線中斷,這時我方的狀態會變成 CLOSE_WAIT, 此時我方要呼叫 close() 來使得連線正確關閉,否則 CLOSE_WAIT 會一直存在。
對應到咱們這個問題,其實就是使用者通過 RS 訪問 DataNode(埠 50010)的數 據,DataNode 端已經主動關閉 Socket 了,但是 RS 端沒有關閉,所以要解決的 問題就是 RS 關閉 Socket 連線的問題。
解決辦法:社群對該問題的討論見 HBASE-9393。該問題的修復依賴 HDFS-7694, 我們的 Hadoop 版本是 hadoop2.6.0-cdh5.4.4,已經集成了 HDFS-7694 的內容。
HBASE-9393 的核心思想是通過 HDFS API 關閉 HBase 兩個地方開啟的 Socket;
RS 開啟 HFile 讀取元資料資訊(flush、bulkload、move、balance 時)後關閉 Socket;每次執行完成使用者 scan 操作後關閉 Socket。
優化效果:CLOSE_WAIT 數量降為 10 左右
4.2 DN 慢盤導致 RS 阻塞優化
問題描述:由於叢集某個磁碟出現壞道(沒有完全壞,表現為讀寫慢,disk.io.util 為 100%),導致 RS 所有 handler 執行緒因為寫 WAL 失敗而被阻塞,無法對外提 供服務,嚴重影響了使用者讀寫資料體驗。
最後分析發現,RS 寫 WAL 時由於 DN 節點出現磁碟壞道(表現為 disk.io.util 為長時間處於 100%),導致寫 WAL 的 pipeline 丟擲異常並誤將正常 DN 節點標記為 bad 節點,而恢復 pipeline 時使用 bad 節點進行資料塊 transfer,導致 pipeline 恢復失敗,最終 RS 的所有寫請求都阻塞到 WAL 的 sync 執行緒上,RS 由於沒有可用的 handler 執行緒,也就無法對外提供服務了。
解決辦法:RS 配置 RPC 讀寫分離:避免由於寫阻塞所有 handler 執行緒,影響到讀請求;
pipeline 恢復失敗解決:社群已有該問題的討論,見並 HDFS-9178,不過因為 HDFS 的 pipeline 過程非常複雜,HDFS-9178 能否解決該問題需要進一步驗證。
4.3 Compact 佔用 Region 讀鎖優化
問題描述:某次有一個業務執行 BulkLoad 操作批量匯入上 T 的資料到 HBase 表時,RS 端報 BulkLoad 操作獲取 Region 級寫鎖出現超時異常:failed to get a lock in 60000 ms,當時該表並沒有進行讀寫操作,最終定位到是該時間段內這個業務 的表正在進行 compact 操作,在我們的 HBase 版本中,執行 compact 時會獲取 Region 級的讀鎖,而且會長時間佔用,所有導致 BulkLoad 獲取寫鎖超時了。
解決辦法:Compact 時不持有 Region 讀鎖,社群對該問題的討論見 HBASE-14575。
4.4 HTablePool 問題優化
問題描述:我們的 SCF 服務最初是基於 HTablePool API 開發的,SCF 服務在運 行一段時間後經常會出現 JVM 堆記憶體暴增而觸發 FGC 的情況,分析發現 HTablePool 已經是標記為已廢棄,原因是通過 HTablePool 的獲取 Table 物件,會建立單獨的執行緒池,而且執行緒個數沒有限制,導致請求量大時,執行緒數會暴增。
解決辦法:最後我們換成了官方推薦的 API,通過 Connection 獲取 Table,這種方式 Connection 內部的執行緒池可以在在所有表中共享,而且執行緒數是可配置的。
4.5 其他優化
BlockCache 啟用 BuckCache;Compact 限流優化等。
- 總結
Apache HBase 實戰技術總結 – 中國 HBase 技術社群
本文從多租戶支援、資料讀寫介面、資料匯入匯出和平臺優化四個方面講解了 HBase 相關的平臺建設工作。HBase 作為一個開源的平臺,有著非常豐富的生態 系統。在 HBase 平臺基礎之上,我們持續不斷地引入了各種新的能力,包括 OLAP、 圖資料庫、時序資料庫和 SQL on HBase 等,這些我們將在 58HBase 平臺實踐和應用的後續篇章中進一步介紹。
轉載
文章作者:何良均/張祥——58 同城 資深研發工程師