hbase零碎小記

1)hbase表查行
可以在shell中進行,命令如下:
count ’tablename’,CACHE=>10000,INTERVAL=>10000
CACHE是客戶端緩存條數,INTERVAL是分隔多久顯示一次結果

上述方法實現是走scan客戶端完成,一旦表較大,查起來很慢。

另外一種方式如下:
 bin/hbase org.apache.hadoop.hbase.mapreduce.RowCounter ’tablename’
通過yarn調度mr任務完成查行,速度較快。

2)客戶端連接hbase集羣時,與zookeeper建立起連接,需要加載兩個配置,一個是zookeeper的ip地址,還有是hbase在zookeeper上的根節點。
客戶端從zookeeper中獲得meta表的地址,然後從meta表中獲取表的region在regionserver間的分佈,至於數據讀寫請求則直接發往數據所在的regionserver。
hbase的client端會與zookeeper保持一個長連接,並在其上註冊一個watcher,用於檢測hbase集羣可能發生的變化,包括meta表位置的變化,regionserver的上下線以及region分佈的變化等等

3)hbase的bulkload
bulkload是高負載hbase的一種常見的優化方式,簡單來說就是先寫hdfs文件,然後直接裝載到hbase集羣,這種數據寫入方式不走client端的rpc通信,可以極大地節省集羣的I/O
形式上類似於solr的全量創建索引,線下搞定,然後線上只是裝載

4)blockcache的大小
  當前blockcache的大小可以從regionserver頁的block cache信息欄查看到。
調整參數hfile.block.cache.size可以修改block cache的大小,默認是0.4,表示使用整個堆大小(hbase-env.sh中配置的-Xmx)的40%作爲block cache,當內存緊張時可以考慮調小此值,但是不推薦。
hbase的blockcache機制是採用LRUBlockCache實現的。

5)hbase的IN_MEMORY屬性
hbase在LRU緩存基礎之上採用了分層設計,整個blockcache分成了三個部分,分別是single、multi和inMemory。三者區別如下:
single:如果一個block第一次被訪問,放在該優先隊列中;
multi:如果一個block被多次訪問,則從single隊列轉移到multi隊列
inMemory:優先級最高,常駐cache,因此一般只有hbase系統的元數據,如meta表之類的纔會放到inMemory隊列中。普通的hbase列族也可以指定IN_MEMORY屬性,方法如下:
create 'table', {NAME => 'f', IN_MEMORY => true}
修改上表的inmemory屬性,方法如下:
alter 'table',{NAME=>'f',IN_MEMORY=>true}

6)加載錯誤的協處理器coprocessor會導致regionserver大面積掛掉
在hbase的源碼中,參數hbase.coprocessor.abortonerror默認值是false,當其爲true的時候加載了錯誤的coprocessor後,會導致region server大面積餓down機,爲了保證集羣的高可用性,可以考慮將參數hbase.coprocessor.abortonerror修改爲true

7)一般情況下不建議直接採用kiill -9命令殺死正在運行的regionserver進程,可以採用graceful_stop命令使用優雅重啓解決,命令使用姿勢如下:
graceful_stop.sh --restart --reload --debug regionserver的host名

如果迫不得已採用kill -9 的方式殺死進程,則應該在殺死進程後儘快採用hbck工具修復集羣的region,避免產生數據的不一致:

bin/hbase hbck -repair


8)hbase split的最小單位是rowkey的個數,如果只有少數幾個rowkey,即便數據量增上去,但是還是不會發生region split。


9)hbase包含兩種coprocessor,分別是observer和endpoint,observer類似於觸發器,在發生某些事件(如put、get)的前後觸發這些代碼執行,

換句話說就相當於用戶埋在server端代碼的hook。endpoint又可以看做是數據庫中的存儲過程,它的優勢是可以利用服務端的計算資源,有點類似於mapreduce中

移動計算而不是移動數據的設計理念,應用endpoint可以進行數據統計計算,相比傳統的方式更加高效。

observer有兩種部署方式:

1、全局部署,把jar包路徑加入到hbase classpath,並修改hbase-site.xml,這樣引入的coprocessor對所有表生效

2、單表部署,通過hbase shell修改表結構,加入coprocessor信息

第二種方式採用alter命令實現,命令格式如下:

alter 'tablename',METHOD=>'table_att','coprocessor'=>'參數列表'

參數列表以|分隔,其依次爲:

1、coprocessor jar包的hdfs路徑

2、observer主類的完整路徑

3、優先級

4、參數(observer主類的輸入參數)


10)如果region在做類似於major_compact這種長時間的compact任務時儘量不要執行unassign操作,比如move、split或者disable等等。

這是由於unassign操作涉及到關閉region,如果關閉region時遇到了長時間阻塞的compact或者flush,會導致該region長時間陷入PENDING_CLOSE或者CLOSING狀態。


