1. 程式人生 > >Hbase常用面試題和高階查詢

Hbase常用面試題和高階查詢

Hbase常用面試題和高階查詢

一、HBase的工作方式
  hbase表中的資料按照行鍵的字典順序排序,hbase表中的資料按照行的的方向切分為多個region,最開始只有一個region 隨著資料量的增加 產生分裂 這個過程不停的進行 一個表可能對應一個或多個region。region是hbase表分散式儲存和負載均衡的基本單元 一個表的多個region可能分佈在多臺HRegionServer上,region是分散式儲存的基本單元 但不是儲存的基本單元內部還具有結果。
  一個region由多個Store來組成,有幾個store取決於表的列族的數量 一個列族對應一個store 之所以這麼設計 是因為 一個列族中的資料往往資料很類似方便與進行壓縮節省儲存空間,表的一個列族對應一個store store的數量由表中列族的數量來決定,一個store由一個memstore 和零個或多個storefile組成,storefile其實就是hdfs中的hfile 只能寫入不能修改。
  資料寫入hbase時 先在hlog中記錄日誌 再修改memstore 直接返回成功 這樣 不需要真正等待寫入hdfs的過程 所以很快,memstore 記憶體有限 當寫入數量達到一定的閾值的時候 就會建立一個新的memstore繼續工作 而舊的memstore 會用一個單獨的執行緒 寫出到storefile中,最終清空舊的memstore 並在zookeeper中記錄最後寫出資料時間的redo point資訊,由於storefile 不能修改 所以資料的更新其實是不停建立新的storefile的過程,這樣多個storefile中可能存在對同一個資料的多個版本 其中舊的版本其實是垃圾資料 時間一長 垃圾資料就可能很多浪費磁碟空間,所以當達到一定的閾值的時候 會自動合併storefile 在合併的過程中將垃圾資料清理,而當合並出來的檔案達到一定程度時 再從新進行切分,防止檔案過大,雖然看起來是小變大再變小,但是經過這個過程垃圾資料就被清理掉了。
  所以store中的資料 其實是memstore和storefile來組成的,而memstore由於是記憶體中的資料 一旦斷電就會丟失,為了解決可能的意外造成資料丟失的問題 hbase在整個hregionserver中 通過記錄hlog 來儲存了所有資料操作的記錄,當hbase啟動時 會檢查zookeeper中的redopoint資訊 從hlog中恢復 這個時間點之後的資料 解決資料容易丟失的問題,hlog整個hregionServer中只有一個 所有這臺機器中的所有HRegion都公用這個檔案 這樣整個機器的磁碟效能都可以為這一個檔案提供支援提升檔案的讀寫效率,hlog檔案最終對應的是hdfs中的檔案,也是分散式儲存的,保證了日誌檔案的可靠性。
  而在資料讀取時會將store的中memstore和storefile中的資料進行合併提供查詢,此處所謂的合併,並不是真正的資料的合併,而是將資料的索引進行合併,由於hbase中的資料天然排序,再加上索引,整個查詢也可以非常的快。
二、叢集結構資訊


  hbase中的老大叫hmaster 小弟叫hregionServer,客戶端叫Client,Zookeepr為hbase提供叢集協調。
  client:訪問hbase 保留一些快取資訊提升效率
  zookeeper:保證任何時候叢集只有一個HMaster。監控regionServer的狀態 將其上線下線資訊通知mater。儲存所有Region的定址地址。儲存hbase的元資料資訊包括有哪些表、有哪些列族等等。
  Mater:為RegionServer分配Region。為RegionServer進行負載的均衡。hdfs上的垃圾回收。處理對Schema資料的更新請求.
  RegionServer:維護Master分配給它的region,處理對這些region的IO請求。負責切分在執行過程中變得過大的region
三、為什麼hbase可以很快?

  從邏輯結構上來說:
   表按照行鍵進行了排序,所以查詢時可以很快定位。
   資料按照行鍵切分為多個HRegion,分佈在多個RegionServer中,查詢大量資料時,多個RegionServer可以一起工作,從而提高速度。
  從物理結構上來說:
   HRegion是存活在RegionServer的記憶體中的,讀寫會非常的高效。
   還有HFile的支援保證大量的資料可以持久化的儲存。
   資料最終落地到HDFS中,分散式的儲存,保證資料段可靠性和可擴充套件性。
四、為什麼hbase可以儲存很多資料?
  基於hdfs,所以支援可擴充套件性,可以通過增加大量的廉價的硬體提高儲存容量。
  按列儲存,空的資料不佔用空間,當儲存稀疏資料時,不會浪費空間。
  按例儲存,同一列的資料存放在一起,而同一列的資料一般都是同樣的型別的內容相似的資料,可以實現非常高效的壓縮,節省空間。
五、為什麼hbase的資料是可靠的?

  基於hdfs,由hdfs的可靠性保證了hbase的可靠性–即資料可以有多個備份。
  利用zookeeper實現了HA,即使某一臺機器掛掉另外的機器也可以很快的替換它。
