久久精品人人爽,华人av在线,亚洲性视频网站,欧美专区一二三

HBase中數據分布模型是怎么樣的

189次閱讀
沒有評論

共計 7650 個字符,預計需要花費 20 分鐘才能閱讀完成。

這篇文章主要為大家展示了“HBase 中數據分布模型是怎么樣的”,內容簡而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓丸趣 TV 小編帶領大家一起研究并學習一下“HBase 中數據分布模型是怎么樣的”這篇文章吧。

數據分布問題簡述

分布式產生的根源是“規模”,規模可理解為計算和存儲的需求。當單機能力無法承載日益增長的計算存儲需求時,就要尋求對系統的擴展方法。通常有兩種擴展方式:提升單機能力(scale up),增加機器(scale out,水平擴展)。限于硬件技術,單機能力的提升在一個階段內是有上限的; 而水平擴展在理論上可以是無限的,同時,也更廉價、更容易落地。水平擴展可以通過快速、簡單的“加機器”,有效解決業務快速增長的問題,這幾乎是現代分布式系統必備的能力。對于爆發式增長的業務,水平擴展似乎是唯一可選擇的方案。

對于存儲系統而言,原本存儲在一臺機器上的數據,現在要存放在多臺機器上。此時必須解決兩個問題:分片,復制。

數據分片(sharding),又稱分區(partition),將數據集“合理的”拆分成多個分片,每臺機器負責其中若干個分片。以此來突破單機容量的限制,同時也提升了整體的訪問能力。另外,分片也降低了單個分片故障的影響范圍。

數據復制(replica),也叫“副本”。分片無法解決單機故障丟數據的問題,所以,必然要通過冗余來解決系統高可用的問題。同時,副本機制也是提升系統吞吐、解決熱點問題的重要手段。

分片和副本是正交的,這意味著我們可以只使用其中一種或都使用,但通常都是同時使用的。因為分片解決的是規模和擴展性的問題,副本解決可靠、可用性的問題。對于一個生產可用的系統,二者必須同時具備。

從使用者 / 客戶端的角度看,分片和副本可以歸結為同一個問題:請求路由,即請求應該發送給哪臺機器來處理。

讀數據時,能通過某種機制來確保有一個合適的分片 / 副本來提供服務

寫數據時,能通過同樣的機制來確保寫到一個合適的地方,并確保副本的一致性

無論客戶端的請求是直達服務端(如 HBase/cassandra),還是通過代理(如公有云上的基于 gateway 的訪問方式),請求路由都是分布式系統必須解決的問題。

無論是分片還是副本,本質上都是數據分布的體現。下面我們來看 HBase 的數據分布模型。

HBase 的數據分布模型

HBase 的數據分片按表進行,以行為粒度,基于 rowkey 范圍進行拆分,每個分片稱為一個 region。一個集群有多張表,每張表劃分為多個 region,每臺服務器服務很多 region。所以,HBase 的服務器稱為 RegionServer,簡稱 RS。RS 與表是正交的,即一張表的 region 會分布到多臺 RS 上,一臺 RS 也會調度多張表的 region。如下圖所示:

“以行為粒度”,意思是行是 region 劃分的最小單位,即一行數據要么屬于 A region,要么屬于 Bregion,不會被拆到兩個 region 中去。(對行進行拆分的方式是“垂直分庫”,通常只能在業務層面進行,HBase 是水平拆分)

HBase 的副本機制是通過通過底層的 HDFS 實現的。所以,HBase 的副本與分片是解耦的,是存儲計算分離的。這使得 region 可以在 RS 之間靈活的移動,而不需要進行數據遷移,這賦予了 HBase 秒級擴容的能力和極大的靈活性。

對于單個表而言,一個“好”的數據分布,應該是每個 region 的數據量大小相近,請求量 (吞吐) 接近,每臺機器調度的 region 數量大致相同。這樣,這張表的數據和訪問能夠均勻的分布在整個集群中,從而得到最好的資源利用率和服務質量,即達到負載均衡。當集群進行擴容、縮容時,我們希望這種“均衡”能夠自動保持。如果數據分布未能實現負載均衡,則負載較高的機器很容易稱為整個系統的瓶頸,這臺機器的響應慢,可能導致客戶端的大部分線程都在等待這臺機器返回,從而影響整體吞吐。所以,負載均衡是 region 劃分和調度的重要目標。

