持つリージョンからしかデータが取れなくなった時の対処法
HBaseからとにかく全件を取得したいクライアントで起こる事象。
HBaseからとにかく全件を取得したいクライアントで起こる事象。
例えばHBaseをキューのように溜まってるデータを取ったら
消すようにして使用している場合。
具体的には org.apache.hadoop.hbase.client.Scan を何も設定せず
具体的には org.apache.hadoop.hbase.client.Scan を何も設定せず
そのまま使用していて、HBaseサーバ側でリージョン分割が
発生した場合に現象が発生する。
これはリージョンサーバの情報をクライアントが覚えておき、
これはリージョンサーバの情報をクライアントが覚えておき、
無駄な通信をしないようにする仕様から来ていると思われる。
分散システム前提のシステムをキューとして使用しようとすること
自体が設計に反しているが、それを敢えてやる場合の話である。
(上司が勘違いされている場合は、部下が必死で「HBaseを
キュートして使うのはちょっと違いますよ。」と説得しましょう。
HBaseはビッグデータの最終的な入れ物。前段でキューが必要なら
RDBを使った方がよほど良い。)
1番いいのはリージョン分割しないようにHBaseの分割サイズを
調整しHBaseに入るデータ量を上回るように、HBaseのパラメータおよび
取得クライアント側の性能を設計することだ。
HBaseリージョンサーバの分割設計は、MemStoreのフラッシュサイズと
リージョンサーバの最大サイズの設計からなる。
フラッシュサイズは
1. 固定値(hbase.hregion.memstore.flush.size)と
2. 計算値(hbase-env.shの HBASE_REGIONSERVER_OPTSで設定するヒープサイズ ×
hbase.regionserver.global.memstore.upperLimit and lowerLimit)
で調整できる。
(フラッシュとは、メモリからディスクへのフラッシュのこと)
また、リージョン分割のサイズは hbase.hregion.max.filesize で調整できる。
とは言ってもHBaseの仕組み上、リージョン分割は念頭に置かなければならない。
リージョン分割ありきで考えるならば、クライアントはいつ分割が発生しても
いいように備えなければならない。
リージョン分割ありきで考えるならば、クライアントはいつ分割が発生しても
いいように備えなければならない。
単純な順かつリソース消費量の順に案を挙げていくと、
1. 毎回HTableから作り直す。
2. 毎回リージョン情報をクリアする。(HTable#clearRegionCache())
3. 開始行キーを先頭にリセットする。(Scan#setStartRow())
となるだろうか。(実際の検証はしてないのであくまで推測。)
ということで3. の開始行キーを設定する方法を紹介する。
1. 毎回HTableから作り直す。
2. 毎回リージョン情報をクリアする。(HTable#clearRegionCache())
3. 開始行キーを先頭にリセットする。(Scan#setStartRow())
となるだろうか。(実際の検証はしてないのであくまで推測。)
ということで3. の開始行キーを設定する方法を紹介する。
// HTable htable = ...
Scan scan = new Scan();// use addFamily() when you want to set row family only,// but it's better to specify a column, because you're going to get
// all of data. this column would be like a second key.
// take care of your machine's memory.
scan.addColumn(Bytes.toBytes(FAMILY_XXX), Bytes.toBytes(COL_XXX));// set 0x00(null) so that HBase will scan from the first region server.scan.setStartRow(new byte[]{ (byte)0x00} );HashMapdataMap = new HashMap<>(); try(ResultScanner result = htable.getScanner(scan);) {for(Result item : result){// Row IDbyte[] rowId = result.getRow();// Column data example.byte[] data = result.getValue(Bytes.toBytes(FAMILY_XXX), Bytes.toBytes(COL_XXX));// for example, get small sortable value like date_and_time value.dataMap.put(rowId, data);}}// then sort the sortable value using Entry<>, sort of value.ArrayList> dataEntries = new ArrayList<>(dataMap.entrySet()); Collections.sort(dataEntries, (o1, o2) -> {// define how to sort between byte[].// for example parse byte[] to Long when the data is UNIX epoch time. (8bytes)Long t1 = ... // convert with ByteBuffer or something.return t1.compareTo(t2);});// loop with sorted key list.for( EntrydataEntry : dataEntries){ // then get all of columns with row id.// this is safer way because you can manage when you should stop the function or not.// you can choose resource or spec or ..Get get = new Get(dataEntry.getKey());Result result = htable.get(get);byte[] content = result.getValue(xxx);....}
0 件のコメント:
コメントを投稿