在 HBase 上使用 Big SQL 實現快速單點查詢

pjjc3716 8年前發布 | 9K 次閱讀 HBase SQL NoSQL數據庫

來自: http://www.ibm.com/developerworks/cn/analytics/blog/using-big-sql-hbase-fast-point-queries/index.html?ca=drs-

隨著一些組織開始探索將其數據轉移到分布式文件系統中的可能性,他們被如今豐富多樣的工具驚呆了。挑選出與其訪問模式匹配的正確工具可能很難。如果過去使用 SQL 和 JDBC 作為主要客戶端接口,現在想繼續使用它們,該怎么辦?好消息是有許多解決方案在 Hadoop 數據上都提供了 SQL 功能。Big SQL 由于能夠支持最廣泛的 SQL 并具有高性能和可伸縮性,很快就倍受青睞。現在,如果您的數據訪問需要快速的亞秒級響應時間,該怎么辦?Big SQL 可以滿足這一需求。借助 HBase 上對 SQL 的支持,您可以在其他文件格式上獲得所有可用特性,并獲得對小型查詢的快速響應時間的額外優勢。我們計劃通過一系列文章介紹 HBase 的一些特性,并解釋 Big SQL 如何利用這些特性。

如果打算挑選一個特性,使用行鍵快速查找的能力使得 HBase 成為需要亞秒級響應時間的查詢的不錯的候選方案。無論您的 HBase 表有多大,您都可以期望在數毫秒內返回所需的行,只要您知道整個行鍵的范圍以及與較小的行集合匹配的某個鍵的范圍。在介紹 SQL 方面的功能之前,讓我們看看如何將數據存儲在 HBase 表中。作為一個列式數據庫,HBase 基本上是一種鍵值存儲。這意味著一個 HBase 表中的每個值都由一個鍵唯一地表示,這個鍵由行鍵、列限定符、列族和時間戳組成。

這是 HBase 中的數據的示例。

rowkey_columnfamily_columnqualifier_timestamp_value
 row1_cf1_cq1_ts1_val#1111
 row1_cf1_cq1_ts2_val#1112
 row1_cf1_cq2_ts1_val#1121
 row2_cf1_cq3_ts1_val#2131
 row2_cf2_cq4_ts1_val#2231

存儲的數據按行鍵進行排序和建立索引,整個鍵與每個值一起持久保存在磁盤上。在想要檢索某個較小的行集合時,可以了解此特性有何幫助。另一方面,這使得 HBase 成為了一種非常冗長的數據存儲。您在存儲和讀取數據時將會花費一些成本。

讓我們來了解此特性如何使您不再厭惡 HBase。Big SQL 可以幫助您減輕我上面提到的問題。為此,它提供一個列映射子句來將一個表中的 SQL 列映射到 HBase 實體。用戶可以在他們的表中擁有想要的任意多個列。訣竅在于在相應的 HBase 表中不要有許多列。請記住,每個列都有大量有效負載。

探索不同的映射可能性之前,我們在這里提供了一個示例 Big SQL DDL,用于創建一個存儲在 HBase 中的包含數據的表。這將在 HBase 中創建一個名為 schemaname.tablename 表。在這個示例中,表名稱將為 bigsql.mixed_encodings。

CREATE HBASE TABLE mixed_encodings (c1 int,c2 int,c3 int,c4 varchar(20),c5 varchar(40),c6 int)
 COLUMN MAPPING
 (
 KEY MAPPED BY (c1,c2,c3),
 cf1:cq1 MAPPED BY (c4,c5) ENCODING DELIMITED FIELDS TERMINATED BY '#',
 cf1:cq2 MAPPED BY (c6) ENCODING USING SERDE 'com.ibm.biginsights.bigsql.serde.JSONSerDeForNonUTFStrings'
 );

