Scala on Hadoop

34
Hadoop Conference Scala on Hadoop ははは はは はは stanaka @ hatena.ne.jp http://d.hatena.ne.jp/stanaka/ http://twitter.com/stanaka/

description

 

Transcript of Scala on Hadoop

Page 1: Scala on Hadoop

Hadoop Conference

Scala on Hadoop

はてな 田中 慎司stanaka @ hatena.ne.jp

http://d.hatena.ne.jp/stanaka/http://twitter.com/stanaka/

Page 2: Scala on Hadoop

アジェンダ 自己紹介 はてなでの Hadoop

Scala までの道 Scala on Hadoop Scala on Hadoop の応用

Page 3: Scala on Hadoop

自己紹介 ( 株 ) はてな 執行役員

担当領域 システムアーキテクチャ

スケーラビリティ サーバ・ネットワーク サポート

Page 4: Scala on Hadoop

はてなでの Hadoop #1

自作サーバ 10 台 CPU: Core2 Quad x 1 Mem: 8GB HDD: 3TB

DC ではなくオフィスに置いて、電源代節約

Page 5: Scala on Hadoop

はてなでの Hadoop #2

蓄積されるデータ ( 主にログ ) ダイアリー 7G/day ブックマーク 5G/day うごメモ 3G/day

ジョブ 300 jobs/day

Page 6: Scala on Hadoop

はてなでの Hadoop システム ( 現状 )

Hadoop MapReduce

HDFS

ReverseProxy

ジョブの投入

HatenaFotolife

HatenaGraph

ログを時間毎に蓄積

/logs/$service/$year/$month/$date/$host_access-$hour.log

Page 7: Scala on Hadoop

Hadoop

2008/5 頃 調査 Hadoop Streaming

2008/8 頃 稼働 Perl による Mapper, Reducer YAML でジョブを定義

2009/4 WebUI を作成 2009/11 Scala 化 ← イマココ

Page 8: Scala on Hadoop

Hadoop Streaming

Java 以外の言語で MapReduce を可能に ! Map, Reduce の入出力を標準入力 /標準出力

として扱う→ map.pl, reduce.pl を用意するだけ

通常は入力出力共に HDFS 上に置かれる

Page 9: Scala on Hadoop

map.pl

#!/usr/bin/env perluse strict;use warnings;

while (<>) { chomp; my @segments = split /\s+/; printf "%s\t%s\n", $segments[8], 1;}

Page 10: Scala on Hadoop

reduce.pl

#!/usr/bin/env perluse strict;use warnings;

my %count;while (<>) { chomp; my ($key, $value) = split /\t/; $count{$key}++;}

while (my ($key, $value) = each %count) { printf "%s\t%s\n", $key, $value;}

Page 11: Scala on Hadoop

実行

% 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

Page 12: Scala on Hadoop

ジョブの定義 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: "Ugomemo Latency $date" xlabel: "Response time (msec)" ylabel: "Rates of requests (%)" fotolife_folder: ugomemo

Page 13: Scala on Hadoop

WebUI

Page 14: Scala on Hadoop

Hadoop Streaming の限界 遅い ← Perl の問題も ..

ジョブを KILL しても、プロセスが残ることがある

HDFS 操作が遅い Combiner が定義できない

Page 15: Scala on Hadoop

Scala

2003 年登場 関数型の特徴を備えた言語 普通のオブジェクト指向っぽくも書ける JavaVM 上で動作する

object HelloWorld { def main(args: Array[String]) { println("Hello, world!") }}

Page 16: Scala on Hadoop

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)

Page 17: Scala on Hadoop

WordCount by Javapublic 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> {…

Page 18: Scala on Hadoop

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 " ") 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]) = {…

Page 19: Scala on Hadoop

Java vs 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 " ") foreach (output write (_, one))}

Java

Scala

Page 20: Scala on Hadoop

Scala on Hadoop

Java と Scala を接続するライブラリが必要

SHadoop http://code.google.com/p/jweslley/

source/browse/#svn/trunk/scala/shadoop 型変換を行うシンプルなライブラリ

Page 21: Scala on Hadoop

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 " ") foreach (output write (_, one)) }}

Page 22: Scala on Hadoop

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) }}

Page 23: Scala on Hadoop

main

def main(args: Array[String]) = { val conf = new Configuration() val otherArgs = new GenericOptionsParser(conf, args).getRemainingArgs()

val job = new Job(conf, "word count") 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})}

Page 24: Scala on Hadoop

HDFS 操作

import java.net.URIimport 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("hdfs://hadoop01:9000/") val fs = new DistributedFileSystem fs.initialize(uri, conf)

var status = fs.getFileStatus(new Path(args(0))) println(status.getModificationTime) }}

Page 25: Scala on Hadoop

ビルド手法 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

Page 26: Scala on 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

Page 27: Scala on Hadoop

ビルド・パッケージ作成と実行 ビルド・パッケージ作成

実行 $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:compilemvn packagemvn clean

Page 28: Scala on Hadoop

レスポンス時間の計測 #1

計測方法 特定の URL を叩いて、その時間を計測 生アクセスログから収集

生アクセスログを分析 Hadoop クラスタ

Core2Quad サーバ 10 台 はてなダイアリーのログ 7GB → 10 分程度で処理

分布をグラフ化

Page 29: Scala on Hadoop

レスポンス時間の計測 #2

Mapper URL などの条件でフィルタ レスポンス時間を記録

Reducer レスポンス時間の分布を計算

後処理 グラフ化 (gnuplot) Fotolife にアップロード(AtomAPI)

Page 30: Scala on Hadoop

レスポンス時間の分布グラフ

Page 31: Scala on Hadoop

良好なレスポンスの例

Page 32: Scala on Hadoop

キャッシュによる影響

Page 33: Scala on Hadoop

まとめ はてなでの Hadoop Scala on Hadoop

色々、触って楽しみましょう !