Real World Android Akka
Who am I?
麻植泰輔 / Taisuke Oe
Twitter: @OE_uia
GitHub: taisukeoe
会社
- BONX INC. でAndroidアプリ書いたりスノー
ボードするお仕事
- ScalaMatsuri座長 / Japan Scala
Association, Inc.常務理事
個人
- Scalaを教える仕事しています
スポンサー募集
CFP
スタッフ募集
OPEN!!
What’s the topic?
本日のお話
本日のお話
Android
+
Scala
+
Akka
⇓
VoIPクライアント
本日のお話
◉ Akka
○ メッセージ駆動
○ Actorの実行モデル
○ Actorのヒエラルキー
◉ BONX
○ BONXとは?
○ BONX VoIPクライアントの要求仕様
◉ Android Akkaの注意点
○ Dispatcher, Mailboxの実装など
◉ Scala Androidってどうなの?
Akka?
Akka
◉ メッセージ駆動で並行/分散処理するtoolkit
◉ Lightbend CTO Jonas Bonér氏が作者
◉ 名前の由来はスイスの先住民の神様
◉ スイスのLaponiaという山がAkka神のシンボル
Message Driven?
メッセージ駆動?
メッセージ駆動
Actorがメッセージを送り合い協調動作することで、システムを構成
あとはたのむ
メッセージ駆動
あとはたのむ
次に手が空いてから
やるわ
Actorが受け取ったメッセージは、そのActorに紐付いたMailboxに入る
メッセージ駆動
あとはたのむ
次に手が空いてから
やるわ
Actorはメッセージ一つ一つを逐次処理する
=> (特にスレッドセーフではない)状態管理を伴う並行プログラミングに有用
メッセージ駆動
あとはたのむ 今からやるお
Actorは他のActorについては、メッセージの送信先と受け取れるメッセージ
の種類についてのみ知っておけばよいため、Actor同士を疎結合にしやす
い
Akka Dispatcher
Actorの実行モデル
Actorの実行モデル
Thread
Thread
Dispatcher
DispatcherがActorの実行基盤。内部にThreadPoolを保持。
Actorの実行モデル
Thread
Thread
Dispatcher
1つのActorは、同時に一つのスレッドにだけ割り振られる
Actorの実行モデル
Thread
Thread
Dispatcher
Threadが空いたら、次のActorが割り振られる
Actorの実行モデル
Dispatcher
Actorは、Mailboxにメッセージが有り、なおかつThreadが割り
当てられてるときにメッセージを処理する
Actorプログラミングのアンチパターン
Thread
Thread
Dispatcher
Actorが長時間Threadをブロックすると、同じdispatcherを使用
しているActorシステム全体の処理が進みにくくなる
進捗ダメです
Akka Actor Hierarchy
Actorのヒエラルキー
Actorの階層構造
Dispatcher
Actorには親子関係が作れる
ワシが育てた
Actorの階層構造
Dispatcher
子ActorでThrowableが投げられると、親Actorの
supervisorStrategy関数が呼ばれる
_人人人人人人人人人_
> 突然のThrowable <
 ̄Y^Y^Y^Y^Y^Y^Y^Y ̄
