HBase查詢優化之Short-Circuit Local Reads


1.概述

在《HBase查詢優化》一文中,介紹了基於HBase層面的讀取優化。由於HBase的實際數據是以HFile的形式,存儲在HDFS上。那么,HDFS層面也有它自己的優化點,即:Short-Circuit Local Reads。本篇博客筆者將從HDFS層面來進行優化,從而間接的提升HBase的查詢性能。

2.內容

Hadoop系統在設計之初,遵循一個原則,那就是移動計算的代價比移動數據要小。故Hadoop在做計算的時候,通常是在本地節點上的數據中進行計算。即計算和數據本地化。流程如下圖所示:

 

在最開始的時候,短回路本地化讀取和跨節點的讀取的處理方式是一樣的,流程都是先從DataNode讀取數據,然后通過RPC服務把數據傳輸給DFSClient,這樣處理雖然流程比較簡單,但是讀取性能會受到影響,因為跨節點讀取數據,需要經過網絡將一個DataNode的數據傳輸到另外一個DataNode節點(一般來說,HDFS有3個副本,所以,本地取不到數據,會到其他DataNode節點去取數據)。

 2.1 方案一:客戶端直接讀取DataNode文件

短回路本地化讀取的核心思想是,由於客戶端和數據在同一個節點上,所以DataNode不需要在數據路徑中。相反,客戶端本身可以簡單地讀取來自本地磁盤的數據。這種性能優化集成在CDH的Hadoop相關項目中,實現如下圖所示:

這種短回路本地化讀取的思路雖然很好,但是配置問題比較麻煩。系統管理員必須更改DataNode數據目錄的權限,以便客戶端有權限能夠打開相關文件。這樣就不得不專門為那些能夠使用短回路本地化讀取的用戶提供白名單,不允許其他用戶使用。通常,這些用也必須被放置在一個特殊的UNIX組中。

另外,這種本地化短回路讀取的思路還存在另外一個安全問題,客戶端在讀取DataNode數據目錄時打開了一些權限,這樣意味着,擁有這個目錄的權限,那么其目錄下的子目錄中的數據也可以被訪問,比如HBase用戶。由於存在這種安全風險,所以這個實現思路已經不建議使用了。

2.2 方案二:短回路本地化安全讀取

為了解決上述問題,在實際讀取中需要非常小心的選擇文件。在UNIX中有這樣一種機制,叫做“文件描述符傳遞”。使用這種機制來實現安全的短回路本地讀取,而不是通過目錄名稱的客戶端,DataNode打開Block文件和元數據文件,將它們直接給客戶端。因為文件描述符是只讀的,用戶不能修改文件。由於它沒有進入Block目錄本身,它無法讀取任何不應該訪問的目錄。

舉個例子:

現有兩個用戶hbase1和hbase2,hbase1擁有訪問HDFS目錄上/appdata/hbase1文件的權限,而hbase2用戶沒有改權限,但是hbase2用戶又需要訪問這個文件,那么可以借助這種“文件描述符傳遞”的機制,可以讓hbase1用戶打開文件得到一個文件描述符,然后把文件描述符傳遞給hbase2用戶,那么hbase2用戶就可以讀取文件里面的內容了,即使hbase2用戶沒有權限。這種關系映射到HDFS中,可以把DataNode看作hbase1用戶,客戶端DFSClient看作hbase2用戶,需要讀取的文件就是DataNode目錄中的/appdata/hbase1文件。實現如下圖所示:

2.3 緩存文件描述

HDFS客戶端可能會有經常讀取相同Block文件的場景,為了提升這種讀取性能,舊的短回路本地讀取實現具有Block路徑的高速緩存。該緩存允許客戶端重新打開其最近已讀取的Block文件,而不需要再去訪問DataNode路徑讀取。

新的短回路本地讀取實現不是一個路徑緩存,而是一個名為FileInputStreamCache的文件描述符緩存。這樣比路徑緩存要更好一些,因為它不需要客戶端重新打開文件來重新讀取Block,這種讀取方式比就的短回路本地讀取方式在讀性能上有更好的表現。

緩存的大小可以通過dfs.client.read.shortcircuit.streams.cache.size屬性來進行調整,默認是256,緩存超時可以通過dfs.client.read.shortcircuit.streams.cache.expiry.ms屬性來進行控制,默認是300000,也可以將其設置為0來將其進行關閉,這兩個屬性均在hdfs-site.xml文件中可以配置。

2.4 如何配置

為了配置短回路本地化讀取,需要啟用libhadoop.so,一般來說所使用Hadoop通常都是包含這些包的,可以通過以下命令來檢測是否有安裝:

 $ hadoop checknative -a
   Native library checking:
   hadoop: true /home/ozawa/hadoop/lib/native/libhadoop.so.1.0.0
   zlib:   true /lib/x86_64-linux-gnu/libz.so.1
   snappy: true /usr/lib/libsnappy.so.1
   lz4:    true revision:99
   bzip2:  false

短回路本地化讀取利用UNIX的域套接字(UNIX domain socket),它在文件系統中有一個特定的路徑,允許客戶端和DataNode進行通信。在使用的時候需要設置這個路徑到Socket中,同時DataNode需要能夠創建這個路徑。另外,這個路徑應該不可能被除了hdfs用戶或root用戶之外的任何用戶創建。因此,在實際創建時,通常會使用/var/run或者/var/lib路徑。

短回路本地化讀取在DataNode和客戶端都需要配置,配置如下:

<configuration>
  <property>
    <name>dfs.client.read.shortcircuit</name>
    <value>true</value>
  </property>
  <property>
    <name>dfs.domain.socket.path</name>
    <value>/var/lib/hadoop-hdfs/dn_socket</value>
  </property>
</configuration>

其中,配置dfs.client.read.shortcircuit屬性是打開這個功能的開關,dfs.domain.socket.path屬性是DataNode和客戶端之間進行通信的Socket路徑地址,核心指標配置參數如下:

屬性 描述
dfs.client.read.shortcircuit 打開短回路本地化讀取,默認false
dfs.client.read.shortcircuit.skip.checksum 如果配置這個參數,短回路本地化讀取將會跳過checksum,默認false
dfs.client.read.shortcircuit.streams.cache.size 客戶端維護一個最近打開文件的描述符緩存,默認256
dfs.domain.socket.path DataNode和客戶端DFSClient通信的Socket地址
dfs.client.read.shortcircuit.streams.cache.expiry.ms 設置超時時間,用來設置文件描述符可以被放進FileInputStreamCache的最小時間
dfs.client.domain.socket.data.traffic 通過UNIX域套接字傳輸正常的數據流量,默認false

3.總結

短回路本地化讀取能夠從HDFS層面來提升讀取性能,如果HBase場景中,有涉及到讀多寫少的場景,在除了從HBase服務端和客戶端層面優化外,還可以嘗試從HDFS層面來進行優化。

4.結束語

這篇博客就和大家分享到這里,如果大家在研究學習的過程當中有什么問題,可以加群進行討論或發送郵件給我,我會盡我所能為您解答,與君共勉!

另外,博主出書了《Hadoop大數據挖掘從入門到進階實戰》,喜歡的朋友或同學, 可以在公告欄那里點擊購買鏈接購買博主的書進行學習,在此感謝大家的支持。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM