優化hbase的查詢優化-大幅提升讀寫速率(轉)
阿新 • • 發佈:2019-01-24
問題導讀:
1.本文通過什麼方法優化查詢效率的?
2.如何增大RPC數量?
3.如何調整hbase記憶體?
環境:suse 8G記憶體,8核,12T磁碟
hbase master 佔一臺,其他7臺作為hbase的region
注意:此處不討論hadoop
情景:
我們有7億的資料,需要做查詢操作,需要從1.7億的表中查詢一個欄位,並寫入到7億資料的表中。
這裡為了描述方便,將7億資料的表稱為:A表,1.7億資料的表稱為B表。
在初期,我們採用的邏輯是:將A表中的資料讀取一行,根據其中的某個欄位去組織一個GET,然後
立刻提交,從B表取得要查詢的欄位的值,組織成一個PUT,並提交到A表。
那麼這麼做的話,完全發揮不出hbase的效率,因為每個get之間它的key不一定連續,或者說是在同一範圍
而hbase的服務端會根據每個請求去載入資料到記憶體,由於請求的塊分散,那麼資料在記憶體中的替換過多的頻繁。
很有可能和直接讀取磁碟資料差不多。
並且採用這種邏輯去處理資料,需要花費時間太多。差不多是10W行讀寫資料需要40分鐘。這對於A表的更新操作
完全是不能接受的。
之後,通過讀資料的讀取操作進行封裝,組織成一個ArrayList<Get> 當到一定程度的時候採取提交。這裡還有一個情況就是
有些資料查詢不到,那麼需要去連線資料庫去申請一個自動分配的值,並立刻提交,因為後面可能有請求這個資料。
這就需要分開處理。
在組織GET 列表的時候需要先查詢,注意,不要採用table.get去取一個cell的值並判斷是否為null來處理。
而是用table.exist(get) 去查詢,這是在server-side跑的,效率要高很多。
對於查詢不到的值立刻申請值並寫入A表。
對於查詢的到的,那麼就可前面說的組織get 加入到GET列表中,到一定程度再去一次提交,在取到值之後,
在根據將迴圈資料的記錄,將這些組織成put,數量和GET列表一樣,不要去具體指定,在迴圈一次後直接table.put
其他引數修改方面,寫的都很多,這裡就不提了。
處理速度(取至其中一臺伺服器中跑的任務):
2011-12-30 17:10:03 Start Write Lines:1700000
2011-12-30 17:14:10 Writed Lines:1700000
2011-12-30 17:14:11 Start Write Lines:1800000
2011-12-30 17:18:21 Writed Lines:1800000
2011-12-30 17:18:22 Start Write Lines:1900000
2011-12-30 17:22:29 Writed Lines:1900000
2011-12-30 17:22:29 Start Write Lines:2000000
2011-12-30 17:26:37 Writed Lines:2000000
2011-12-30 17:26:37 Start Write Lines:2100000
大約是查詢,寫入速度是4分鐘處理10W行資料。
也就是4000/s的速率,較之前的處理方式提升了一個量級
參考:
1、使用bloomfilter和mapfile_index_interval
測試環境為:單機,規模為10萬條資料。隨機在10000條資料中有99條存在的情況下。
結論:開啟bloomfilter比沒開啟要快3、4倍。而適當的減少mapfile_index_interval可以提升效能 注意: 在1.9.3版本的hbase中,bloomfilter是不支援的,存在一個bug,可以通過如下的修改加以改正:
(1)、在方法org.apache.hadoop.hbase.region.HStore.createReaders()中,找到如下行
BloomFilterMapFile.Reader reader = file.getReader(fs, false, false);
將其改成
BloomFilterMapFile.Reader reader = file.getReader(fs, this.family.isBloomfilter(), false);
(2)、在方法org.apache.hadoop.hbase.HColumnDescriptor.toString()中,找到如下的程式碼行
if (key != null && key.toUpperCase().equals(BLOOMFILTER)) {
// Don't emit bloomfilter. Its not working.
continue;
}
將其註釋掉
2、hbase對於記憶體有特別的嗜好,在硬體允許的情況下配足夠多的記憶體給它。
通過修改hbase-env.sh中的
export HBASE_HEAPSIZE=3000 #這裡預設為1000m
3、修改java虛擬機器屬性
(1)、在環境允許的情況下換64位的虛擬機器
(2)、替換掉預設的垃圾回收器,因為預設的垃圾回收器在多執行緒環境下會有更多的wait等待
export HBASE_OPTS="-server -XX:NewSize=6m -XX:MaxNewSize=6m -XX:+UseConcMarkSweepGC -XX:+CMSIncrementalMode"
4、增大RPC數量
通過修改hbase-site.xml中的
hbase.region.handler.count屬性,可以適當的放大。預設值為10有點小
5、做程式開發是注意的地方
(1)、需要判斷所求的資料行是否存在時,儘量不要用HTable.exists(final byte [] row) 而用HTable.exists(final byte [] row, final byte[] column)等帶列族的方法替代。
(2)、不要使用HTable.get(final byte [] row, final byte [] column) == null來判斷所求的資料存在,而是用HTable.exists(final byte [] row, final byte[] column)替代
(3)、HTable.close()方法少用.因為我遇到過一些很令人費解的錯誤
6、記住HBase是基於列模式的儲存,如果一個列族能搞定就不要把它分開成兩個,關係資料庫的那套在這裡很不實用.分成多個列來儲存會浪費更多的空間,除非你認為現在的硬碟和白菜一個價。
7、如果資料量沒有達到TB級別或者沒有上億條記錄,很難發揮HBase的優勢,建議換關係資料庫或別的儲存技術。
1.本文通過什麼方法優化查詢效率的?
2.如何增大RPC數量?
3.如何調整hbase記憶體?
環境:suse 8G記憶體,8核,12T磁碟
hbase master 佔一臺,其他7臺作為hbase的region
注意:此處不討論hadoop
情景:
我們有7億的資料,需要做查詢操作,需要從1.7億的表中查詢一個欄位,並寫入到7億資料的表中。
這裡為了描述方便,將7億資料的表稱為:A表,1.7億資料的表稱為B表。
在初期,我們採用的邏輯是:將A表中的資料讀取一行,根據其中的某個欄位去組織一個GET,然後
立刻提交,從B表取得要查詢的欄位的值,組織成一個PUT,並提交到A表。
那麼這麼做的話,完全發揮不出hbase的效率,因為每個get之間它的key不一定連續,或者說是在同一範圍
而hbase的服務端會根據每個請求去載入資料到記憶體,由於請求的塊分散,那麼資料在記憶體中的替換過多的頻繁。
很有可能和直接讀取磁碟資料差不多。
並且採用這種邏輯去處理資料,需要花費時間太多。差不多是10W行讀寫資料需要40分鐘。這對於A表的更新操作
完全是不能接受的。
之後,通過讀資料的讀取操作進行封裝,組織成一個ArrayList<Get> 當到一定程度的時候採取提交。這裡還有一個情況就是
有些資料查詢不到,那麼需要去連線資料庫去申請一個自動分配的值,並立刻提交,因為後面可能有請求這個資料。
這就需要分開處理。
在組織GET 列表的時候需要先查詢,注意,不要採用table.get去取一個cell的值並判斷是否為null來處理。
而是用table.exist(get) 去查詢,這是在server-side跑的,效率要高很多。
對於查詢不到的值立刻申請值並寫入A表。
對於查詢的到的,那麼就可前面說的組織get 加入到GET列表中,到一定程度再去一次提交,在取到值之後,
在根據將迴圈資料的記錄,將這些組織成put,數量和GET列表一樣,不要去具體指定,在迴圈一次後直接table.put
其他引數修改方面,寫的都很多,這裡就不提了。
處理速度(取至其中一臺伺服器中跑的任務):
2011-12-30 17:10:03 Start Write Lines:1700000
2011-12-30 17:14:10 Writed Lines:1700000
2011-12-30 17:14:11 Start Write Lines:1800000
2011-12-30 17:18:21 Writed Lines:1800000
2011-12-30 17:18:22 Start Write Lines:1900000
2011-12-30 17:22:29 Writed Lines:1900000
2011-12-30 17:22:29 Start Write Lines:2000000
2011-12-30 17:26:37 Writed Lines:2000000
2011-12-30 17:26:37 Start Write Lines:2100000
大約是查詢,寫入速度是4分鐘處理10W行資料。
也就是4000/s的速率,較之前的處理方式提升了一個量級
參考:
1、使用bloomfilter和mapfile_index_interval
結論:開啟bloomfilter比沒開啟要快3、4倍。而適當的減少mapfile_index_interval可以提升效能 注意: 在1.9.3版本的hbase中,bloomfilter是不支援的,存在一個bug,可以通過如下的修改加以改正:
(1)、在方法org.apache.hadoop.hbase.region.HStore.createReaders()中,找到如下行
BloomFilterMapFile.Reader reader = file.getReader(fs, false, false);
將其改成
BloomFilterMapFile.Reader reader = file.getReader(fs, this.family.isBloomfilter(), false);
(2)、在方法org.apache.hadoop.hbase.HColumnDescriptor.toString()中,找到如下的程式碼行
if (key != null && key.toUpperCase().equals(BLOOMFILTER)) {
// Don't emit bloomfilter. Its not working.
continue;
}
將其註釋掉
2、hbase對於記憶體有特別的嗜好,在硬體允許的情況下配足夠多的記憶體給它。
通過修改hbase-env.sh中的
export HBASE_HEAPSIZE=3000 #這裡預設為1000m
3、修改java虛擬機器屬性
(1)、在環境允許的情況下換64位的虛擬機器
(2)、替換掉預設的垃圾回收器,因為預設的垃圾回收器在多執行緒環境下會有更多的wait等待
export HBASE_OPTS="-server -XX:NewSize=6m -XX:MaxNewSize=6m -XX:+UseConcMarkSweepGC -XX:+CMSIncrementalMode"
4、增大RPC數量
通過修改hbase-site.xml中的
hbase.region.handler.count屬性,可以適當的放大。預設值為10有點小
5、做程式開發是注意的地方
(1)、需要判斷所求的資料行是否存在時,儘量不要用HTable.exists(final byte [] row) 而用HTable.exists(final byte [] row, final byte[] column)等帶列族的方法替代。
(2)、不要使用HTable.get(final byte [] row, final byte [] column) == null來判斷所求的資料存在,而是用HTable.exists(final byte [] row, final byte[] column)替代
(3)、HTable.close()方法少用.因為我遇到過一些很令人費解的錯誤
6、記住HBase是基於列模式的儲存,如果一個列族能搞定就不要把它分開成兩個,關係資料庫的那套在這裡很不實用.分成多個列來儲存會浪費更多的空間,除非你認為現在的硬碟和白菜一個價。
7、如果資料量沒有達到TB級別或者沒有上億條記錄,很難發揮HBase的優勢,建議換關係資料庫或別的儲存技術。