六、hbase和hive和傳統的關係型資料庫的比較:
  比起傳統的關係型資料庫,可以儲存半結構化非結構化的資料,可以儲存和處理更大級別的資料,提供高效的查詢,對於稀疏資料的處理更好,具有更好的橫向擴充套件性,免費開源價效比很高。但是不能支援非常好的事務特性,只支援行級的事務。只能通過行鍵來查詢,表設計時難度更高。而mysql用來儲存結構化的資料提供更好的事務控制。
  比起hive,hive只是在mapreduce上包了一層殼,本質上還是離線資料的處理的工具,實時查詢效能有限,本質上是一個基於hadoop的資料倉庫工具,不能支援行級別的新增修改和刪除。hbase可以提供實時的資料的處理能力,適用於線上資料查詢處理,本質上是一種資料庫工具。
六、HBase的高階查詢
  (1)實現範圍查詢
   如果只設置scan但是不做任何限制 則查詢所有資料
    Scan scan = new Scan();
   如果設定scan並且設定scan的掃描開始和結束為止則查詢範圍資料 注意含頭不含尾
    Scan scan = new Scan();
    scan.setStartRow(“rk2”.getBytes());
    scan.setStopRow(“rk4”.getBytes());
   (2)過濾器實現過濾查詢

			在scan上提供了方法來實現過濾查詢
				Scan scan = new Scan();
				Filter filter = ...
				scan.setFilter(filter)
			Hbase內建的14種過濾器
				HBase為篩選資料提供了一組過濾器,通過這個過濾器可以在HBase中的資料的多個維度(行,列,資料版本)上進行對資料的篩選操作,也就是說過濾器最終能夠篩選的資料能夠細化到具體的一個儲存單元格上(由行鍵,列明,時間戳定位)。
				Filter filter = new RowFilter(CompareOp.GREATER_OR_EQUAL,new BinaryComparator("rk3".getBytes()));
				//--RowFilter配合正則過濾器 可以通過正則表示式從hbase表中篩選所有行鍵符合正則的資料
				!!Filter filter = new RowFilter(CompareOp.EQUAL,new RegexStringComparator("^[^x]*x[^x]*$"));
				Filter filter = new PrefixFilter("rkx".getBytes());
				Filter filter = new KeyOnlyFilter();
				Filter filter = new RandomRowFilter(0.2f);
				Filter filter = new InclusiveStopFilter("rk4".getBytes());
				Filter filter = new FirstKeyOnlyFilter();
				//--ColumnPrefixFilter可以實現按照列的字首過濾資料
				!!Filter filter = new ColumnPrefixFilter("c2".getBytes());
				//--ValueFilter可以按照值來過濾資料
				!!Filter filter = new ValueFilter(CompareOp.EQUAL,new RegexStringComparator("^[^2]*2.*$"));
				//--SingleColumnValueFilter按照某一個指定列的值決定該行是否返回
				!!Filter filter = new SingleColumnValueFilter("cf1".getBytes(), "c1".getBytes(), CompareOp.EQUAL, new RegexStringComparator("^[^3]*3.*$"));
				//--FilterList 可以將多個過濾器的效果合併起作用
				!!Filter f1 = new RowFilter(CompareOp.EQUAL,new RegexStringComparator("^rk\\d+$"));
				!!Filter f2 = new KeyOnlyFilter();
				!!FilterList fl = new FilterList(Operator.MUST_PASS_ALL, f1,f2);
				scan.setFilter(fl);

七、HBase的表設計
  對HBase表的設計會直接影響hbase使用的效率和使用的便利性,主要是 列族的設計 和 行鍵的設計。
  1.列族的設計
   在設計hbase表時候,列族不宜過多,越少越好,官方推薦hbase表的列族不宜超過3個。
   經常要在一起查詢的資料最好放在一個列族中,儘量的減少跨列族的資料訪問。
   如果有多個列族,多個列族中的資料應該設計的比較均勻。
  2.行鍵的設計
   hbase表中行鍵是唯一標識一個表的欄位,所以行鍵設計的好不好將會直接影響未來對hbase的查詢的效能和查詢的便利性,所以hbase中的行鍵是需要進行設計的。
   行鍵設計的基本原則:
    行鍵必須唯一:必須唯一才能唯一標識資料
    行鍵必須有意義:這樣才能方便資料的查詢
    行鍵最好是字串型別:因為數值型別在不同的系統中處理的方式可能不同
    行鍵最好具有固定的長度:不同長度的資料可能會造成自然排序時排序的結果和預期不一致
    行鍵不宜過長:行鍵最多可以達到64KB,但是最好是在10~100位元組之間,最好不要超過16位元組,越短越好,最好是8位元組的整數倍。
   行鍵的最佳實踐:
    雜湊原則:行鍵的設計將會影響資料在hbase表中的排序方式,這會影響region切分後的結果,要注意,在設計行鍵時應該讓經常要查詢的資料分散在不同的region中,防止某一個或某幾個regionserver成為熱點。
    有序原則:行鍵的設計將會影響資料在hbase表中的排序方式,所以一種策略是將經常連續查詢的條件作為行鍵最前面的資料,這樣一來可以方便批量查詢。
