Blog
1年経ってiPhone4の電池がヘタってきた、太田です。
指数関数的にエントリ数が少なくなってきた本ブログですがw、景気付けのためにエントリを投稿したいと思います!本日はHBaseについてです。
Linux と Hadoop と HBase と ZooKeeper に詳しいあなた!あなたがターゲットです。
HBaseとは?
HBaseとは、HDFS (Hadoop Distributed File System)上に構築された分散データベースです。大量の非常に細かいデータをリアルタイムに読み書き出来るのが特徴です。最近ではFacebook Messageの基盤技術として使用された事で注目を集めています。
保存されたデータはHDFS上に保存され、HDFSの仕組みによってレプリケーションされるため安全にデータを保持することが出来ます。
また、MapReduceとも非常に相性が良く、保存されたデータに対してバッチ処理を行なうことが出来ます。リアルタイムにデータを入出力しながら、分散でバッチ処理も出来るようになります。
これを検証するために、弊社ではTwitterのデータをリアルタイムにストリーミングで保存しながら解析するシステムを作ってみました。が、HBaseは色々と敷居が高くハマりどころも多かったので、そこで色々と試している結果をblogで紹介したいと思います。
OSのセットアップ
HBaseのセットアップの前に、OS (Linux) の設定を正しく行なうことが重要です。
最大ファイルディスクリプタ数
HBaseのノードでは1プロセスから大量のファイル/ソケットをopenする可能性が有るため、最大ファイルディスクリプタ数を上げておく必要があります。/etc/security/limits.confに以下の記述を追加して下さい。
root soft nofile 65536 root hard nofile 65536 * soft nofile 65536 * hard nofile 65536
一旦ログアウトして再度ログインし、ulimit -nコマンドで65536と表示されていればokです。
カーネルパラメータ
以下のパラメータを指定します。kernel.panic* 系でカーネルパニックが有った際に、マシンが自動リブートされるようにします。
vm.swappiness = 0で、メモリがスワップアウトされにくくします。HBaseの各ノードは大量のメモリを消費しますので、それらがディスクに追い出されにくい様にします。
net.* で、ネットワーク関連のバッファを増やしています。
kernel.panic_on_oops = 1 kernel.panic = 1 vm.swappiness = 0 net.core.rmem_max = 16777216 net.core.wmem_max = 16777216 net.ipv4.tcp_rmem = 4096 87380 16777216 net.ipv4.tcp_wmem = 4096 65536 16777216
ネットワークドライバのアップデート
大量のデータを転送するジョブを走らせると、以下のようにパケットドロップが大量に発生するという問題が起こりました。ifconfigで、droppedパケットが出ていないか確認します。
[root@hdp10 ~]# /sbin/ifconfig eth0 Link encap:Ethernet HWaddr 90:FB:A6:DD:2D:90 inet addr:192.168.0.60 Bcast:192.168.0.255 Mask:255.255.255.0 inet6 addr: fe80::92fb:a6ff:fedd:2d90/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:661312053 errors:0 dropped:14045 overruns:0 frame:0 TX packets:760148388 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:913845944363 (851.0 GiB) TX bytes:1043952570747 (972.2 GiB) Interrupt:169 Memory:b1a00000-b1a20000
余りに数が多くて不可思議な場合は、ネットワークドライバのアップデートで解消される可能性が有ります。
今回は、ネットワークドライバにe1000eを使用していたので、そちらをアップデートしました。こちらのblogが参考になります。
ntpdのセットアップ
ntpdをセットアップし、ノードの時刻が常に正しくなっているようにして下さい。
HBase本体は時刻がズレていても動作は正しく行えるように書かれているはずですが、不可解なバグの原因やログの検証時にかなり不便なので必ず設定して下さい。
Javaのセットアップ
なるべく新しめのJDKを使用します。必ず Oracle 純正の JDK を使用してください。 OpenJDK, GCJ は避けるようにします。
Hadoopのセットアップ
Hadoopのセットアップを行います。今回はCDH3u0 (Cloudera Distribution for Hadoop, Update 0)を使用しました。HadoopのバージョンとHBaseのバージョンはかなりシビアに合わせないといけないので、CDHを利用するのがおすすめです。
dfs.datanode.max.xceiversの設定
hdfs-site.xmlで、dfs.datanode.max.xceiversの値を増加させます。datanodeには、region serverから大量のコネクションを張られる可能性が有るために、この設定が必要です。
<property> <name>dfs.datanode.max.xcievers</name> <value>3072</value> </property>
ZooKeeperの設定
ZooKeeper専用ノードの検討
HBaseを入出力に使用するMapReduceジョブを動作させると、必ずZooKeeperへのコネクションがはられます。これが失敗すると、何も始まりません。
始め、ノードをけちってTaskTracker/DataNodeと同居させていたのですが、I/O負荷が上がるとOSのレスポンスが悪くなり、ZooKeeperへのコネクションが同時に切断されまくるという問題が起こりました。
安定稼働には、負荷の低いノードに同居させるか、専用ノードを用意するのがベターです。
maxClientCnxnsの設定
zoo.cfgで、maxClientCnxnsを設定します。こちらは、1ノードからのZooKeeperの最大コネクション数の設定です。デフォルトでは10に設定されています。
つまり、デフォルトでは1ノードから10並列以上繋げない事になります。MapReduceを使用した際には簡単に上限を超えてしまいますので、少し大きめの値を指定しておきます。
# max number of client connections from the same node maxClientCnxns=128
zoo.cfgの全ノードへの設置
zoo.cfgを全ノードの/etc/zookeeper/zoo.cfgに配備します。
HBaseのセットアップ
ついにHBaseのセットアップです。
RegionServerへのメモリの割当
RegionServerへは出来る限りメモリを割り当てます。ただし、MapReduceを行う場合には、タスクが使用するメモリも計算にいれておく必要があります。もし必要以上にメモリを食ってしまうと、OSのOOM KillerによってデーモンがKillされてしまう場合があります。
メモリの設定はhbase-env.shで行います。
# The maximum amount of heap to use, in MB. Default is 1000. export HBASE_HEAPSIZE=16384
MSLABの有効化
最近までのHBaseには、(特に大量のメモリを割り当てている場合)非常に時間のかかるGCが走ってRegion Serverが停止したように見えてしまう問題がありました。
これを解決するために、mslabという仕組みが導入されたのでそちらを有効化します。hbase-site.xmlに以下の設定を追加します。
<property> <name>hbase.hregion.memstore.mslab.enabled</name> <value>true</value> </property> <property> <name>hbase.hregion.memstore.mslab.chunksize</name> <value>2097152</value> </property>
mslabについては、こちらの記事を参考にして下さい。
/etc/hbase/conf/を全台に配置
/etc/hbase/conf/以下のファイルを全台に配置します。
HBaseを利用したMapReduceプログラムのポイント
HBaseを利用したMapReduceプログラムは、以下のようになります。TableMapReduceUtilを使用して InputFormat, OutputFormat を設定します。
zoo.cfg, /etc/hbase/conf/をクラスパスに追加
/etc/zookeeper/zoo.cfg, /etc/hbase/conf/をクラスパスに追加する事で、zookeeper/hbaseの設定ファイルを見つけてくれるようです。
意味不明なシステムなので、明示的にconf.addResourceで追加した方が良いかもしれません。
hbase.client.scanner.cachingの設定
ここで、hbase.client.scanner.cachingというパラメーターが非常に重要になります。
conf.set("hbase.client.scanner.caching", "1024");
HBaseを入力にしたMapReduceでは、Scannerを用いてキーバリューペアにシーケンシャルにアクセスします。この時、デフォルトでは1ペア毎にRPCリクエストを発行してペアを取得します。
hbase.client.scanner.cachingを1024にすると、1回のリクエスト1024個のペアをバッチで取ってくるため、非常に高速化されます。
手動リージョンスプリット
MapReduceプログラムを走らせていると、他のMapTaskと比較して100倍程度の時間がかかるTaskが有りました。このおかげでジョブの実行時間が非常に伸びてしまいます。
この場合は、そのタスクの担当しているリージョンを特定し、手動でsplitすることで細かいサイズに分けることが出来ます。何故、100倍もサイズが偏るのかはまだ謎です。
$ hbase shell hbase(main):001:0> split "twitter,43264430598914048,1302178394984.bb056008b2c069ad88ace728bcf0d757." 0 row(s) in 0.7930 seconds
肥大化したリージョンの特定方法は、時間の掛かっているタスクのログを心の目で見るか、JRubyでスクリプトを書いてみて特定します。
まとめ
HBaseは容量・用法に合わせて正しくセットアップしましょう。リアルタイムにデータを入れながら大規模データを解析出来るのは非常に嬉しいのですが、その反面、運用ノウハウはまだまだ必要そうです。
他にも使用されている方がいらっしゃいましたら、是非是非、フィードバックお待ちしています。
Tag