HadoopのCDH4で完全分散環境構築した
基本的には、Clouderaの
http://www.cloudera.com/content/support/en/documentation/cdh4-documentation/cdh4-documentation-v4-latest.html
ここにある、ドキュメントにそってやっただけ。
意外とすんなりできました。
英語のドキュメントしかねぇから、英語の勉強もかねて
和訳したのをどっかで公開するのもありかと思ったけど
著作権的にアウトだった。。。
HDFS、MapReduce、HBaseが動くまでの手順をまとめてみる。
この記事に全部詰め込む予定だから、だいぶ長くなるかも。
マシン構成は、マスタ1台、スレーブ2台。
NameNodeHA試すために、この後、マスタを1台追加する予定だけど
それはまた別のお話。
まずはネットワーク周りの設定。
ホスト名の設定
# hostname master10
/etc/hostsにクラスタを構成するマシンのホスト名とIPを記述
192.168.1.10 master10 master10
192.168.1.11 slave11 slave11
192.168.1.12 slave12 slave12
的な感じ。
# uname -a
コマンドで、設定したホスト名が含まれてたらOK?
ファイヤウォール停止
本当は、ポート番号指定して、許可する設定をするべきなんだろうけど
ひとまずは・・・。
# /etc/init.d/iptables stop
次に、NameNode、DataNode、JobTracker、TaskTrackerとかのインストール。
あぁ、いまさらだけど、OSはCentOS6.4です。
・各ノード共通
# cd /etc/yum.repos.d/
# wget http://archive.cloudera.com/cdh4/redhat/6/x86_64/cdh/cloudera-cdh4.repo
・NameNodeにて
# yum install hadoop-hdfs-namenode
# yum install hadoop-0.20-mapreduce-jobtracker
# yum install hbase-master
# yum install zookeeper-server
・DataNodeにて
# yum install hadoop-hdfs-datanode
# yum install hadoop-0.20-mapreduce-tasktracker
# yum install hbase-regionserver
次、設定ファイル周り。
# cd /etc/hadoop
# cp -r conf.empty conf.my_cluster
# alternatives --verbose --install /etc/hadoop/conf hadoop-conf /etc/hadoop/conf.my_cluster 50
# alternatives --set hadoo-conf /etc/hadoop/conf.my_cluster
# alternatives --display hadoop-conf
で、確認。
で、今コピーして、向き先を設定したmy_clusterの中の
core-site.xmlに、以下の記述を追加
fs.defaultFS hdfs://master10:8020/ hadoop.tmp.dir /tmmp/hadop-${user.name}
次、NameNodeのhdfs-site.xmlに以下の記述を追加。
dfs.permissions.superusergroup hadoop dfs.name.dir /data/1/dfs/nn
DataNodeのhdfs-site.xmlには以下の記述を追加。
dfs.permissions.superusergroup hadoop dfs.name.dir /data/1/dfs/dn,/data/2/dfs/dn,/data/3/dfs/dn
hdfs-site.xml中で指定したディレクトリを作成、所有者、パーミッションを修正。
NameNodeにて
# mkdir -p /data/1/dfs/nn
# chown -R hdfs:hdfs /data/1/dfs/nn
# chmod 700 /data/1/dfs/nn
DataNodeにて
# mkdir -p /data/1/dfs/dn /data/2/dfs/dn /data/3/dfs/dn
# chown -R hdfs:hdfs /data/1/dfs/dn /data/2/dfs/dn /data/3/dfs/dn
# chmod 700 /data/1/dfs/dn /data/2/dfs/dn /data/3/dfs/dn
HDFSは、とりあえずこれで、準備が整ったので
NameNodeとDataNodeを起動する。
まずは、NameNodeの初期化
NameNode起動
DataNode起動y
# /etc/init.d/hadoo-hdfs-datanode start
/var/log/hadoo-hdfs/配下のログにエラーとか出てなければ
# jps
で、NameNodeとDataNodeがいるはず。
jpsコマンドがない人は
# yum install openjdk-1.7.0-devel(だいたいこんな感じ・・・)
で、インストール。
動作確認は、まず
でディレクトリを作成できるか。
次に、適当なファイルを用意して
で、ファイルをHDFSにおけるか確認。おければOK。
次、MapReduce
conf配下にmapreduce-site.xmlを作成して、以下の記述をする。
<?xml version="1.0" ?> <?xml-stylesheet type="text/xsl" href="configuration.xsl" ?> <configuration> <property> <name>mapred.job.tracker</name> <value>master10:8021</value> </property> <property> <name>mapred.local.dir</name> <value>/data/1/mapred/local,/data/2/mapred/local,/data/3/mapred/local</value> </property> </configuration>
ただし、mapred.local.dirはDataNodeのmapred-site.xmlにのみ記述。
(NameNodeのmapred-site.xmlはmapred.job.trackerだけ)
DataNodeにて、mapred.local.dirで指定したディレクトリを作成、オーナーを変更。
# mkdir -p /data/1/mapred/local /data/2/mapred/local /data/3/mapred/local
# chown -R mapred:hadoop /data/1/mapred/local /data/2/mapred/local /data/3/mapred/local
# su - hdfs
$ hadoop fs -mkdir /tmp
$ hadoop fs -chmod -R 1777 /tmp
/varディレクトリ作成
$ hadoop fs -mkdir /var/lib/hadoop-hdfs/cache/mapred/mapred/staging
$ hadoop fs -chmod -R 1777 /var/lib/hadoop-hdfs/cache/mapred/mapred/staging
$ hadoop fs -chown -R mapred /var/lib/hadoop-hdfs/cache/mapred
mapred.system.dirディレクトリ作成
$ hadoop fs -mkdir /tmp/mapred/system
$ hadoop fs -chown mapred:hadoop /tmp/mapred/system
これで、MapReduceの準備が整ったので、JobTrackerとTaskTrackerを起動
NameNodeにて
DataNodeにて
まずは、/var/log/hadoop-0.20-mapreduce配下のログファイルにエラーが
出てないことを確認。
その後、以下のコマンドで、エラーが出なければOK
# cd /etc/hadoop-0.20-mapreduce
# hadoop jar hadoop-example.jar pi 4 1000
次、zookeeper
設定ファイル、/etc/zookeeper/confo/zoo.cfg
に以下の記述を。
dataDir=/tmp/zookeeper
server.1=master10:2888:3888
dataDirは修正する必要ないかも。初期設定の/var/lib/zookeeperはもうあるよって
怒られたんだけど、後でする、初期化時に、--forceオプションをつければ問題ない?
正直、よくわからない。
以下のコマンドで、初期化と起動
# /etc/init.d/zookeeper-server init --myid=1
# /etc/init.d/zookeeper-server start
最後、HBase
各ノードのhbase-site.xmlに以下の記述を追加。
hbase.cluster.distributed true hbase.rootdir hdfs://master10:8020/hbase hbase.zookeeper.quorum master10
hbase-site.xmlで指定したディレクトリをHDFS上に作成
# su - hdfs
$ hadoop fs -mkdir /hbase
$ hadoop fs -chown hbase /hbase
これでHBaseの準備が整ったので起動するだけ。
NameNodeにて
# /etc/init.d/hbase-master start
DataNodeにて
# /etc/init.d/hbase-regionserver start
# hbase shell
で、テーブル作成したりなんなりができればOK
ふぅ・・・長かった。
インタフェースって便利だね!
ついったーで軽くしたやり取りをメモ。
発端は、forの中にifを書くか、ifの中にforを書くか、どっちがいいの!?ってお話。
具体的には
boolean bool = true; if (bool) { for (略) { 〜〜 } } else { for (略) { 〜〜 } }
こっちがいいのか
boolean bool = true; for (略) { if (bool) { 〜〜 } else { 〜〜 } }
こっちがいいのか。
同じ条件のforを何個も書くのも馬鹿らしいけど
ループのたびに変わらない条件判定も馬鹿らしい。
この疑問に対する一つの回答を教えてもらいました。
「delegate使えばいいんじゃね。」
javaではdelegateは使えないので、
インタフェース使って、同じような仕組みを書いてみた。
まず、インタフェース。
public interface Delegate { public void invoke(int num); }
で、メインクラス。
public class DelegateTestMain { public static void main(String[] args) { boolean branch = true; Delegate delegate = null; if (branch) { delegate = new Delegate() { int sum = 0; @Override public void invoke(int num) { this.sum += num; System.out.println(this.sum); } }; } else { delegate = new Delegate() { int prod = 1; @Override public void invoke(int num) { this.prod *= num; System.out.println(this.prod); } }; } for (int i = 1; i <= 10; i++) { delegate.invoke(i); } } }
branchがtrueだったら、1〜10総和を一つずつ出力
falseだったら、1〜10総乗を一つずつ出力するよ。
例として適当かどうかは置いておいて
ifの条件判定も1回だし、forも1回で済んでるNE!
他にも、インタフェース使うと、メソッドを引数に渡すみたいなことができて便利ネ。
public interface Delegate<R> { public R invoke(String arg); }
こんなインタフェースと
public class DelegateTestMain { public static void main(String[] args) { Delegate<List<String>> delegateList = null; Delegate<Map<String, String>> delegateMap = null; delegateList = new Delegate<List<String>>() { @Override public List<String> invoke(String arg) { List<String> retList = new ArrayList<String>(); retList.add(arg); return retList; } }; delegateMap = new Delegate<Map<String, String>>() { @Override public Map<String, String> invoke(String arg) { Map<String, String> retMap = new HashMap<String, String>(); retMap.put(arg, arg); return retMap; } }; System.out.println(getData(delegateList)); System.out.println(getData(delegateMap)); } private static <R> R getData(Delegate<R> delegate) { return delegate.invoke("test"); } }
こんなメインクラスとかで、やらせたい処理で、戻り値の型も変えられるし。
札幌Ruby会議2012に行ってみたYO
9月14〜16日に札幌で開催された、Ruby会議に行ってみたよ。
参加できたのは16日だけだったのだけども・・・
Rubyは触ったことがある程度で、書いたコードの行数を
数えることができるほどだと思うのだけど、
Rubyでバリバリコードを書いてないとわからない、なんてことも全然なくて
俺は普段仕事でJAVA(たまにJavascript)しか書いてないけど
興味深い話はたくさんあって、面白かった。
初日、は無理としても、せめて二日目と懇親会にはでたかった・・・。
一日会場にいて、一番感じたのは、自分から行動しないと、ってことかなー
こういうイベントに参加するのもそうだし
参加したうえでコミュニケーション取っていくこともそうだし
コードを書いていくこともそうだし
きれいなコードを他の人に伝えるのもそうだし
英語の勉強もそうだし
残念ながら特に2番目は全然できなくて、セッションを聞くだけになってしまったのだけど
だれかの感想にもあったけど、セッションを聞くだけならUstでもいいわけで
せっかく会場に行くからには、何かしらアクションを起こさないと
もったいなかったかなぁ・・・と思う。
あと、英語だよ、英語。せっかく、薦めてもらったセッションも
半分も理解できなくてすごくもったいなかった。
せっかく理解できたところも、本筋とは関係ない余談だったりとかしてw
ちょっと前にOSCに行ってみたときも思ったけど、
こういうイベントに参加している人って本当に生き生きしてて、楽しそうだから
次はその中に入れたらいいなぁ、と思うね!
一日だけだったけど、本当に有意義な時間だったと思う。
誘ってくれた@snoozer05さんには感謝です。
jettyでテスト用簡易サーバ
微妙にはまったのでメモ
すげー頭の悪いはまり方だったから、自戒の意味もこめて・・・orz
まずは結論を簡単に
・jettyの8はservlet3、7は2.5だ。バージョンの違いに注意。
・7.3.1⇒7.6.1のどこかで、HttpConnectionが
AsyncHttpConnectionとBlockingHttpConnectionに分かれた。
そりゃ、HttpConnectionが解決できません、って怒られるわ・・・。
以下経緯。
JUnitでWebサービスのモックを作る
これを参考にして、簡易サーバを立てようとしたわけだ
なるほど、最新版は8.1.1か・・・とりあえずこれでいいか、とダウンロードして
ビルドパスに追加。
で、↑のソースをほぼコピペして、とりあえず動かしてみて
一週間くらいまえにHttpClient4でmixiにつないでみたで触ったHttpClientで
つないでみた・・・が、AsyncContextがみつからねぇぞ、と怒られてしまう。
ここみると、Servletのバージョンのせいらしい。なるほど確かに、jettyのDLページを見ると、8ってServlet3じゃないですか
今作ってるもので使ってるのって、2.5じゃないですか。8じゃだめじゃないですか。
ってことで、7の最新、7.6.1をDLして、ビルドパス修正、再実行。
おぉ、繋がった。が、Responseに設定した値が取れない。
↓のようにコメントアウトしてる部分か・・・。
private static class RequestHandlerImpl extends AbstractHandler { @Override public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { response.setCharacterEncoding("UTF-8"); response.setContentType("application/json"); response.setStatus(HttpServletResponse.SC_OK); Writer writer = response.getWriter(); writer.write(TEST_RESULT); // HttpConnectionが解決できないのでとりあえずコメントアウト //HttpConnection connection = // HttpConnection.getCurrentConnection(); //Request req = connection.getRequest(); //req.setHandled(true); } }
参考にしたブログは7.3.1、使おうとしてるのは7.6.1
いくらバージョンが違うとはいえ7.X.Xなのに・・・と思って、7.6.1のjavadoc見てたら
あったよ、↓の三つが・・・!
AbstructHttpConnection
AsyncHttpConnection
BlockingHttpConnection
なるほど、HttpConnectionが非同期通信のために二つに分かれたのか・・・。
というわけで、早速修正。
private static class RequestHandlerImpl extends AbstractHandler { @Override public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { response.setCharacterEncoding("UTF-8"); response.setContentType("application/json"); response.setStatus(HttpServletResponse.SC_OK); Writer writer = response.getWriter(); writer.write(TEST_RESULT); AbstructHttpConnection connection = BlockingHttpConnection.getCurrentConnection(); Request req = connection.getRequest(); req.setHandled(true); } }
めでたく、レスポンスに設定した値も取れるようになりましたとさ。
参考にしたブログの記事は1年も立ってないのに、変わってしまうもんだねぇ・・・。
簡単なサーブレットのテスト
たとえばこんな、すごく単純なサーブレット
public void doGet(HttpServletRequest request, HttpServletResponse response) { response.setStatus(200); }
200 OKを返すだけの、本当に単純なサーブレット
流石にここまで単純なのはないけど、あくまで例として。
こんな、単純なものでも試験はせにゃならないわけで
そのためだけに、EasyMockとかわざわざ入れるのもどうかと思った。
じゃあ、自前で実装すればいいじゃない
やりたいことは、setStatus(int)だけなのだから
public MockHttpServletResponse implements HttpServletResponse { private int status; @Override public void setStatus(int i) { this.status = i; } // 試験用(ステータスコードを取得) public int getStatus() { return status; } //以下盛大に省略 }
これだけの実装をしたモックさんを用意して
MockHttpServletRequest mockResponse = new MockHttpServletRequest(); testServlet.doGet(null, mockResponse); int status = mockResponse.getStatus();
こうやってやれば、statusに何セットしたかどうかわかるよねっ!
これだけなら、非常に簡単なお話だったのだけど、
テストしたかったサーブレットはこんなこともやってた。
public void doGet(HttpServletRequest request, HttpServletResponse response) { PrintWriter out = response.getWriter(); out.print("<html></html>"); // 中略 response.setStatus(200); }
PrintWriter#printとかちょっと詰んだ気しかしない。
でも、ちょっと頑張ってみたら、意外と簡単に何とかなった。
というわけで、実装追加したモックさん。
public MockHttpServletResponse implements HttpServletResponse { private int status; StringWriter stringWriter = new StringWriter(); @Override public void setStatus(int i) { this.status = i; } // 試験用(ステータスコードを取得) public int getStatus() { return status; } @Override public void getPrintWriter() { return new PrintWriter(stringWriter); } // 試験用(PrintWriterで出力した文字列を取得) public String getPrintWritedString() { return stringWriter.toString(); } //以下やっぱり盛大に省略 }
これくらいの実装なら、自分で書いちゃったほうが早いよね。多分。
Eclipseなら必要なメソッドはreturn nullとかで適当に実装してくれちゃうし。
今回は初回だったんで時間かかったけど。
HTMLのお話
多分知っている人には、知ってて当然だけど
知らない人にとっては、結構面白いと思う
そして多分、Web系の開発するなら知ってなきゃいけないお話。
面白かったのでメモ。
発端
俺「<div></div>って何なの?javascriptとかでよく使うけど。」
答「ブロック要素を作るタグだよ」
あまりにもぴんと来なかった俺に丁寧に回答してくれました。
聞いた話を、自分の中で消化し切れてはいないので
突っ込みどころ満載な気がする。指摘おねぎしまう。
HTMLってタグ使って書くよね
<p></p>で囲めば段落をあらわすし
<a></a>で囲めばリンクを貼れる。
で、そもそもの前提として
HTMLのタグって大きく分けて2種類ある。
ブロックを作るか、作らないか、だ。
<h1>とかのタイトルを表すタグや、前述