11)hbase的讀寫性能
hbase是個寫快讀慢的系統,寫較快的原因是hbase的LSM的數據結構決定的,數據寫道hbase時並沒有直接寫到磁盤,而是先寫到內存中skip-list結構的一個memstore中,再由其它線程選擇較大的memsotre刷寫到磁盤中。每一次磁盤刷寫都形成了一個StoreFile,StoreFile分層以及minor_compact和major_compact就是後話了。這種數據結構帶來的缺點就是讀放大,你讀一條數據要遍歷多個storeFile才能最終確定位置。所以hbase的隨機讀性能是比較差的。

12) hbase replication中隱藏的一個坑
replication用於在主從集羣間同步數據,包括源集羣和目的集羣,具體原理不在這裏展開,需要注意的是使用了replication再關掉的時候,如果僅僅只是disable peer而沒有disable replication table,該table的數據仍然會同步出來,此時同步出來的數據會寫到集羣的zookeeper中去,供下次enable peer的時候,這個時間差的數據能夠準確同步到從集羣。zookeeper中會積累大量的wal同步過來的數據,因此如果想要徹底地關掉replication,記住table的replication也要關掉。

13)應用snapshot複製一張表
我們假設要複製的表名爲testTable,可以按以下流程複製一張新表newTestTable:
首先,將原表打快照:
hbase> snapshot 'testTable','testTableSnapshot'
可以應用list_snapshots列出所有可用快照:
hbase>list_snapshots
應用打出的snapshot複製到新表:
hbase>clone_snapshot 'testTableSnapshot','testTable'
OK,萬事大吉

14)如果截取hbase的metrics信息
我們假設regionserver的ip地址是127.0.0.1,那麼這臺服務器上的metrics信息都保存在http://127.0.0.1:16030/jmx
其中16030是regionserver的web端口,向上述URL發送Http請求,可以獲得該regionsever的所有metrics信息,這些信息以Json串的形式返回,解析其中的metrics項便可。

15)hbase上使用hbck的一個小坑
hbase掛掉一臺regionserver以後,我們往往需要使用hbck命令來修復因爲regionserver掛掉導致的region空洞,這裏有個小坑,就是不能剛剛拉起regionserver就立刻運行hbck命令,而應該等到該region已經對外提供正常的服務之後,在運行hbck命令,指令順序如下:
bin/hbase-daemon.sh start regionserver //拉起regionserver
tail -f XXXX_regionserver.log //監控regionserver,觀察是否region遷移已完畢
bin/hbase hbck -repair
如果在regionserver還未完全正常服務時就repair,可能會導致數據不一致。

16)hbase的慢節點
hbase當集羣出現慢節點的時候可能拖跪整個集羣,這是由於慢節點吞掉大量的服務端線程,導致其它請求不能得到響應,進而線程又進一步被佔用,出現慢節點的可能情況包括:節點硬件故障、高併發大量的scan請求同時發生等等。

17)hbase的客戶端參數
爲防止hbase請求超時過長,拖跪業務方應用,建議在使用hbase的時候合理配置客戶端的超時時間,目前涉及到的超時時間包括以下三項:
hbase.client.operation.timeout.period:針對get/put/delete/append等常規請求的超時時間,默認是1200000(單位ms),這個超時時間指代的是從請求發出到結果返回的整段時間;
hbase.client.scanner.timeout.period:針對hbase的scan請求超時時間,默認60000(單位ms)
hbase.rpc.timeout:針對rpc請求的超時時間,一次完整的客戶端請求中會包含多次rpc請求,默認60000(單位ms)

18)scan場景下客戶端應該及時close
hbase中的一次scan請求是劃分成多次RPC請求發往服務端的,一次RPC請求獲取的數據由scan函數的setCaching指定,scan的總量和caching兩者的比值就是一個scan請求中的rpc次數。
scan過程中後面的rpc請求複用前面rpc請求的資源,因此大的scan中客戶端會一直持有服務端的資源,爲防止資源泄漏,服務端通過租約機制保證資源及時地釋放,如果在超過了租約的時間,而後續的客戶端請求並沒有發到服務端,此時服務端會銷燬掉scan擁有的資源,如果此時客戶端的請求陸續到來,服務端會出現LeaseException異常。
租約的超時時間由hbase.regionserver.lease.period控制,默認是60000ms。
因此客戶端的scan應該及時close掉,否則會在上面這個時間窗口內持有服務端的資源。在高併發場景下很容易導致服務端內存被佔滿,進而出現full GC。

19)客戶端的重聯的避讓算法
當regionserver掛掉或由於其它原因導致客戶端與服務端失去連接的時候,客戶端會重試以恢復與服務端的連接,重試的次數和時間由hbase中的如下兩個參數決定,分別是hbase.client.pause和hbase.client.retries.number,其中hbase.client.retries.number指定了最大重試次數,默認是31次,而hbase.client.pause是兩次重試之間的休眠(sleep)時間,默認是100ms,實際實現中休眠時間是隨着重試次數的增加而遞進增加的,代碼如下所示:
public static long getPauseTime(final long pause, final int tries) {
    int ntries = tries;
    if (ntries >= HConstants.RETRY_BACKOFF.length) {
      ntries = HConstants.RETRY_BACKOFF.length - 1;
    }

    long normalPause = pause * HConstants.RETRY_BACKOFF[ntries];
    long jitter =  (long)(normalPause * RANDOM.nextFloat() * 0.01f); // 1% possible jitter
    return normalPause + jitter;
  }

