Upload
taisuke-oe
View
1.639
Download
1
Embed Size (px)
Citation preview
Who am I?
麻植泰輔 / Taisuke OeTwitter: @OE_uiaGitHub: taisukeoe
会社
- BONX INC. でAndroidアプリ書いたりスノー
ボードするお仕事
- ScalaMatsuri座長 / Japan Scala Association, Inc.常務理事
個人
- Scalaを教える仕事しています
本日のお話
◉ Akka○ メッセージ駆動○ Actorの実行モデル○ Actorのヒエラルキー
◉ BONX○ BONXとは?○ BONX VoIPクライアントの要求仕様
◉ Android Akkaの注意点○ Dispatcher, Mailboxの実装など
◉ Scala Androidってどうなの?
Akka
◉ メッセージ駆動で並行/分散処理するtoolkit◉ Lightbend CTO Jonas Bonér氏が作者◉ 名前の由来はスイスの先住民の神様◉ スイスのLaponiaという山がAkka神のシンボル
Actorプログラミングのアンチパターン
Thread
ThreadDispatcher
Actorが長時間Threadをブロックすると、同じdispatcherを使用しているActorシステム全体の処理が進みにくくなる
進捗ダメです
Actorの階層構造Dispatcher
子ActorでThrowableが投げられると、親ActorのsupervisorStrategy関数が呼ばれる
_人人人人人人人人人_
> 突然のThrowable < ̄Y^Y^Y^Y^Y^Y^Y^Y ̄
Akkaについて - まとめ
◉ Actorがメッセージを送り合うことでシステムを構成◉ 1つのActorは同時に1メッセージを1スレッドで逐次処
理するため、状態管理が楽◉ 実行モデル
○ Dispatcher … Thread(pool)の保持と、ActorへのThread貸出
○ Mailbox … Actorに送られたメッセージ置き場
◉ ActorのヒエラルキーとSupervisorStrategyの実装を適切に設定することで、障害からの回復力をもつ
音声ストリーム処理: 並行プログラミング
◉ 1フレームの処理が終わる前に、次のフレームの音声デー
タが送られてくる
◉ 必然的に並行プログラミングすることになる
◉ しかしエンコーダー・デコーダーなどのモジュールは、多く
の場合Threadセーフではない
Actorモデル向き
低遅延
◉ 合計の遅延:大きくなりすぎると、(特に顔が見えていると
き)通話中に違和感
◉ 個々の遅延:フレーム間の遅延が大きくなりすぎると、「ブ
ツッ」という音の途切れの原因
Dispatcher, Mailboxのカスタマイズ性は必要十分
障害からの回復力
◉ クライアントアプリとしては長時間(~8時間)の連続使用を想定
◉ 使用中、録音/再生のハードウェア I/Oなど一部のモジュールに問題が発生するケースがある
◉ 何かの状態がおかしい場合は、関連するモジュール含めて、自動で再初期化が必要
AkkaのActorヒエラルキーを適切に設定しておくと、モジュール群を自動で再初期化することで障害から回復できる
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のavailableProcessorsAndroidの場合、電力消費を抑えるため、高クロックと低クロックのコアから構成されているヘテロ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"}
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 までメッセください