這個示例表有 6 個 SQL 列:前 3 列映射到 HBase 行鍵;接下來的兩列映射到一個 HBase 列 cf1:cq1;最后一列映射到 cf1:cq2。您還可以注意到一條 ENCODING 子句,它指明了如何在將數據存儲到 HBase 中之前對它們進行編碼。如果您不在意,可以將此工作留給 Big SQL,它將選擇最佳的編碼,這恰好是它內置的二進制編碼。使用二進制編碼,您會最大限度地實現下推和數字排序。DELIMITED 編碼實際上是一種字符串編碼,它使得 HBase 中的數據變得可讀,而在 USING SERDE 編碼中,用戶可以指定一個 SerDe 類來編碼/解碼數據。我提到過 HBase 不關心數據類型或您存儲數據的方式嗎?對它而言,所有數據都是原始字節。這為應用程序提供了存儲它們想要的任何數據并以它們喜歡的任何方式來解釋它的靈活性。這是 Big SQL 利用的特性之一。它允許您將多個 SQL 列打包到一個 HBase 實體中,該實體可能是行鍵或列。它還允許您為 HBase 選擇短名稱,以便您不會向列的有效負載中添加太多內容,其中已包含列限定符和列族名稱。

提示:保持列族和限定符簡短!使用您的命名技能來為這些 SQL 列選擇一些漂亮的名稱。

這是展示了在使用以下插入語句時,HBase 中的數據的外觀。

點擊查看代碼清單

關閉 [x]

INSERT INTO mixed_encodings values (1,2,3,'four','five','six');
hbase(main):001:0> scan 'bigsql.mixed_encodings'
ROW COLUMN+CELL
 \x00\x80\x00\x00\x01\x00\x80\x00\x00\x02\x00\x80\ column=cf1:cq1, timestamp=1447974104744, value=four#five
 x00\x00\x03
 \x00\x80\x00\x00\x01\x00\x80\x00\x00\x02\x00\x80\ column=cf1:cq2, timestamp=1447974104744, value={"c6":6}
 x00\x00\x03
1 row(s) in 0.1870 seconds

當包裝列時,需要做出一些選擇,要求您掌握數據訪問工作負載的一些知識。這很可能是您在選擇 HBase 作為數據存儲之前已學過的知識。如果需要使用一組謂詞來選擇小范圍的數據,您很可能已經選擇將數據存儲在 HBase 中。仔細觀察您的謂詞。選擇大多數查詢中使用的或最常使用的查詢中的謂詞。將這些謂詞映射到行鍵。Big SQL 支持將多個 SQL 列映射到行鍵,可以將查詢謂詞下推到列上來形成合成的行鍵。在示例中,這些謂詞是 c1、c2 和 c3,其中 c1 是最常用和最受限的謂詞。現在,如果一個查詢包含謂詞 c1、(c1,c2) 或 (c1, c2, c3),那么您非常幸運。

上面提到的謂詞下推 ( predicate pushdown) 會讓工作在離數據更近的 HBase 區域服務器中執行。作為一種客戶端/服務器數據庫,HBase 客戶端需要向區域服務器發送請求來讀/寫數據。在某些情況下,可以繞過此限制,這將在以后的文章中介紹。就現在而言,可以將謂詞下推視為一種避免高成本的網絡和磁盤 I/O 的方式。Big SQL 將映射到行鍵的列上的謂詞轉換為鍵范圍,并將它們應用到 HBase 掃描請求。如果該范圍與一到數千行匹配,那么查詢會在亞秒級的響應時間內完成。

提示:可以使用合成的行鍵和二進制編碼來最大化謂詞下推。

與大多數索引實現一樣,您需要在行鍵的前導部分擁有謂詞,Big SQL 才能下推并獲得快速的響應。如果僅查詢 c2,結果如何?或者說查詢另一個未映射到行鍵的列,比如 c4?在這些情況下,您可以在這些列上創建一個輔助索引。以后會對此進行更詳細的介紹。

將關注點轉移回行鍵中的列,Big SQL 也使用了這些列來減少它需要掃描的區域數量。可以將某個區域視為一個由開始鍵和結束鍵限定的定義明確的數據切片。BHase 中的表是區域的集合。在查詢沒有任何謂詞時,將掃描整組區域。借助行鍵的前導部分上的謂詞,Big SQL 可以避免執行這種昂貴的全表掃描,只實際處理一個區域子集。進行區域消除的能力,可以保證在 Big SQL 工作節點之間調度和分配查詢所需的工作更少,這些節點可以并行地處理區域。

提示:決定行鍵是 HBase 表設計的最重要部分之一。提出列映射時,嘗試將想要快速響應時間的查詢中使用的 SQL 列映射到行鍵。

