前言:
作為Hadoop生態系統中重要的一員, HBase作為分布式列式存儲, 在線實時處理的特性, 備受矚目, 將來能在很多應用場景, 取代傳統關系型數據庫的江湖地位. 本篇主要講述面向時間序列/面檢索的應用場景時, 如何利用HBase的特性去處理和優化.
構造應用場景
某氣象局對各個站點的信息進行采集和匯總, 這些信息包括站點id, 時間點, 采集要素(要素特別多). 然后對這些采集的數據, 提出如下檢索需求:
1). 時間序列檢索(檢索出該站點的在某個時間范圍內的全要素信息)
2). 面檢索(檢索出在某個時間點, 各個站點在具體時間點的某要素信息)
而其數據信息的特別如下:
1). 要素種類多, 氣象涉及的觀測元素多(濕度, 溫度, 風向等等)
2). 每個站點收集部分信息, 每個站點各司其職(觀測點的重新不一樣)
由此可見數據的分布是呈現大寬表的形式, 列多且稀疏的方式分布.
存儲選型
對比傳統關系型數據和HBase, 對照的衡量參數如下:
| 存儲選型 | 可擴展性 | 索引支持 | 事務支持 | 存儲模式 | 應用場景 |
| Oracle/DB2(CA) | 不支持水平擴容 | 多索引支持 | 支持事務 | 行式存儲(固定的schema, 對稀疏的列數據支持差) | 銀行金融機構(對數據一致性要求高的場所) |
| Mysql Cluster(AP) | 支持水平擴容(分庫分表, hash型) | 多索引支持 | 不支持事務(跨庫) | 行式存儲(固定的schema, 對稀疏的列數據支持差) | 互聯網/移動互聯網(追求高並發/高性能) |
| HBase(CP) | 支持水平擴容(按key范圍來划分region, 區間型) | 無索引, 基於key/value | 不支持事務 | 列式存儲(不固定的schema, 對稀疏的列數據支持好) | 大數據領域 |
評注: CAP理論, 任何的分布式系統中, 只能最多滿足CAP(一致性/高可用性/分區容忍性)中的兩種.
由以上圖數據, 對比, 我們可以發現, 傳統關系型數據庫很難滿足大寬表(列多且稀疏)的數據存儲, 因此我們就選用HBase作為我們的存儲模型.

檢索分析
HBase作為分布式列式存儲, 對列多且稀疏分布的數據支持非常的好. 而對於實時檢索, HBase借助rowkey來實現, 其支持key的范圍/前綴搜索, 檢索性能非常好. 因此要應用好hbase, 其rowkey的設計成為至關重要的一環. 根據實戰的經驗, rowkey由多個字段構成且支持key前綴檢索, 這有點類似與傳統關系型數據庫的復合索引. 但不足的方面是, hbase表只有一個rowkey, 換句話說就是只有一個索引, 同時多個字段組成的rowkey, 需要等寬字節來構建它. 這些因素就對上述的檢索需求產生了影響.
回到最初的應用場景, 其檢索需求有時間序列檢索和面檢索, rowkey設計方案如下:
1). rowkey格式: timestamp:site_id:others, 其把時間字段作為rowkey的前綴, 對面檢索(檢索某個時間點, 列出各個站點的要素信息)友好, 而對時間序列檢索(檢索該站點在某個時間范圍的要素檢索)不友好. 前者利用到了rowkey前綴, 后者利用不到, 因此掃描范圍變大, 效率迅速降低.
2). rowkey格式: site_id:timestamp:others, 把站點id放在rowkey的前綴, 則結果恰好於上相反.
由此可見, 兩種rowkey設計方案, 都無法同時滿足時間序列檢索和面檢索. 那我們該這么辦?
數據雙寫, 采用數據冗余的方式, 構建兩張表. 一張表采用timestamp:site_id:others作為rowkey的設計方案, 另一張則采用site_id:timestamp:others作為rowkey的設計方案. 同時這兩張表的數據內容完全一樣, 這樣就能滿足上述的時間序列檢索和面檢索的需求了. 這種冗余方案, 在分布式mysql集群中, 被廣泛的運用.
評注: 數據雙寫, 是作為HA(高可用性)的一種方案, 常用的HA策略有主從備份(存在單點故障).
寫優化
盡管數據雙寫方案解決了上述檢索需求(讀性能高), 但以tiemstamp作為rowkey前綴的hbase表, 存在寫入熱點問題. 因為hbase的region是按rowkey的范圍來划分的, 而數據的時間密集性很高, 導致幾乎所有的數據都擱在同一個region上, 導致寫熱點問題. 因此我們需要對數據雙寫方案進行補充, 使得能夠解決數據寫入熱點問題.
rowkey前綴加salt, 采用隨機/hash(站點)的方式生成salt, 這樣分散了寫入, 避免了熱點問題. 當然加salt是有代價的, 它加大讀取數據的難度, 因為原本連續的數據被分散到了不同region上.

該圖取之書籍<<hbase權威指南>>, 表明了不同的salt選擇對讀寫性能的影響.
最終方案:
針對該應用場景, 采用HBase作為底層儲存方案.
1). 數據雙寫的模式, 構建兩張表, 數據冗余.
2). 表A以hash(site_id):timestamp:site_id:others作為rowkey, hash(site_id)表示對站點id取模作為salt.
3). 表B以site_id:timestamp:others作為rowkey, 站點(site_id)個數較多, 分散性好.