Actorの階層構造
Dispatcher
supervisorStrategyの実装により、その後の子Actorの処遇が
決定される
Restart
Akkaについて - まとめ
◉ Actorがメッセージを送り合うことでシステムを構成
◉ 1つのActorは同時に1メッセージを1スレッドで逐次処
理するため、状態管理が楽
◉ 実行モデル
○ Dispatcher … Thread(pool)の保持と、ActorへのThread貸
出
○ Mailbox … Actorに送られたメッセージ置き場
◉ ActorのヒエラルキーとSupervisorStrategyの実装を
適切に設定することで、障害からの回復力をもつ
The Way We Talk
BONX
BONXとは?
野外の激しい運動中でも
複数の仲間とスムーズに
コミュニケーションとれるVoIPサービス
VoIP = Voice over Internet Protocol
Requirement specification in BONX VoIP client
BONX VoIPクライアントの要求仕様
BONX VoIPクライアントの要求仕様
◉ 状態管理を伴う並行プログラミング
◉ (それなりに)低遅延
◉ 障害からの回復力
VoIPは音声ストリーム処理
ソケット通信録音 音量調整 発話検知 エンコード
デコード再生
音声ストリーム処理: 並行プログラミング
◉ 1フレームの処理が終わる前に、次のフレームの音声デー
タが送られてくる
◉ 必然的に並行プログラミングすることになる
◉ しかしエンコーダー・デコーダーなどのモジュールは、多く
の場合Threadセーフではない
Actorモデル向き
低遅延
◉ 合計の遅延:大きくなりすぎると、(特に顔が見えていると
き)通話中に違和感
◉ 個々の遅延:フレーム間の遅延が大きくなりすぎると、「ブ
ツッ」という音の途切れの原因
Dispatcher, Mailboxのカスタマイズ性は必要十分
障害からの回復力
◉ クライアントアプリとしては長時間(~8時間)の連続使用を想
定
◉ 使用中、録音/再生のハードウェア I/Oなど一部のモ
ジュールに問題が発生するケースがある
◉ 何かの状態がおかしい場合は、関連するモジュール含め
て、自動で再初期化が必要
AkkaのActorヒエラルキーを適切に設定しておくと、モジュール
群を自動で再初期化することで障害から回復できる
Pitfalls in Android Akka
Android Akkaの注意点
Android Akkaの注意点
◉ Akka version
◉ Proguard設定
◉ Dispatcherの罠
◉ Mailboxのサイズ
Akka version
◉ AndroidはJava6/7相当の環境
◉ Akka 2.14系はJava8要求
=> Akka 2.13系を使う
Proguard
● Akkaはapplication.confやPropsを基に、リフレクションで
Actorなどをインスタンス化
● Proguardは使用されていないクラス、メソッドをバイトコード
から抜くpost-processingツール
● Proguardはリフレクションを理解しない
● Android ScalaにおけるNoSuchMethodErrorの発生原因
の殆どはProguard起因
=> proguard.cfgに随時指定
参考: Macroid | Akka Integration
Dispatcherの罠
application.confのparallerism-factorは、(min~maxの範囲
で)availableProcessorsに乗じた数のThreadPoolを作る
akka.dispatch.ThreadPoolConfig
object ThreadPoolConfig {
/* … */
def scaledPoolSize(floor: Int, multiplier: Double, ceiling: Int): Int =
math.min(math.max((Runtime.getRuntime.availableProcessors * multiplier).ceil.toInt, floor), ceiling)
/* … */
}
AndroidのavailableProcessors
Androidの場合、電力消費を抑えるため、高クロックと低クロックのコア
から構成されているヘテロCPUが主流。そのため、一度に全てのCPUコ
アがonlineにならない端末が多い。
しかしRuntime#availableProcessorsは常に全合計コア数を返す。この
数字をそのまま使うと、Thread数がコア数に対して多くなりすぎてパ
フォーマンスが低下することがある
/sys/devices/system/cpu/online では 1-5,6 のようにオンライン状態の
CPUのindexをチェックできる (参考:Linux kernel related to hotplug a
CPU)
カスタムDispatcher
akka.dispatcher.ExecutorServiceConfiguratorを継承
したクラスのFQCN(フル修飾名)をapplication.confに指定
可能
my-dispatcher {
type = Dispatcher
executor = "com.taisukeoe.MyExecutorConfigurator"
fork-join-executor {
parallerism-min = 8
parallerism-factor = 2
parallerism-max = 16
}
}
カスタム
ExecutorServiceConfigurator
class MyExecutorConfigurator(config: Config, prerequisites: DispatcherPrerequisites) extends
ExecutorServiceConfigurator(config, prerequisites) {
final def createExecutorServiceFactory(id: String, threadFactory: ThreadFactory): ExecutorServiceFactory = {
val c = config.getConfig("fork-join-executor")
new ForkJoinExecutorServiceFactory(
threadFactory.asInstanceOf[ForkJoinPool.ForkJoinWorkerThreadFactory],
CPUConfig.scaledPoolSize(
c.getInt("parallelism-min"),
c.getDouble("parallelism-factor"),
c.getInt("parallelism-max")),
true)
}
}
OnlineのCPUコア数を取得
object CPUConfig {
private lazy val rangeRegex = "([0-9]+)-([0-9]+)".r
def onlineProcessors: Option[Int] = Try {
val reader = new BufferedReader(new FileReader("/sys/devices/system/cpu/online"))
val num = Iterator.continually(reader.readLine()).takeWhile(_ != null).toSeq.headOption map { cpu:String =>
cpu.split(",").map {
case rangeRegex(from, to) => to.toInt - from.toInt + 1
case num => 1
}.sum
reader.close()
num
}}.toOption.flatten
def scaledPoolSize(floor: Int, multiplier: Double, ceiling: Int): Int =
math.min(math.max(onlineProcessors.getOrElse(Runtime.getRuntime.availableProcessors) * multiplier).ceil.toInt,
floor), ceiling)
}
Mailboxのサイズ
◉ Androidは(増えてきたとはいえ)基本的には低メモリ環境
◉ 1 VM ~ 数百MB RAM
◉ サイズ制限のないMessageBoxだとOutOfMemoryErrorのおそれ
◉ できるだけ有限サイズのMailbox (BoundedMailbox) を使う方が
良い
◉ それで必要要件をみたさないときは、カスタムMailboxを作るべき
参考: Mailboxes -- Akka
my-mailbox {
mailbox-type = "com.taisukeoe.MyMailBox"
}
Android Scala Pros & Cons
ScalaでAndroidってどうなの?
ScalaでAndroidってどうなの?
◉ ScalaとAndroid両方に詳しい人がチームに1人いたら選択肢として
アリ。チーム2人目以降は、どちらかについて詳しければ、教育可能
◉ sbt-androidが(クセはあるけど)とても優秀。組み合わせると便利な
sbt pluginも色々
◉ 今回のケースではScala + Akka + Androidのメリットが存分に活き
た
○ 常時1~2人分の工数の少人数チームで新規機能開発&メンテ
○ 必要な低遅延/スループットなどのパフォーマンスを達成しつ
つ、モジュールの疎結合化、コードの抽象化に(それなりに)成
ScalaでAndroidってどうなの?
◉ 万人にオススメはしない
◉ ScalaとAndroid両方の知識がそれなりに必要
◉ ビルドが長い (Proguardのせい)
◉ Googleのサポート外
○ Scala2.12 & Java8対応?
■ Jack & JillがJava8対象
○ Jack & Jill対応?
■ sbt-androidにPullReqは一応....
まとめ
◉ Akkaはメッセージ駆動で並行/分散処理を便利に行える
toolkit
◉ Androidでも幾つかのポイントに注意すれば、Akkaは十分
実用的である。
◉ VoIPアプリの音声ストリーム処理など、AndroidでもActor
モデルが非常に有用となるケースがある
We’re hiring!
◉ VoIPクライアントアプリに興味がある人
◉ Android Scalaを触ってみたい人
◉ Akkaのチューニングをゴリゴリしたい人
◉ スノボ、サイクリング 等々が好きな人
お気軽に @OE_uia までメッセください

Real world android akka