hue-logo

スチールです。この記事はHadoop Advent Calendar 2013の14日目の記事です。
13日目の記事はkmizumarさんの「cdh-twitter-exampleで遊ぶ」です。

さて今回はhueについて、ちょろっと手を加えてみたのでそちらについてまとめてみます。
hueはHadoop運用してる方にはおなじみだと思われる、WebのUIでHadoopが使えるというプロダクトです。
職場でも、運用には参加していないメンバーがhiveやImpalaを中心にこのhueを通して集計作業をしています。

そのhueのHAを組む記事が「High Availability of Hue」にあるので、そちらを元に環境構築の検証をしていたのですが、記事内のHA Proxyの設定に 
When the balance parameter is set to source, a client is guaranteed to communicate with the same server every time it makes a request. If the server the client is communicating with goes down, the request will automatically be sent to another active server. This is necessary because Hue stores session information in process memory.
とあったので、 キャッシュをmemcachedにすればラウンドロビンとかでもできるんじゃないかなと思って改造を考え出した次第です。

hueのソースはgithubにてclouderaが公開しています。https://github.com/cloudera/hue
ソースをちょろっと見ればすぐわかるのですが、hueはpythonのdjangoで開発されていますので、 djangoを触ったことがあれば大体検討がつくんではないかと思います。(自分は0.9系のずいぶん前にちょろっとさわったくらいでした)
今運用しているhueのバージョンが2.5なので、djangoは1.2系です。
(hue3はdjango1.4にverupしている模様)

hueのソース構成は、desktop以下がコアとなっていて、hue上に展開されるhiveやImpala、hbaseのアプリがapps以下に展開されています。今回いじるのはdesktop以下です。

最終的にrpmにして再利用しやすいようにビルドしたかったので、clouderaからhueのSRPMを持ってきてそちらをビルドしました。

変更点は下記です。

ざっくりと変更展の説明を。
まず、インストール後にhue自体のソースを変更するのは見通しが悪くなるため、hue.iniにcacheという項目で設定変更できるようにしました。
で、その設定はdesktop/core/src/desktop/conf.pyで読み込まれるため、そこにCACHEという項目を追加。
defaultの値は、hueがdjango自体のglobal_settings.pyの値をそのまま使用しているためそこに準拠しました。
最後に、djangoアプリとしてのhueに反映させるため、desktop/core/src/desktop/settings.pyに各設定を上書きできるようにします。

実際にインストールしたあとは、hue.iniのcacheのbackendを
backend=memcached://example.local:11211
なんて設定すればOKです。 key_prefixはお好みで。 衝突する可能性があるなら何か入れておいた方がよいかもしれません。

