HBaseワークショップ(第一回)

| # Comments
先日5月20日(金)にHBaseワークショップ(第一回)が開催されました。

HBaseについて、メインの参加者間での情報交換を中心としたディスカッションを行いました。
周りの方々からも質問等があればいつでも声をかけていただき、話をふくらませていくスタイルでした。
このような会に参加させていただいたことを、心より感謝いたします。

今回はこの勉強会の当日に、発言しておけばよかった、言葉足らずだった、後で思ったこと等をまとめておこうと思います。

何に使っている・使いたいのか?

Twitter Streamingからのデータの取り込みをしています。

素人ながら、統計解析、機械学習や自然言語処理などの分野を勉強しようと思っていて、そのためのデータ収集をしています。
そのための基盤をHadoop MapReduceでやろうと思ったので、連携のしやすいHBaseを選択しました。

現状ではデータ収集を安定して行えるような施策をしたり、次の集計などをうまく行うためのいろいろな設計を試しているところです。

キーの設計

HBaseをうまく使うためには、キーの設計は非常に大きなウェイトを占めます。
これまでTwitter Streamingの件でいろいろ試してみて思ったところは次のようなパターンです。

画面等から参照する必要がある場合はPrefixで局所化

WebUIなどの画面からデータ参照をするのであれば、参照する単位で局所化します。

例えばTwitterであれば、基本的に各ユーザーのツイートを一覧で参照することになりますので、ユーザーIDをキーのPrefixとし、ステータスID(の逆順)もしくはタイムスタンプ(の逆順)をその後に置けば、各ユーザーのツイートを局所化して持つことができます。
場合によっては、2個目、3個目のPrefixを追加します。

このようにすると、キー範囲指定のScanを使えるようになるので高速にデータにアクセスすることができます。

注)「逆順」は、例えばLong.MAX_VALUEから引き算するなどした値を利用します。

MapReduceの入力に使うならひたすら分散

局所化の必要がなく、MapReduceの入力データとして利用するのであれば、ひたすら分散させます。
データを一意に特定できる何か、をハッシュしたりすると充分に分散できます。

データ量が多くなることが予め分かっているのであれば、テーブル作成時にリージョン分割をすることをおすすめします。
キーにハッシュを利用するのであれば000・・・からfff・・・までの範囲に均等に配置されることが期待できるので、割り当て可能なMap数分程度に分割しておけばMapを適度に分散して処理することができます。

特殊な場合

HBaseは、時系列、連番をキーとして扱うことが苦手なことが分かっています。

キーが単調増加、もしくは単調減少すると、一番下、もしくは一番上のリージョンに書き込み負荷が集中することになります。

1つのリージョンで充分に処理できる程度しか書き込みがない場合で、どうしても時間範囲、連番の範囲でScanする必要がある場合を除いては採用しないほうがいいと思います。

HBaseWD

やむを得ず、かつ書き込みを多少でも分散したい、という場合には、HBaseWDというライブラリが利用できます。
これは、各キーにPrefixを付けてくれるライブラリです。

例えば[0-f]をPrefixとして、順繰り、ランダム、などで付け、書き込み負荷を16個に分散します。
Scanの時には[0-f]のPrefixをつけた16個のScanを行います。

良くも悪くもPrefixに利用する値の種類しか分散しませんので、他にいい方法があればそちらを採用すべきだと思います。

カラムファミリーの使い方

論理的分類

基本的には論理的分類によってカラムファミリーをわけます。
Twitter取り込みの最新の実装では status、user、place、user_mentions、urls、hashtags、delete となっています。

論理的分類で分けるだけでも、それなりにアクセスパターンも分類できている印象です。

tall table vs fat wide table

tall table(縦長テーブル) vs fat wide table(横長テーブル) の議論がHBaseのMLでよく行われています。

tall tableは、RDBのテーブルのように、ほぼ同じカラム数で行数が増えていく(縦に伸びる)テーブルで、fat wide tableは、qualifierを利用することで、カラム数が増えていく(横に伸びる)テーブルです。

実は、初期のTwitter Streaming取り込みの実装ではfat wide table方式を採用していました。
具体的には、キーにユーザーIDで、カラムファミリーstatusに対してqualifierにステータスIDを指定して、そのユーザーのツイートを同じ行内で横に入れていました。

fat wide tableの利点は、1つのキーが指定出来れば、紐づくデータを一括で取れるところです。なので、キーの並びを気にせず、自由に分散することができます。(データの偏りは発生します)

HBaseを使ったMapReduceへの入力は、キー毎にmapへ入力されます。
fat wide tableを使うと、mapに同じキーに紐づくデータを一気に投入できるので、reduceで行うような処理をmapで行うことができることがあります。
予めshuffleの結果と同等のテーブル設計にしておくと、多段に及ぶMapReduce処理の分岐、合流地点の受け皿としてかなり有用です。

大きな問題点は、行の肥大化です。
特定の行が太りすぎてしまっても、その行が複数のリージョンに分割されることはありません。
また、mapへの入力時にメモリの問題にもなりかねません。

fat wide tableはとても有用ですが、利用の際にはそのあたりの見積りも必要となります。

(修正 2011/06/05: "fat table"という表現はあまり使われていないようなので、wide tableに改めました。)
(訂正 2011/06/14: "fat table"は、セルに大きなデータを持つようなテーブルのことを指すようです。大変失礼しました。)

思うこと

貧乏性な発想では、うまくいかない場合が多い。
元々大規模向けに作られているので、そのように発想の転換が必要。
(とかいうと個人でやってる身としてはツライですが。。。)

おまけ

雑談、飲み会の時に個人的にヒットした発言。

@ashigeruさん: 「データのダム」 -> 「最悪テーブルごと入れ替える」
@doryokujinさん: 「どこもがんばってるんですね。」

反省

もっと積極的に発言を。
話題提供のためにも、説明をスムーズにするためにも、資料を作っていく。

というわけで、次回は6月16日(木)を予定しています。
またよろしくお願いします!


comments powered by Disqus

Twitter Icon

AdSense

Creative Commons License
このブログはクリエイティブ・コモンズでライセンスされています。
Powered by Movable Type 5.14-ja

Google検索

カスタム検索

2013年10月

    1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31