• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
Scala on Hadoop
 

Scala on Hadoop

on

  • 9,028 views

 

Statistics

Views

Total Views
9,028
Views on SlideShare
6,973
Embed Views
2,055

Actions

Likes
9
Downloads
105
Comments
0

10 Embeds 2,055

http://d.hatena.ne.jp 1863
http://blog.stanaka.org 90
http://stanaka.hatenablog.com 57
http://www.slideshare.net 32
http://webcache.googleusercontent.com 6
http://www.techgig.com 2
http://74.125.153.132 2
http://cache.yahoofs.jp 1
http://www.copyscape.com 1
http://translate.googleusercontent.com 1
More...

Accessibility

Categories

Upload Details

Uploaded via as Microsoft PowerPoint

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

    Scala on Hadoop Scala on Hadoop Presentation Transcript

    • Hadoop Conference Scala on Hadoop はてな 田中 慎司 stanaka @ hatena.ne.jp http://d.hatena.ne.jp/stanaka/ http://twitter.com/stanaka/
    • アジェンダ
      • 自己紹介
      • はてなでの Hadoop
        • Scala までの道
      • Scala on Hadoop
      • Scala on Hadoop の応用
    • 自己紹介
      • ( 株 ) はてな 執行役員
      • 担当領域
        • システムアーキテクチャ
          • スケーラビリティ
        • サーバ・ネットワーク
        • サポート
    • はてなでの Hadoop #1
      • 自作サーバ 10 台
        • CPU: Core2 Quad x 1
        • Mem: 8GB
        • HDD: 3TB
      • DC ではなくオフィスに置いて、電源代節約
    • はてなでの Hadoop #2
      • 蓄積されるデータ ( 主にログ )
        • ダイアリー 7G/day
        • ブックマーク 5G/day
        • うごメモ 3G/day
      • ジョブ
        • 300 jobs/day
    • はてなでの Hadoop システム ( 現状 ) Hadoop MapReduce HDFS Reverse Proxy ジョブの 投入 Hatena Fotolife Hatena Graph ログを 時間毎に蓄積 /logs/$service/$year/$month/$date/$host_access-$hour.log
    • Hadoop
      • 2008/5 頃 調査
        • Hadoop Streaming
      • 2008/8 頃 稼働
        • Perl による Mapper, Reducer
        • YAML でジョブを定義
      • 2009/4 WebUI を作成
      • 2009/11 Scala 化 ← イマココ
    • Hadoop Streaming
      • Java 以外の言語で MapReduce を可能に !
        • Map, Reduce の入出力を標準入力 / 標準出力として扱う -> map.pl, reduce.pl を用意するだけ
      • 通常は入力出力共に HDFS 上に置かれる
    • map.pl #!/usr/bin/env perl use strict; use warnings; while (<>) { chomp; my @segments = split /s+/; printf &quot;%s %s &quot;, $segments[8], 1; }
    • reduce.pl #!/usr/bin/env perl use strict; use warnings; my %count; while (<>) { chomp; my ($key, $value) = split / /; $count{$key}++; } while (my ($key, $value) = each %count) { printf &quot;%s %s &quot;, $key, $value; }
    • 実行 % hadoop jar $HADOOP_DIR/contrib/hadoop-*-streaming.jar -input httpd_logs -output analog_out -mapper /home/user/work/analog/map.pl -reducer /home/user/work/analog/reduce.pl
    • ジョブの定義
      • YAML で定義
      - name: latency mapper: class: LogAnalyzer::Mapper options: filters: isbot: 0 conditions: - key: Top filters: uri: '^/$' value: $response reducer: class: Reducer::Distribution input: class: LogAnalyzer::Input options: service: ugomemo period: 1 output: class: Output::Gnuplot options: title: &quot;Ugomemo Latency $date&quot; xlabel: &quot;Response time (msec)&quot; ylabel: &quot;Rates of requests (%)&quot; fotolife_folder: ugomemo
    • WebUI
    • Hadoop Streaming の限界
      • 遅い ← Perl の問題も ..
      • ジョブを KILL しても、プロセスが残ることがある
      • HDFS 操作が遅い
      • Combiner が定義できない
    • Scala
      • 2003 年登場
      • 関数型の特徴を備えた言語
      • 普通のオブジェクト指向っぽくも書ける
      • JavaVM 上で動作する
      object HelloWorld { def main(args: Array[String]) { println(&quot;Hello, world!&quot;) } }
    • Scala による Quick sort def qsort[T <% Ordered[T]](list: List[T]): List[T] = list match { case Nil => Nil case pivot::tail => qsort(tail.filter(_ < pivot)) ::: pivot :: qsort(tail.filter(_ >= pivot)) } scala> qsort(List(2,1,3)) res1: List[Int] = List(1, 2, 3)
    • WordCount by Java public class WordCount { public static class Map extends MapReduceBase implements Mapper<LongWritable, IntWritable> { private final static IntWritable one = new IntWritable(1); private Text word = new Text(); public void map(LongWritable key, Text value, OutputCollector<Text, IntWritable> output, Reporter reporter) throws IOException { String line = value.toString(); StringTokenizer tokenizer = new StringTokenizer(line); while (tokenizer.hasMoreTokens()) { word.set(tokenizer.nextToken()); output.collect(word, one); } } } public static class Reduce extends MapReduceBase implements Reducer<Text, IntWritable> { …
    • WordCount by Scala object WordCount { class MyMap extends Mapper[LongWritable, Text, Text, IntWritable] { val one = 1 override def map(ky: LongWritable, value: Text, output: Mapper[LongWritable, Text, Text, IntWritable]#Context) = { (value split &quot; &quot;) foreach (output write (_, one)) } } class MyReduce extends Reducer[Text, IntWritable, Text, IntWritable] { override def reduce(key: Text, values: java.lang.Iterable[IntWritable], output: Reducer[Text, IntWritable, Text, IntWritable]#Context) = { val iter: Iterator[IntWritable] = values.iterator() val sum = iter reduceLeft ((a: Int, b: Int) => a + b) output write (key, sum) } } def main(args: Array[String]) = { …
    • Java vs Scala
      • Java
      • Scala
      public void map(LongWritable key, Text value, OutputCollector<Text, IntWritable> output, Reporter reporter) throws IOException { String line = value.toString(); StringTokenizer tokenizer = new StringTokenizer(line); while (tokenizer.hasMoreTokens()) { word.set(tokenizer.nextToken()); output.collect(word, one); } } override def map(ky: LongWritable, value: Text, output: Mapper[LongWritable, Text, Text, IntWritable]#Context) = { (value split &quot; &quot;) foreach (output write (_, one)) }
    • Scala on Hadoop
      • Java と Scala を接続するライブラリが必要
      • SHadoop
        • http://code.google.com/p/jweslley/source/browse/#svn/trunk/scala/shadoop
        • 型変換を行うシンプルなライブラリ
    • mapper class MyMap extends Mapper[LongWritable, Text, Text, IntWritable] { val one = 1 override def map(ky: LongWritable, value: Text, output: Mapper[LongWritable, Text, Text, IntWritable]#Context) = { (value split &quot; &quot;) foreach (output write (_, one)) } }
    • reducer class MyReduce extends Reducer[Text, IntWritable, Text, IntWritable] { override def reduce(key: Text, values: java.lang.Iterable[IntWritable], output: Reducer[Text, IntWritable, Text, IntWritable]#Context) = { val iter: Iterator[IntWritable] = values.iterator() val sum = iter reduceLeft ((a: Int, b: Int) => a + b) output write (key, sum) } }
    • main def main(args: Array[String]) = { val conf = new Configuration() val otherArgs = new GenericOptionsParser(conf, args).getRemainingArgs() val job = new Job(conf, &quot;word count&quot;) job setJarByClass(WordCount getClass()) job setMapperClass(classOf[WordCount.MyMap]) job setCombinerClass(classOf[WordCount.MyReduce]) job setReducerClass(classOf[WordCount.MyReduce]) job setMapOutputKeyClass(classOf[Text]) job setMapOutputValueClass(classOf[IntWritable]) job setOutputKeyClass(classOf[Text]) job setOutputValueClass(classOf[IntWritable]) FileInputFormat addInputPath(job, new Path(otherArgs(0))) FileOutputFormat setOutputPath(job, new Path(otherArgs(1))) System exit(job waitForCompletion(true) match { case true => 0 case false => 1}) }
    • HDFS 操作 import java.net.URI import org.apache.hadoop.fs._ import org.apache.hadoop.hdfs._ import org.apache.hadoop.conf.Configuration object Hdfs { def main(args: Array[String]) = { val conf = new Configuration() val uri = new URI(&quot;hdfs://hadoop01:9000/&quot;) val fs = new DistributedFileSystem fs.initialize(uri, conf) var status = fs.getFileStatus(new Path(args(0))) println(status.getModificationTime) } }
    • ビルド手法
      • Maven
        • http://maven.apache.org/
        • Java 系のプロジェクト管理ツール
      • プロジェクト作成
      mvn org.apache.maven.plugins:maven-archetype-plugin:2.0-alpha-4:create -DarchetypeGroupId=org.scala-tools.archetypes -DarchetypeArtifactId=scala-archetype-simple -DarchetypeVersion=1.2 -DremoteRepositories=http://scala-tools.org/repo-releases -DgroupId=com.hatena.hadoop -DartifactId=hadoop
    • 依存関係の記述
      • Hadoop 関連 jar の登録
      • 依存関係の記述
      <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.0.4</version> <scope>provided</scope> </dependency> <dependency> <groupId>commons-cli</groupId> <artifactId>commons-cli</artifactId> <version>1.0</version> <scope>provided</scope> </dependency> mvn install:install-file -DgroupId=org.apache.hadoop -DartifactId=hadoop-core -Dversion=0.20.1 -Dpackaging=jar -Dfile=/opt/hadoop/hadoop-0.20.1-core.jar
    • ビルド・パッケージ作成と実行
      • ビルド・パッケージ作成
      • 実行
      $HADOOP_HOME/bin/hadoop jar ../maven/hadoop/target/hadoop-1.0-SNAPSHOT.jar com.hatena.hadoop.Hadoop -D mapred.job.tracker=local -D fs.default.name=file:/// input output mvn scala:compile mvn package mvn clean
    • レスポンス時間の計測 #1
      • 計測方法
        • 特定の URL を叩いて、その時間を計測
        • 生アクセスログから収集
      • 生アクセスログを分析
        • Hadoop クラスタ
          • Core2Quad サーバ 10 台
          • はてなダイアリーのログ 7GB -> 10 分程度で処理
        • 分布をグラフ化
    • レスポンス時間の計測 #2 Mapper URL などの条件でフィルタ レスポンス時間を記録 Reducer レスポンス時間の分布を計算 後処理 グラフ化 (gnuplot) Fotolife にアップロード (AtomAPI)
    • レスポンス時間の分布グラフ
    • 良好なレスポンスの例
    • キャッシュによる影響
    • まとめ
      • はてなでの Hadoop
      • Scala on Hadoop
      • 色々、触って楽しみましょう !
      • Q & A
      • [email_address]