建立行鍵映射后,可以如何處理其他所有列?在示例中只有 3 列,但實際上,列數可能會達到數百個或更多。如果建立對列的一對一映射,則需要考慮所有需要存儲和傳遞的有效負載。在這個時候,使用密集列映射會很方便。您可以將其他所有列放在單個 HBase 列中。如果您知道您的查詢使用的投影,您可能知道一起檢索的列集。將一起查詢的列放在一個 HBase 列中是一種更好的選擇。在 Big SQL 中,可以在 HBase 實體級別指定一種編碼。這意味著可以對行鍵和每個 HBase 列使用不同的編碼。在大部分情況下,最好對整個表使用單一的編碼。

提示:使用密集列映射最小化存儲空間并改善掃描時間。查看您的工作負載中的查詢的投影列表,以決定將哪些列打包在一起。

在編寫列映射時,您可能會想為什么不使用 a:b、c:d 作為 HBase 列名稱?根據本文中的一條提示,它們很短,應該非常適合。但是等等!您需要理解這對 HBase 表而言有何含義。HBase 中的表有兩個列族 a 和 b。一般最好將列族的數量保持最少,最好是一個。這是因為 HBase 將每個列族中的數據持久化到單獨的 HFile 中。HFile 是 HBase 中的基本存儲單元。為了最小化磁盤 I/O,您可能希望讀取較少的文件。擁有一個列族是最好的情況,除非您有一些很少查詢和/或總是單獨查詢的列。在這個示例中,使用了 a:b、a:c 作為列名稱可能更有效。這會在 HBase 表中創建一個名為 a 的列族。

提示:嘗試使用單個列族,除非您的工作負載要求更多。

對于映射到 HBase 列的 SQL 列,如果一個是密集列映射的前導部分的列(比如 c4)上有一個查詢謂詞,你會獲得一定的下推能力。在這種情況下,Big SQL 會將一個列過濾器下推到 HBase 中。服務器端過濾沒有鍵范圍那么高效,因為 HBase 仍需要掃描所有數據,但它有助于減少發送回客戶端的數據。

借助上面描述的密集列映射,我們最小化了為每個值返回的 rowkey_columnfamily_columnqualifier_timestamp_value。如果我們可以避免更多的有效負載該多好?這可以通過定義只包含鍵映射的表來實現。

CREATE HBASE TABLE keyonly(k0 int, k1 int, k2 int)
 COLUMN MAPPING
 (
 key mapped by (k0,k1,k2)
 );

使用這樣一個表,Big SQL 可以應用特殊過濾器來僅檢索行鍵。這些僅包含鍵的表非常適合通常會一起查詢所有列的窄表。但是請記住,HBase 限制了行鍵大小,而且行鍵始終會被檢索。考慮將足夠多的列包裝到行鍵中,但也要嘗試保持它簡短。

提示:您可以為窄表定義一個僅包含鍵的 Big SQL HBase 表。

現在討論一下注意事項。如果您已開始將 HBase 中的行鍵視為關系數據庫中的主鍵,那么做一下對比在某種程度上講是非常合理的。但是,在嘗試為現有的行鍵插入不同的值時,您不會獲得任何違反限制的錯誤。HBase 會創建該值的另一個版本。在 Big SQL 檢索一個值的最新版本時,這意味著您會丟失一些數據,但卻不會獲得任何錯誤。在傳遞數據之前,一定要確保您擁有一個唯一的行鍵。如果不確定,Big SQL 有一條特殊的子句來應對這些情形。

CREATE HBASE TABLE force_key_unique(k0 int, c0 int)
 COLUMN MAPPING
 (
 key mapped by (k0) force key unique,
 f:q mapped by (c0)
 );

如果沒有 FORCE KEY UNIQUE 子句,如果數據包含兩個具有相同的 k0 值的行,那么只有最后一行對查詢是可見的。使用該子句,Big SQL 會在將行鍵存儲到 HBase 中之前向它附加一個唯一值,而且兩行均對查詢可見。請注意,使用該子句會向 HBase 中存儲更多的數據。因此僅在真正需要時使用此子句。

提示:請注意 HBase 的列版本特性,確保映射到行鍵的列是唯一的,以預防數據丟失。Big SQL 提供了一個 FORCE KEY UNIQUE 子句,但盡在真正需要時才使用它。

對于行鍵設計,還有更多內容可以介紹,而且在 HBase 中建模數據時還有其他區域需要考慮。就現在而言,我希望這些技巧能幫助您攜帶輕便的、正確的有效負載,使您能快速而又高效地檢索所需的數據。

</div>

 本文由用戶 pjjc3716 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!