這里涉及到 3 層面的負載均衡問題:

數據的邏輯分布:即 region 劃分 / 分布,是 rowkey 到 region 的映射問題

數據的物理分布:即 region 在 RS 上的調度問題

訪問的分布:即系統吞吐 (請求) 在各個 RS 上的分布問題,涉及數據量和訪問量之間的關系,訪問熱點等。

可見,一行數據的分布(找到一行數據所在的 RS),存在 2 個層級的路由:一是 rowkey 到 region 的路由,二是 region 到 RS 的路由。這一點是 HBase 能夠實現靈活調度、秒級擴容的關鍵。后面我們會詳細討論。本文僅討論前面兩個問題,第三個問題放在后續的文章中討論。

基于 rowkey 范圍的 region 劃分

首先,我們來看數據的邏輯分布,即一張表如何劃分成多個 region。

region 劃分的粒度是行,region 就是這個表中多個連續的行構成的集合。行的唯一標識符是 rowkey,所以,可以將 region 理解為一段連續分布的 rowkey 的集合。所以,稱這種方式為基于 rowkey 范圍的劃分。

一個 region 負責的 rowkey 范圍是一個左閉右開區間,所以,后一個 region 的 start key 是前一個 region 的 end key。注意,第一個 region 是沒有 start key 的,最后一個 region 是沒有 end key 的。這樣,這個表的所有 region 加在一起就能覆蓋任意的 rowkey 值域。如下圖所示:

上圖中,region1 是第一個 region,沒有 startKey,region3 是最后一個 region,沒有 endKey。圖中的 region 分布是比較均勻的,即每個 region 的行數是相當的,那么,這個分布是怎么得到的呢? 或者說,region 的邊界是如何確定的?

一般來說,region 的生成有 3 種方式:

建表時進行預分區:通過對 rowkey 進行預估,預先劃分好 region

region 分裂:手工分裂,或達到一定條件時自動分裂(如 region 大小超過一個閾值)

region 合并:手工合并

建表時如果未顯式指定 region 分布,HBase 就會只創建一個 region,這個 region 自然也只能由一臺機器進行調度(后面會討論一個 region 由多個 RS 調度的情況)。那這個 region 的吞吐上限就是單機的吞吐上限。如果通過合理的預分區將表分成 8 個 region,分布在 8 臺 RS 上,那整表的吞吐上限就是 8 臺機器的吞吐上限。

所以,為了使表從一開始就具備良好的吞吐和性能,實際生產環境中建表通常都需要進行預分區。但也有一些例外,比如無法預先對 rowkey 范圍進行預估,或者,不容易對 rowkey 范圍進行均勻的拆分,此時,也可以創建只有一個 region 的表,由系統自己分裂,從而逐漸形成一個“均勻的”region 分布。

比如一張存儲多個公司的員工信息的表,rowkey 組成是 orgId + userid,其中 orgId 是公司的 id。由于每個公司的人數是不確定的,同時也可能是差別很大的,所以,很難確定一個 region 中包含幾個 orgId 是合適的。此時,可以為其創建單 region 的表,然后導入初始數據,隨著數據的導入進行 region 的自動分裂,通常都能得到比較理想的 region 分布。如果后續公司人員發生較大的變化,也可以隨時進行 region 的分裂與合并,來獲得最佳分布。

字典序與 rowkey 比較

上一節我們提到 region 的 rowkey 范圍是一個左閉右開區間,所有落在這個范圍的 rowkey 都屬于這個 region。為了進行這個判斷,必須將其與這個 region 的起止 rowkey 進行比較。除了 region 歸屬的判斷,在 region 內部,也需要依賴 rowkey 的比較規則來對 rowkey 進行排序。

