JavaからScalaへの
継続的なマイグレーション
株式会社サイバーエージェント
福原 真
ITモダナイゼーションSummit 2015/4/23
株式会社サイバーエージェント
アドテクスタジオ
AMoAd所属
福原 真
@fukuo33
-2011/08 (主にJava)
SIer として 金融、物流、外食、通信 etc様々なプロジェクトに参加
2011/09- (C言語 + Scala)
某アドネットワークシステム サーバサイドエンジニア
2013/04- (Scala + Java)
株式会社AMoAd サーバサイドエンジニア
自己紹介
[AMoAdでの役割]
基本はプログラマー
(Java成分多め)ですが、
設計/開発/テスト/サーバ運用/保守
なんでもやってます!
Agenda
Introduction
1. アドテクスタジオの紹介
2. アドネットワークとは?
Chapter
1. システム内製化
2. JavaからScalaへ
3. 継続的なマイグレーション
アドテクスタジオの紹介
Introduction
1
NEW! 2015
NEW! 2015NEW! 2015
NEW! 2015
出典: サイバーエージェント アドテクノロジー説明会動画
https://www.cyberagent.co.jp/reportlist/adtech/
アドネットワークとは?
Introduction
2
出典: サイバーエージェント アドテクノロジー説明会動画
https://www.cyberagent.co.jp/reportlist/adtech/
アドネットワークのサーバに
求められる機能
1. 高トラフィック/低レンテンシ
2. リアルタイムユーザ判定
3. 最適化ロジック
4. レポート集計
Key Point
膨大なトラフィック捌きつつ
リアルタイムに最適化し
膨大なログデータを解析/集計
すること!
システム内製化
Chapter
1
In-House
2013/4- 内製化開始
サーバサイドエンジニア 2人
インフラエンジニア 1人
[移管されたソフトウェア]
• ソースコード(主にJava)
[移管されたハードウェア]
• 配信サーバ
• 各種バッチサーバ
• Hadoop
• RDBサーバ
• KVSサーバ etc…
仕様書類なし
単体テストコードなし(汗)
仕様書が無いので、引き継ぎ
することも特になし( _ )
Key Point
正しい仕様は自分たちで把握し、
判断できた。
JavaからScalaへ
Chapter
2
なぜScalaか?
オブジェクトが不変であること、
参照透明性を維持すること、
が直感的に正しいと思えたから。
scala> val x = 123
x: Int = 123
scala> x = 321
<console>:8: error: reassignment to val
x = 321
^
不変(immutable)の例
なぜScalaか?
scala> def twice(x: Int) = x * 2
twice: (x: Int)Int
scala> twice(123)
res1: Int = 246
参照透明性の例
チームビルド
Functional Programming in
Scala 読書会
• メンテナンス性の高いコードが
書けるようになった
• チーム内の共通理解が出来た
• Javaを書く際にもメンテナンス性
を意識するようになった
Scala導入事例
オフラインバッチ
並列処理が書きやすい!
scala> def heavyProcess(i: Int): Future[Int] = Future {
| Thread.sleep(10000)
| println(s"process: $i")
| i * 2
| }
heavyProcess: (i: Int)scala.concurrent.Future[Int]
scala> (1 to 3).map(heavyProcess).toList
res0: List[scala.concurrent.Future[Int]] =
List(scala.concurrent.impl.Promise$DefaultPromise@69824fe7, …
scala> Await.result(Future.sequence(res0), Duration.Inf)
process: 3
process: 2
process: 1
res1: List[Int] = List(2, 4, 6)
集計処理
• 実はこれまでHadoopジョブを書いたメンバー
が居ない。。。
• パフォーマンス改善が急務!
集計処理(Scalding)
• Scalaのコレクション操作のように
Hadoopジョブが書ける!
• 単体テストが書ける!
• パフォーマンスも良好!
class WordCountJob(args: Args) extends Job(args) {
TypedPipe.from(TextLine(args("input")))
.flatMap { line => tokenize(line) }
.groupBy { word => word } // use each word for a key
.size // in each group, get the size
.write(TypedTsv[(String, Long)](args("output")))
}
Key Point
• Functionalを学ぶことで、メンテナンス
性の高いコードが書けるようになった
• 大量のinputデータに対してハイパフォー
マンスなコードが書けるようになった
→ アドテクシステムには非常に有効!
継続的なマイグレーション
Chapter
3
前提
自分たちのビジネスに貢献することが目的!
システムをリプレースするのが
目的ではない!
実例紹介
新規機能追加
• 機能を盛り込み過ぎない
• Scalaで実装する
• テスタビリティを意識
Point: リリースを意識して
スモールスタート
既存機能への機能追加
• 全体設計
Point: 必ずリリースロールバック出来るようにする
• 実装
1. 既存機能のテストコードを実装
2. リファクタリング-> リリース
Point: リファクタリングで依存関係を整理
3. 追加機能のテストコードを実装 (コーナーケースはここで潰す)
4. 追加機能の実装 -> リリース
• テスト
1. CIツールでリグレッションテスト
2. インテグレーションテスト
負荷対策(チューニング)
• 現状分析
ボトルネックとなる負荷の種類(メモリ/CPU/IO)を理解する
• どこまでチューニングするかの指標を決める
Point: チューニングをやり過ぎないこと
• 対策
Point: スケールアップで対処出来るか切り分ける
• リリース
大事なことは
Summary
自分たちのビジネスの価値を
把握し、それにあったマイグ
レーション手法を考えること

JavaからScalaへの継続的なマイグレーション