手元の環境ではpythonのmemcachedクライアントがなかったのでpython-memcachedをpipなんかでインストールする必要があるのですが、それもrpmbuildする際に組み込まれるようにしました。
こちらはpypiから(https://pypi.python.org/pypi/python-memcached/)ソースをダウンロードしてきて展開しました。 
tar.gzの展開先は、hueのdesktop/core/ext-py/以下に展開するだけでOKです。
展開した後のライブラリ群はこんな感じになると思います。
# ls -la rpmbuild/SOURCES/hue-2.5.0-cdh4.4.0/desktop/core/ext-py/
合計 172                                                                        
drwxr-xr-x 43 nn nn 4096 12月 14 15:08 2013 .
drwxr-xr-x  5 nn nn 4096  9月  4 12:44 2013 ..
drwxr-xr-x  6 nn nn 4096  9月  4 12:44 2013 Babel-0.9.6
drwxr-xr-x  3 nn nn 4096  9月  4 12:44 2013 BabelDjango-0.2.2
drwxr-xr-x  7 nn nn 4096  9月  4 12:44 2013 Django-1.2.3
drwxr-xr-x  7 nn nn 4096  9月  4 12:44 2013 Mako-0.7.2
drwxr-xr-x  3 nn nn 4096  9月  4 12:44 2013 MarkupSafe-0.9.3
drwxr-xr-x  5 nn nn 4096  9月  4 12:44 2013 MySQL-python-1.2.3c1
drwxr-xr-x  5 nn nn 4096  9月  4 12:44 2013 Paste-1.7.2
drwxr-xr-x  7 nn nn 4096  9月  4 12:44 2013 PyYAML-3.09
drwxr-xr-x  6 nn nn 4096  9月  4 12:44 2013 Pygments-1.3.1
drwxr-xr-x  4 nn nn 4096  9月  4 12:44 2013 Spawning-0.9.6
drwxr-xr-x  4 nn nn 4096  9月  4 12:44 2013 avro-1.5.0
drwxr-xr-x  3 nn nn 4096  9月  4 12:44 2013 configobj
drwxr-xr-x  6 nn nn 4096  9月  4 12:44 2013 ctypes-1.0.2
drwxr-xr-x  4 nn nn 4096  9月  4 12:44 2013 django-auth-ldap-1.0.7
drwxr-xr-x  3 nn nn 4096  9月  4 12:44 2013 django-extensions-0.5
drwxr-xr-x  3 nn nn 4096  9月  4 12:44 2013 django-moxy
drwxr-xr-x  3 nn nn 4096  9月  4 12:44 2013 django_nose
drwxr-xr-x  5 nn nn 4096  9月  4 12:44 2013 elementtree
drwxr-xr-x  3 nn nn 4096  9月  4 12:44 2013 enum-0.4.4
drwxr-xr-x  6 nn nn 4096  9月  4 12:44 2013 eventlet-0.9.14
drwxr-xr-x  6 nn nn 4096  9月  4 12:44 2013 greenlet-0.3.1
drwxr-xr-x  4 nn nn 4096  9月  4 12:44 2013 httplib2-0.8
drwxr-xr-x  5 nn nn 4096  9月  4 12:44 2013 kerberos-1.1.1
drwxr-xr-x  3 nn nn 4096  9月  4 12:44 2013 lockfile
drwxr-xr-x  8 nn nn 4096  9月  4 12:44 2013 lxml
drwxr-xr-x  7 nn nn 4096  9月  4 12:44 2013 markdown
drwxr-xr-x  2 nn nn 4096  9月  4 12:44 2013 pam
drwxr-xr-x  6 nn nn 4096  9月  4 12:44 2013 pyopenssl
drwxr-xr-x  5 nn nn 4096  9月  4 12:44 2013 pysqlite
drwxr-xr-x  4 nn nn 4096  9月  4 12:44 2013 python-daemon
drwxr-xr-x  7 nn nn 4096  9月  4 12:44 2013 python-ldap-2.3.13
drwxrwxr-x  3 nn nn 4096  6月  8 02:14 2013 python-memcached-1.53  #追加されたやつ
drwxr-xr-x  6 nn nn 4096  9月  4 12:44 2013 python-oauth2
drwxr-xr-x  5 nn nn 4096  9月  4 12:44 2013 pytidylib-0.2.1
drwxr-xr-x  3 nn nn 4096  9月  4 12:44 2013 sasl-0.1.1
drwxr-xr-x  5 nn nn 4096  9月  4 12:44 2013 simplejson
drwxr-xr-x  4 nn nn 4096  9月  4 12:44 2013 south
drwxr-xr-x  4 nn nn 4096  9月  4 12:44 2013 ssl-1.15
drwxr-xr-x  2 nn nn 4096  9月  4 12:44 2013 threadframe-0.2
drwxr-xr-x  3 nn nn 4096  9月  4 12:44 2013 thrift
drwxr-xr-x  2 nn nn 4096  9月  4 12:44 2013 urllib2_kerberos-0.1.6
以上の変更をしたあと、rpmbuildを行います。自分の環境だとJDK1.7環境だったため、hue-2.5.0-cdh4.4.0/maven/pom.xmlのjavaVersionとtargetJavaVersionを1.7にしてビルドしました。
なお、ビルドにはmavenといくつか依存関係があるので、hue2.5.0のドキュメントのHue Dependenciesを参考にインストールしておいてください。

長くなってきたので、ここでSRPMのダウンロードからビルドするところまでの流れを書いてみます。
# wget "http://archive.cloudera.com/cdh4/redhat/6/x86_64/cdh/4.4.0/SRPMS/hue-2.5.0+139-1.cdh4.4.0.p0.70.src.rpm"
# rpm -ivh hue-2.5.0+139-1.cdh4.4.0.p0.70.src.rpm
# cd rpmbuild/SOURCES/
# tar xzvf hue-2.5.0-cdh4.4.0.tar.gz
上記gistのdiffのパッチをあてるか編集する
# cd rpmbuild/SOURCES/hue-2.5.0-cdh4.4.0/desktop/core/ext-py/
# wget "https://pypi.python.org/packages/source/p/python-memcached/python-memcached-1.53.tar.gz" --no-check-certificate
# tar xzvf python-memcached-1.53.tar.gz
# rm python-memcached-1.53.tar.gz 
jdkによってはpom.xmlを編集
# cd rpmbuild/SOURCES/
# rm hue-2.5.0-cdh4.4.0.tar.gz
# tar czvf hue-2.5.0-cdh4.4.0.tar.gz hue-2.5.0-cdh4.4.0
# rm -rf hue-2.5.0-cdh4.4.0
# cd rpmbuild
# /usr/bin/rpmbuild -ba SPECS/hue.spec
これでできたrpmをインストールすればめでたく改造版hueのインストール完了です。

インストール後、hueは標準でsqliteを利用しているため、複数のhueから参照できるようにmysqlやpostgresqlにsyncする必要があります。

syncの手順もhueのドキュメントの「5.3. The Hue Database」にありますので、その手順に従ってください。
ただこちらにもハマリどころがありまして、mysql5.6を使用していると、hueがtext型にdefault値を設定している部分があり、
BLOB/TEXT column 'hoge' can't have a default value
といったエラーでsyncdbがうまく動きません。参考→ MySQL5.6で今までのVerでは問題無かったSQL文がエラーになった場合の対処法

これについては、my.cnfに
sql_mode=''
と設定してあげるのが(共存している他のdbに影響がなければ)一番手っ取り早いです。 
共存したdbに置くためmysqlの再起動がしづらい環境だったり、sql_modeを変えるのが厳しい場合は(自分の場合は共存してるdbをあまり止めたくなかった)、migrationのファイルを変えてあげればなんとかなります。
hueはsouthというmigrationツールを使っているのですが、southが生成するファイルに手を加える形になります。
text型にalterする部分を消去したりして対応したのですが、ホントにこれでいいのかはまだ未検証です(一応動いている様子)
あまり自信は無いのでgistのリンクだけ貼っておきます→こちら

ここまで終えて、「High Availability of Hue」にあるHA proxyの設定のbalanceをroundrobinにしても無事に動いています。
ただ、beeswaxサーバーのホストは1つ選んで指定してあげないとうまくhueからhiveクエリを投げられないので若干片手落ち感はあります。その辺の課題は今後という事で。

以上、hadoopというより、djangoの話になっちゃったような気がしますが、hadoop advent calendar14日目の記事でした。

明日の15日目は@hishidamaさんです。お楽しみに!