很多人都會認為 rowkey 的比較非常簡單,沒有什么討論的必要。但正是因為簡單,它的使用才能靈活多樣,使得 HBase 具備無限的可能性。可以說,rowkey 的比較規則是整個 HBase 數據模型的核心,直接影響了整個請求路由體系的設計、讀寫鏈路、rowkey 設計、scan 的使用等,貫穿整個 HBase。對于用戶而言,深入理解這個規則及其應用有助于做出良好的表設計,寫出精準、高效的 scan。

HBase 的 rowkey 是一串二進制數據,在 Java 中就是一個 byte[],是一行數據的唯一標識符。而業務的主鍵可能是有各種數據類型的,所以,這里要解決 2 個問題:

將各種實際使用的數據類型與 byte[]進行相互轉換

保序:byte[]形式的 rowkey 的排序結果與原始數據的排序結果一致

rowkey 的比較就是 byte[]的比較,按字典序進行比較(二進制排序),簡單說,就是 c 語言中 memcmp 函數。通過下面的示例,我們通過排序結果來對這一比較規則以及數據類型轉換進行理解。

(1)ascii 碼的大小比較 1234 – 0x31 32 33 345 – 0x35 從 ascii 碼表示的數字來看,1234 5,但從字典序來看,1234 5

(2)具有相同前綴的 ascii 碼比較 1234 – 0x31 32 33 3412340 – 0x31 32 33 34 00 在 C 語言中,字符串一般是以 0 自己結尾的。本例的兩個字符串雖然前綴相同,但第二個末尾多了 0 字節,則第二個“較大”。

(3)正數與負數的比較 int 類型的 100 – 0x00 00 00 64int 類型的 -100 – 0xFF FF FF 9C100 -100,但其二進制表達中,100 -100

我們可以將這個比較規則總結如下:

從左到右逐個字節進行比較,以第一個不同字節的比較結果作為兩個 byte[]的比較結果

字節的比較是按無符號數方式進行的

“不存在”比“存在”小

常見的 rowkey 編碼問題:

有符號數:二進制表示中,有符號數的首 bit 是 1,在字典序規則下,負數比正數大,所以,當 rowkey 的值域同時包含正數和負數時,需要對符號位進行反轉,以確保正數比負數大

倒序:通常用 long 來描述時間,一般都是倒排的,假設原始值是 v,則 v 的倒序編碼是 Long#MAX_VALUE – v。

下面通過一個前綴掃描的案例來體會一下這個比較規則的應用。

示例:前綴掃描

Hbase 的 rowkey 可以理解為單一主鍵列。如果業務場景需要多列一起構成聯合主鍵(也叫多列主鍵,組合主鍵,復合主鍵等等),就需要將多列拼接為一列。一般來說,直接將二進制拼接在一起即可。例如:

rowkey 組成:userId + ts

為了簡單,假設 userid 和 ts 都是定長的,且只有 1 個字節。例如:

現在,我們要做的事情是,查找某個 userid = 2 的所有數據。這是一個典型的前綴掃描場景,我們需要構造一個 Scan 操作來完成:設置正確掃描范圍[startRow, stopRow),與 region 的邊界一樣,scan 的范圍也是一個左閉右開區間。

一個直接的思路是找到最小和最大的 ts,與 userid = 2 拼接,作為查詢范圍,即[0x02 00, 0x02 FF)。由于 scan 是左臂右開區間,則 0x02 FF 不會被作為結果返回。所以,這個方案不可行。

正確的 scan 范圍必須滿足:

startRow:必須必任何 userId = 2 的 rowkey 都小,且比任何 userId = 1 的 rowkey 都大

stopRow:必須必任何 userId = 2 的 rowkey 都大,且比任何 userId = 3 的 rowkey 都小

那如何利用 rowkey 的排序規則來“找到”這樣一個掃描范圍呢?

正確的掃描范圍是[0x02, 0x03)。

0x02 比任何 userid = 2 的行都小。因為 ts 這一列是缺失的。同理,0x03 比任何 userid = 2 的行都大,又比任何 userId = 3 的行都小。可見,要實現前綴掃描,只根據前綴的值就可以得到所需的 startRow 和 stopRow,而不需要知道后面的列及其含義。

