HBase查詢優化之Short-Circuit Local Reads

哥不是小蘿莉發表於2018-08-12

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大資料探勘從入門到進階實戰》,喜歡的朋友或同學, 可以在公告欄那裡點選購買連結購買博主的書進行學習,在此感謝大家的支援。

相關文章