八、HBase二級索引的設計
  涉及到多個條件組合查詢時,hbase就有點力不從心了,因為hbase支援的是三種方式,上面已經提到了,對於多條件組合查詢來說,如果通過某個條件filter出來一部分資料,然後再一個個判斷,這樣比較影響效能。但又不能將
這些條件都設計到rowkey中去,這時可以考慮到用二級索引。
  二級索引的實現:設計兩個列族,一個列族什麼資料都不存,存放索引的key就對應這個列族,另一個列族就對應主資料,主資料的rowkey就是之前業務正常設計好的,現在通過二級索引來滿足多條件組合查詢。資料還是和之前不變,只是多用一些資源來存放索引的rowkey。先通過多條件找到二級索引的rowkey,然後再擷取到最終查詢主資料的rowkey,這樣就可以實現多條件組合查詢了。
  其實也可以將這些組合條件放入mysql,通過mysql找到查詢主資料的rowkey,然後用這個rowkey去hbase中查詢,得到最終結果。
  詳情參考這篇部落格:Hbase二級索引的設計
九、Hbase的快取原理
  hbase的快取由兩部分組成,一部分是memstore,一部分是blockcache。一個regionServer對應多個region和一個blockcache,每個region對應一個memstore,寫入資料的時候,是先寫預寫日誌,上文已經說了,然後再寫入memstore,當memstore達到閾值,將資料寫入hfile中。讀取資料的時候先到memstore中找,沒有的話再去blockcache中找,最後再去hfile中讀取。這裡就有一個LRU演算法問題,確認是blockcache是經常查詢的資料。
  想去參考這篇部落格:hbase快取機制
十、Hbase調優
  1、Scan 快取
   如果HBase的輸入源是一個MapReduce Job,要確保輸入的Scan的setCaching值要比預設值0要大。使用預設值就意味著map-task每一行都會去請求一下region-server。可以把這個值設為500,這樣就可以一次傳輸500行。當然這也是需要權衡的,過大的值會同時消耗客戶端和服務端很大的記憶體,不是越大越好。
  2、Scan 屬性選擇
   當Scan用來處理大量的行的時候(尤其是作為MapReduce的輸入),要注意的是選擇了什麼欄位。如果呼叫了 scan.addFamily,這個列族的所有屬性都會返回。如果只是想過濾其中的一小部分,就指定那幾個column,否則就會造成很大浪費,影響效能。
  3、關閉 ResultScanners
   這與其說是提高效能,倒不如說是避免發生效能問題。如果你忘記了關閉ResultScanners,會導致RegionServer出現問題。所以一定要把ResultScanner包含在try/catch 塊中…
  4、塊快取
   Scan例項可以在RegionServer中使用塊快取,可以由setCacheBlocks方法控制。如果Scan是MapReduce的輸入源,要將這個值設定為 false。對於經常讀到的行,就建議使用塊緩衝。
  5、行鍵的負載優化
   當scan一個表的時候, 如果僅僅需要行鍵(不需要no families, qualifiers, values 和 timestamps),在加入FilterList的時候,要使用Scanner的setFilter方法的時候,要填上MUST_PASS_ALL操作引數(譯者注:相當於And操作符)。一個FilterList要包含一個 FirstKeyOnlyFilter 和一個 KeyOnlyFilter.通過這樣的filter組合,就算在最壞的情況下,RegionServer只會從磁碟讀一個值,同時最小化客戶端的網路頻寬佔用。
  6、表建立: 延遲log刷寫
   Puts的預設行為使用 Write Ahead Log (WAL),會導致 HLog 編輯立即寫盤。如果採用延遲刷寫,WAL編輯會保留在記憶體中,直到刷寫週期來臨。好處是集中和非同步寫HLog,潛在問題是如果RegionServer退出,沒有刷寫的日誌將丟失。但這也比Puts時不使用WAL安全多了。延遲log刷寫可以通過 HTableDescriptor 在表上設定,hbase.regionserver.optionallogflushinterval預設值是1000ms。
  7、HBase 客戶端: 自動刷寫
   當你進行大量的Put的時候,要確認你的HTable的setAutoFlush是關閉著的。否則的話,每執行一個Put就要想區域伺服器發一個請求。通過 htable.add(Put) 和 htable.add( Put)來將Put新增到寫緩衝中。如果 autoFlush = false,要等到寫緩衝都填滿的時候才會發起請求。要想顯式的發起請求,可以呼叫flushCommits。在HTable例項上進行的close操作也會發起flushCommits