請讀者仔細體會這個例子,然后思考下面幾個場景該如何構造 startRow 和 stopRow(答案見文末)。

where userid = 2 and ts = 5 and ts 20

where userid = 2 and ts 5 and ts 20

where userid = 2 and ts 5 and ts = 20

where userid 2 and userid 4

還有下面這些組合場景:

where userid in (3, 5, 7, 9)

where userid = 2 and ts in (10, 20, 30)

現在,已經可以感受到使用 scan 的難點和痛點所在了。在上面的例子中,只有兩個定長的列,但在實際業務中,列可能是變長的,有各種各樣的數據類型,各種豐富的查詢模式。此時,構造一個正確、高效的 scan 是有難度的。那為什么會有這些問題呢? 有沒有系統性的解決方案呢?

從形式是看,這是一個“如何將業務查詢邏輯轉換為 HBase 的查詢邏輯”的問題,本質上是關系表模型到 KV 模型的映射問題。HBase 僅提供了 KV 層的 API,使得用戶不得不自己實現這兩個模型之間的轉換。所以,才會有上面這么多的難點問題。不僅是 HBase,所有的 KV 存儲系統在面臨復雜的業務模型時,都面臨相同的困境。

這個問題的解法是 SQL on NoSQL,業界這類方案有很多(如 Hive,presto 等),HBase 之上的方案就是 Phoenix。此類方案通過引入 SQL 來解決 NoSQL 的易用性問題。對于傳統的關系型數據庫,雖然有強大的 SQL 和事務支持,但擴展性和性能受限,為了解決性能問題,MySQL 提供了基于 Memcached 的 KV 訪問方式; 為了解決擴展性問題,有了各種 NewSQL 的產品,如 Spanner/F1,TiDB,CockroachDB 等。NoSQL 在做 SQL,支持 SQL 的在做 KV,我們可以想象一下未來的存儲、數據庫系統會是什么樣子。這個話題很大,不在本文的討論范圍內,這里就不展開了。

region 的元數據管理與路由

前面我們討論了將一張表的行通過合理的 region 劃分,可以得到數據量大致接近的 region 分布。通過合理的運維手段(region 的分裂與合并),我們可以通保證在系統持續運行期間的 region 分布均勻。此時,數據在邏輯上的拆分已經可以實現均勻。本節中我們看一下 region 如何分布在 RS 上,以及客戶端如何定位 region。

因為 region 的 rowkey 范圍本身的不確定性或者主觀性(人為拆分),無法通過一個數學公式來計算 rowkey 屬于哪個 region(對比一致性 hash 的分片方式)。因此,基于范圍進行的分片方式,需要一個元數據表來記錄一個表被劃分為哪些 region,每個 region 的起止 rowkey 是什么。這個元數據表就是 meta 表,在 HBase1.x 版本中表名是“hbase:meta”(在 094 或更老的版本中,是 -ROOT- 和.META. 兩個元數據表)。

我們從 Put 操作來簡要的了解 region 的定位過程。

ZK 上找 meta 表所在的 RS(緩存)

到 meta 表上找 rowkey 所在的 region 及這個 region 所在的 RS(緩存)

發 Put 請求給這個 RS,RS 根據 region 名字來執行寫操作

如果 RS 發現這個 region 不在自己這里,拋異常,客戶端重新路由

無論讀還是寫,其定位 region 的邏輯都是如此。為了降低客戶端對 meta 表的訪問,客戶端會緩存 region location 信息,當且僅當緩存不正確時,才需要訪問 meta 表來獲取最新的信息。所以,HBase 的請求路由是一種基于路由表的解決方案。相對應的,基于一致性 Hash 的分片方式,則是通過計算來得到分布信息的。

這種基于路由表的方式

優點:region 的歸屬 RS 可以任意更換,或者說,region 在 RS 上的調度是靈活的、可人工干預的。

缺點:meta 表是一個單點,其有限的吞吐限制了集群的規模和客戶端數量

region 的靈活調度,結合存儲計算分離的架構,賦予了 HBase 極其強大的能力。