由此可見hbase.client.pause定義重試間隔時間的基線。
之所以需要設計上述的避讓算法,是爲了避免某個regionserver掛掉的時候,所有client都在同一時間發起重連的情況,這會導致啓動後的regionserver被大量衝進來的建連重新衝跨。

20)SingleColumnValueFilter的小坑
注意:當某一行沒有要過濾的字段時,SingleColumnValueFilter默認這一行是符合過濾條件的,查看源碼會發現這樣一段話:
 * To prevent the entire row from being emitted if the column is not found
 * on a row, use {@link #setFilterIfMissing}.
 * Otherwise, if the column is found, the entire row will be emitted only if
 * the value passes.  If the value fails, the row will be filtered out.
正確的姿勢如下:
SingleColumnValueFilter f1 = new SingleColumnValueFilter(Bytes.toBytes(FAMILY), Bytes.toBytes(QUALIFER), CompareOp.GREATER_OR_EQUAL, Bytes.toBytes(value));
f1.setFilterIfMissing(true);  //true 跳過改行;false 通過該行
filters.add(f1);

21)hlog
hlog中的數據是以key-value的形式組織的,需要注意的是發生多次修改的數據,所有的過往修改記錄都會統一寫成一條hlog中的記錄。對於某些需要實時解析hlog的日誌同步hbase新增數據的場景,直接應用該hlog記錄會出現錯誤,需要從中解析出最後寫入的那條記錄。

22)regionserver的Promotion Failure造成的Full GC問題

regionserver在持續運行了一段時間之後,偶爾會出現宕機掛掉的現象,翻看當時的GC日誌可以看到是CMS GC的時候出現了Promotion Failure現象,進而引發Full GC,而Full GC是stop the world的,如果時間較長,zookeeper長期收不到該region server上報上來的心跳就會將該region server判死,造成region server的宕機。

繼續探究Promotion Failure的原因,可能的原因是CMS GC不斷產生碎片,隨着系統運行時間越來越長,碎片逐漸累積,當累積到一定程度,新生代分配過來的對象發現沒有空間了,但是老年代的內存使用並沒有到XX:CMSInitiatingOccupancyFraction設置的百分比,此時就會觸發一次full gc。

避免方法比如調大XX:CMSInitiatingOccupancyFraction,使用堆外內存,使用G1 GC算法,同時也業務上要儘量避免字段過大的數據。


23)zookeeper的連接數
客戶端在使用hbase的時候,需要添加zookeeper的ip地址和節點路徑,建立起與zookeeper的連接,建立連接的方式如下面的代碼所示:
Configuration configuration = HBaseConfiguration.create();
configuration.set("hbase.zookeeper.quorum", "XXXX.XXX.XXX");
configuration.set("hbase.zookeeper.property.clientPort", "2181");
configuration.set("zookeeper.znode.parent", "XXXXX");
Connection connection = ConnectionFactory.createConnection(configuration);
需要注意的坑是上述變量需要在全局初始化,亦或者作爲一個單例對外提供服務,切忌在循環中或者在函數的局部方法裏反覆建立與zookeeper的連接,否則會導致zookeeper的連接數過高,影響服務的穩定性。檢查zookeeper服務的連接數可以使用下面的命令:
netstat -na | grep "2181" | wc -l

24)hbase的客戶端scan的時候有個配置方法setCacheBlocks,默認是true,表示用戶此次scan出來的數據會同時寫到服務端的讀緩存中一份,如果業務短時間內沒有重複讀取行爲,則建議修改爲false;

25)hive讀hbase的bytes類型的cell時會出現亂碼,解決方式如下:
a mapping entry must be either :key or of the form column-family-name:[column-name][#(binary|string) (the type specification that delimited by # was added in Hive 0.9.0, earlier versions interpreted everything as strings)
If no type specification is given the value from hbase.table.default.storage.type will be used
Any prefixes of the valid values are valid too (i.e. #b instead of #binary)
If you specify a column as binary the bytes in the corresponding HBase cells are expected to be of the form that HBase's Bytes class yields
一個可借鑑的例程如下所示:
CREATE TABLE hbase_table_1 (key int, value string, foobar double)
STORED BY 'org.apache.hadoop.hive.hbase.HBaseStorageHandler'
WITH SERDEPROPERTIES (
"hbase.columns.mapping" = ":key#b,cf:val,cf:foo#b"
);

26)如果表採用prefix-tree編碼,有可能會導致表的compact被堵住;

27)archive目錄會存放很多臨時文件,正常情況下master會每隔一定的時間清理archive中的文件,間隔時間由hbase.master.hfilecleaner.ttl來設置,默認是5分鐘;

28)業務導數據這種長時間任務造成gc時間過長,導致客戶端和zk的心跳時間超時,表象就是zk的連接數忽高忽低,據此推測是應用因爲心跳超時而反覆重建連接,在客戶端執行netstat -antp | grep 2181,查看客戶端到zk的連接狀態,可以發現很多處於TIME_WAIT狀態的連接;

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章