秒級擴容:新加入的 RS 只需要移動 region 即可立即投產,不依賴數據的遷移(后續慢慢遷)

人工隔離:對于有問題的 region(如熱點,有異常請求),可以手工移動到一臺單獨的 RS 上,進行故障域的快速隔離。

這兩點,是眾多基于一致性 hash 的分片方案無法做到的。當然,為了獲得這種靈活性,HBase 所付出的代價就是復雜的 meta 表管理機制。其中比較關鍵的問題就是 meta 表的單點問題。例如:大量的客戶端都會請求 meta 表來獲取 region location,meta 表的負載較高,會限制獲取 location 的整體吞吐,從而限制集群的規模和客戶端規模。

對于一個擁有數百臺機器,數十萬 region 的集群來說,這套機制可以很好的工作。但當集群規模進一步擴展,觸及到 meta 表的訪問上限時,就會因 meta 表的訪問阻塞而影響服務。當然,絕大多數的業務場景都是無法觸達這個臨界規模的。

meta 表的問題可以有很多種解決思路,最簡單的方式就是副本。例如 TiDB 的 PD 服務,獲取 location 的請求可以發送給任何一臺 PD 服務器。

region 的調度

下面我們討論 region 調度問題:

region 在 RS 之間的負載均衡

同一個 region 在多個 RS 上調度

對于第一個問題,HBase 的默認均衡策略是:以表為單位,每個 RS 上調度盡可能相同數量的 region。

這個策略假設各個 region 的數據量分布相對均勻,每個 region 的請求相對均勻。此時,該策略非常有效。這也是目前使用最多的一種。同時,HBase 也提供了基于負載的調度(StochasticLoadBalancer),會綜合考慮多種因素來進行調度決策,不過,暫時缺少生產環境使用的案例和數據。

對于第二個問題,region 同一時間只在一臺 RS 上調度,使得 HBase 在請求成功的情況下提供了強一致的語義,即寫成功的數據可以立即被讀到。其代價是 region 的單點調度,即 region 所在的服務器因為各種原因產生抖動,都會影響這個 region 的服務質量。我們可將影響 region 服務的問題分為兩類:

不可預期的:宕機恢復,GC,網絡問題,磁盤抖動,硬件問題等等

可預期的(或人為的):擴容 / 縮容導致的 region 移動,region split/merge 等。

這些事件發生時,會對這個 region 的服務或多或少產生一些影響。尤其在宕機場景,從 ZK 發現節點宕機到 region 的 re-assign,split log,log replay,一些列步驟執行完,一般都需要 1 分鐘以上的時間。對于宕機節點上的 region,意味著這段時間這些 region 都無法服務。

解決方案依然是副本方案,讓 region 在多個 RS 上調度,客戶端選擇其中一個進行訪問,這個特性叫“region replia”。引入副本必然帶來額外的成本和一致性問題。目前這個特性的實現并未降低 MTTR 時間,內存水位的控制、臟讀,使得這個特性仍未在生產中大規模使用。

以上是“HBase 中數據分布模型是怎么樣的”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注丸趣 TV 行業資訊頻道!

正文完
 
丸趣
版權聲明:本站原創文章,由 丸趣 2023-07-18發表,共計7650字。
轉載說明:除特殊說明外本站除技術相關以外文章皆由網絡搜集發布,轉載請注明出處。
評論(沒有評論)
主站蜘蛛池模板: 津南区| 洪泽县| 友谊县| 韩城市| 天等县| 阳江市| 浦东新区| 潼关县| 洛阳市| 松阳县| 油尖旺区| 通道| 林芝县| 铁力市| 江川县| 南平市| 东宁县| 息烽县| 甘洛县| 定远县| 贺州市| 西乌| 和平区| 禹州市| 荔波县| 桃园县| 柏乡县| 天长市| 瑞金市| 黄山市| 呼伦贝尔市| 建阳市| 西乌珠穆沁旗| 会东县| 佛山市| 永嘉县| 轮台县| 罗平县| 靖宇县| 沁水县| 陆川县|