Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
Akka Typed - 型安全にメッセージパッシングする! / Akka Typed - t...
Search
hayasshi
November 10, 2018
Technology
3k
6
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Akka Typed - 型安全にメッセージパッシングする! / Akka Typed - typesafe messaging
hayasshi
November 10, 2018
More Decks by hayasshi
See All by hayasshi
Chatwork で Akka をどうつかっているのか なぜつかっているのか / Why Akka, How Akka in Chatwork
hayasshi
1
620
とある会社のビルドデプロイ / A certain company's application building
hayasshi
0
390
Scala / refined で`型く`表明プログラミング / Programing with type level assertion
hayasshi
2
990
AWS Dev Day Challenge (2018-11-02) - ChatWork Suita
hayasshi
2
760
Scala and Akka apps on Kubernetes in ChatWork
hayasshi
0
2.7k
Other Decks in Technology
See All in Technology
音声コミュニティを守るAI監視基盤_ 90%以上の入力削減を支えたServerless設計と運用判断
shuheioka123
0
110
Coil3を内部実装から読み解く~キャッシュ戦略とAVIF画像の描画〜/nikkei-tech-talk50
nikkei_engineer_recruiting
0
110
SREへの勘違いに気づいた後の話
tomodakengo
0
180
Vibe Coding で作ったプロダクトをどう安全に動かすか / How to Safely Run Products Built with Vibe Coding
glidenote
0
780
EventBridge に「合流」はない ― サーバーレスのワークフローを育てるということ / No Join in EventBridge
yusukeshimizu
2
580
AI coding 整合正規方法
philipz
0
550
AI感のないAWS構成図をAIエージェントに描かせたい!
sagochiko
2
450
CI/CDではもう遅い - 人とAIが迂回しないDevSecOps Verify基盤の再設計 -
kintotechdev
1
340
人にやさしく、AIにやさしく、書き手を選ばないIaCのガードレール再考 / Rethinking IaC Guardrails for Humans and AI Alike
kohbis
5
1.4k
Hermes Agentで、AIが調べて記事を書くブログを作った話
blueb
0
110
AI Native Platform Engineering 〜PlatformとAgileで“作る速さ”を“価値”へ〜
uya116
0
230
AIは推し活である。
kurazuuuuuu
2
990
Featured
See All Featured
Music & Morning Musume
bryan
48
7.4k
Self-Hosted WebAssembly Runtime for Runtime-Neutral Checkpoint/Restore in Edge–Cloud Continuum
chikuwait
0
840
Visualizing Your Data: Incorporating Mongo into Loggly Infrastructure
mongodb
50
10k
The Web Performance Landscape in 2024 [PerfNow 2024]
tammyeverts
12
1.3k
16th Malabo Montpellier Forum Presentation
akademiya2063
PRO
0
390
Taking LLMs out of the black box: A practical guide to human-in-the-loop distillation
inesmontani
PRO
3
2.4k
Facilitating Awesome Meetings
lara
57
7.2k
A Tale of Four Properties
chriscoyier
163
24k
We Analyzed 250 Million AI Search Results: Here's What I Found
joshbly
1
2k
RailsConf & Balkan Ruby 2019: The Past, Present, and Future of Rails at GitHub
eileencodes
141
35k
Principles of Awesome APIs and How to Build Them.
keavy
128
18k
How GitHub (no longer) Works
holman
316
150k
Transcript
Akka Typed 型安全にメッセージパッシングする! 2018-11-10 Scala 関西Summit 2018 1
自己紹介 林 大介 Twitter: @hayasshi_ GitHub: hayasshi ChatWork 株式会社 Scala
2.9 系から使い始め(2013 年頃) 型好き、Akka 好き 2018-11-10 Scala 関西Summit 2018 2
お話すること Akka や アクターモデルについて簡単におさらい Akka Typed について 各パターンでの比較 アクター生成とAsk スーパービジョン
ライフサイクル 他のモジュールとの統合 2018-11-10 Scala 関西Summit 2018 3
お話しない( できない) こと Akka Actors とのパフォーマンス比較 簡易なものでもやりたかった!スミマセン Akka Typed の導入事例
Akka Typed への移行戦略について 2018-11-10 Scala 関西Summit 2018 4
Akka と アクターモデル 2018-11-10 Scala 関西Summit 2018 5
メニーコア時代における、並行・分散処理をおこなう アプリケーションを構築するためのツールキット 一台のマシン上でのアプリケーションから 複数台のマシンでの分散処理やクラスタリングなどを構築するため のモジュールが用意されている これらの根底にあるものは アクターモデル 2018-11-10 Scala 関西Summit
2018 6
アクターモデル 1973 年 カール・ヒューイット氏が発表した 並行処理を行うための計算モデル 全てのものはアクターである 全てのものはオブジェクトであると同様な考え方 違いは本質的に並行性を備えているということ アクターはメッセージに対する振る舞いを持つ アクター間のメッセージのやり取りで計算を行う
2018-11-10 Scala 関西Summit 2018 7
アクターモデル 2018-11-10 Scala 関西Summit 2018 8
詳しくは 2018-11-10 Scala 関西Summit 2018 9
お話する前提のバージョン 下記のバージョンで動作確認等を行っています。 val scalaVersion = "2.12.7" val akkaVersion = "2.5.17"
2018-11-10 Scala 関西Summit 2018 10
Akka Actors Akka の全ての基礎となる、根底のモジュール JVM 上でアクタープログラミングを行うことができる JVM で並行処理をおこなうにあたっての大変な部分を隠蔽し、 ロジックに集中できる 2018-11-10
Scala 関西Summit 2018 11
Akka Actors akka-scala-seed.g8 class Greeter(message: String, printerActor: ActorRef) extends Actor
{ import Greeter._ import Printer._ var greeting = "" def receive: Receive = { case WhoToGreet(who) => greeting = message + ", " + who case Greet => printerActor ! Greeting(greeting) } } 2018-11-10 Scala 関西Summit 2018 12
Akka Actors val system: ActorSystem = ActorSystem("helloAkka") val printer: ActorRef
= system.actorOf(Printer.props, "printerActor") val howdyGreeter: ActorRef = system.actorOf(Greeter.props("Howdy", printer), "howdyGreeter") val goodDayGreeter: ActorRef = system.actorOf(Greeter.props("Good day", printer), "goodDayGreeter") howdyGreeter ! WhoToGreet("Akka") howdyGreeter ! Greet // Howdy, Akka howdyGreeter ! WhoToGreet("Scala") howdyGreeter ! Greet // Howdy, Scala goodDayGreeter ! WhoToGreet("Play") goodDayGreeter ! Greet // Good day, Play 2018-11-10 Scala 関西Summit 2018 13
LGTM! しかし気をつけなければいけないことも... 2018-11-10 Scala 関西Summit 2018 14
Akka Actors val system: ActorSystem = ActorSystem("helloAkka") val printer: ActorRef
= system.actorOf(Printer.props, "printerActor") val howdyGreeter: ActorRef = system.actorOf(Greeter.props("Howdy", printer), "howdyGreeter") val goodDayGreeter: ActorRef = system.actorOf(Greeter.props("Good day", printer), "goodDayGreeter") howdyGreeter ! Greeting("Akka") howdyGreeter ! Greeting("Scala") goodDayGreeter ! Greeting("Play") なんか動きそう。コンパイルも通る。でも動かない... 2018-11-10 Scala 関西Summit 2018 15
tell ( ! ) メソッド型安全じゃない問題 trait ScalaActorRef { ref: ActorRef
⇒ def !(message: Any)(implicit sender: ActorRef = Actor.noSender): Unit } type Receive = PartialFunction[Any, Unit] trait Actor { def receive: Receive } アクター定義時に指定していないメッセージを受け取れてしまう ( コンパイルできてしまう) コードベースが大規模になってくると間違ったメッセージを送って しまう可能性が高くなる 2018-11-10 Scala 関西Summit 2018 16
型安全じゃない 2018-11-10 Scala 関西Summit 2018 17
Akka Typed 2018-11-10 Scala 関西Summit 2018 18
Akka Typed Akka Actors のメッセージパッシングを 型安全に行うためのモジュール Akka Actors の置き換えになる 基本的な部分のAPI
はだいたい固まっている 他モジュールとの統合API の部分を中心に細かな変更が続いている 2018-11-10 Scala 関西Summit 2018 19
Akka Typed libraryDependencies += "com.typesafe.akka" %% "akka-actor-typed" % akkaVersion アクターの定義は、振る舞い
Behavior を定義する 振る舞いは、次の振る舞いを返す入れ子構造になっている import akka.actor.typed.Behavior import akka.actor.typed.scaladsl.{ActorContext, Behaviors} case class Greet(whom: String) val greeterBehavior: Behavior[Greet] = Behaviors.receive { (ctx: ActorContext[Greet], msg) => ctx.log.info("Hello {}!", msg.whom) Behaviors.same } 2018-11-10 Scala 関西Summit 2018 20
Akka Typed アクターは振る舞い Behavior から生成される import akka.actor.typed.ActorSystem val greeter =
ActorSystem(greeterBehavior, "greeter") greeter ! Greet("Akka") // Hello Akka! case class Greeting(whom: String) greeter ! Greeting("Akka") // compile error ( ActorSystem もActorRef[T] を継承している) 型安全にメッセージパッシングできる! 2018-11-10 Scala 関西Summit 2018 21
Akka Typed - 状態 def counterBehavior(current: Int): Behavior[Int] = Behaviors.receiveMessage
{ c => val count = current + c println(count) counterBehavior(count) } val counter = ActorSystem(counterBehavior(0), "counter") counter ! 1 // 1 counter ! 3 // 4 状態は再帰をつかって表現する よりイミュータブルな振る舞いとして扱うことができる 2018-11-10 Scala 関西Summit 2018 22
なるほど良さそうに見える 型安全にメッセージパッシングできることはわかった しかし、Akka Actors に比べ 大きくコーディングスタイルが変わっている Akka Actors でよく使われる アクタープログラミングのパターンをどう記述していくか比較する
2018-11-10 Scala 関西Summit 2018 23
注意 これからのサンプルコードは資料の都合上、好ましくない書き方 をしているコードがあります 特に Akka Actors で Props を利用側が直接使っている箇所は 注意してください
Props にインスタンスを利用側から渡すと、利用側でインスタン スの状態を書き換えることができてしまいます // ダメゼッタイ val actor = new Greeter(...) val props = Props(actor) val actorRef = system.actorOf(props, "child") actor.greeting = "hoge" 2018-11-10 Scala 関西Summit 2018 24
パターン比較 アクター生成とAsk 2018-11-10 Scala 関西Summit 2018 25
アクター生成とAsk - Akka Actors class Producer extends Actor { def
receive: Receive = { case p: Props => val child = context.actorOf(p) context.watch(child) sender() ! context.actorOf(p) } } class Printer extends Actor { def receive: Receive = { case s: String => println(s) } } 2018-11-10 Scala 関西Summit 2018 26
アクター生成とAsk - Akka Actors val system = ActorSystem() val producer
= system.actorOf(Props(classOf[Producer])) import akka.pattern.ask implicit val ec = system.dispatcher implicit val timeout: Timeout = Timeout(3.seconds) val printer: Future[ActorRef] = (producer ? Props(classOf[Printer])).mapTo[ActorRef] for (printerRef <- printer) { printerRef ! "Hello" } 2018-11-10 Scala 関西Summit 2018 27
アクター生成とAsk - Akka Actors アクター生成 ActorSystem.actorOf , ActorContext.actorOf アクターの内部どこでも生成することができる Ask
import akka.pattern.ask で ask メソッド( ? ) を使えるようになる ask メソッドの返り値は Future[Any] のため mapTo をつかい、型を変換する ( 返ってくる実際の型と異なれば実行時エラー) 28
アクター生成とAsk - Akka Typed val printerBehavior: Behavior[String] = Behaviors.receiveMessage {
msg => println(msg) Behaviors.same } val producerBehavior: Behavior[SpawnProtocol] = Behaviors.receive { (ctx, msg) => msg match { case Spawn(bhvr, name, props, replyTo) => val ref = ctx.spawn(bhvr, name, props) ctx.watch(ref) replyTo ! ref } Behaviors.same } 2018-11-10 Scala 関西Summit 2018 29
アクター生成とAsk - Akka Typed アクター生成 ActorContext[T].spawn 振る舞いのなか( コンテキストのあるスコープ) で 生成することができる
SpawnProtocol はアクター生成するための組み込みメッセージ 対応する振る舞いも標準で用意されている SpawnProtocol.behavior 2018-11-10 Scala 関西Summit 2018 30
アクター生成とAsk - Akka Typed val producerBehavior: Behavior[SpawnProtocol] = Behaviors.receive {
(ctx, msg) => msg match { case Spawn(bhvr, name, props, replyTo) => val ref = ctx.spawn(bhvr, name, props) ctx.watch(ref) replyTo ! ref } Behaviors.same } val spawnBehavior = SpawnProtocol.behavior val producer = ActorSystem(spawnBehavior, "producer") ただし ActorContext[T].watch を差し込めない 2018-11-10 Scala 関西Summit 2018 31
アクター生成とAsk - Akka Typed val producer = ActorSystem(producerBehavior, "producer") import
akka.actor.typed.scaladsl.AskPattern._ implicit val ec = producer.executionContext implicit val timeout: Timeout = Timeout(3.seconds) implicit val scheduler: Scheduler = producer.scheduler val printer: Future[ActorRef[String]] = producer ? SpawnProtocol.Spawn(printerBehavior, "printer") for (printerRef <- printer) { printerRef ! "Hello" } 2018-11-10 Scala 関西Summit 2018 32
アクター生成とAsk - Akka Typed Ask import akka.actor.typed.scaladsl.AskPattern._ で、 ask メソッド(
? ) を使えるようになる ActorRef[T] から実際の型が返る def ?[U](replyTo: ActorRef[U] ⇒T)(implicit...): Future[U] 戻し先となる ActorRef[U] をメッセージに含める case class Request(s: String, replyTo: ActorRef[Response]) server ?(ref => Request("data", ref) server ? (Request("data", _)) 2018-11-10 Scala 関西Summit 2018 33
アクター生成とAsk - 比較まとめ アクター生成 大きな違いはない Typed は ActorSystem ( ヒエラルキートップ)
からの 子アクター生成がメッセージ経由になる Ask 返ってくるメッセージに型がある! ask メソッドで送るメッセージに戻り先の ActorRef[U] を含める必要がある ( 送り先のActorRef[T] も受け付けれる必要がある) 2018-11-10 Scala 関西Summit 2018 34
パターン比較 スーパービジョン 2018-11-10 Scala 関西Summit 2018 35
スーパービジョンとは アクターには親子関係があり、アクターヒエラルキーを構成する 子アクターがクラッシュした際に、親アクターが子アクターをどう 扱うかを管理する仕組み 適切なエラーハンドリングを行い、状態を復元したり、再起動させ たり、安全に停止させることで、ヒエラルキー全体の自己復元力, 耐 障害性を高める 2018-11-10 Scala
関西Summit 2018 36
スーパービジョン - Akka Actors class Supervisor extends Actor { override
val supervisorStrategy: SupervisorStrategy = OneForOneStrategy(maxNrOfRetries = 10, withinTimeRange = 1.minute) { case _: ArithmeticException ⇒ Resume case _: NullPointerException ⇒ Restart case _: IllegalArgumentException ⇒ Stop case _: Exception ⇒ Escalate } def receive: Receive = { case p: Props ⇒ sender() ! context.actorOf(p) } } class Child extends Actor { def receive: Receive = { case ex: Exception ⇒ throw ex 37
スーパービジョン - Akka Typed val childBehavior: Behavior[Exception] = Behaviors.receiveMessage(throw _)
val supervisorBehavior: Behavior[Exception] = Behaviors.supervise { Behaviors.supervise { Behaviors.supervise { childBehavior }.onFailure[ArithmeticException](SupervisorStrategy.resume) }.onFailure[NullPointerException]( SupervisorStrategy.restartWithLimit( maxNrOfRetries = 10, withinTimeRange = 1.minute ) ) }.onFailure[IllegalArgumentException](SupervisorStrategy.stop) 2018-11-10 Scala 関西Summit 2018 38
スーパービジョン Actors Typed 戦略定義位置 親アクター Behavior への組み込み 戦略種別 OneForOneStrategy AllForOneStrategy
OneForOneStrategy 対応内容種別 Resume , Restart , Stop Escalate Resume , Restart , Stop 再起動制御 あり あり デフォルトの戦略 OneForOneStrategy で Restart OneForOneStrategy で Stop 2018-11-10 Scala 関西Summit 2018 39
パターン比較 ライフサイクル 2018-11-10 Scala 関西Summit 2018 40
アクターのライフサイクルとは アクターには生成から停止して削除されるまでのライフサイクルが ある ライフサイクルの各ポイントでフックでき、様々な処理を追加でき る let it crash の思想に従い、問題が起きたときのハンドリングを設計 し、組み込むことができる
スーパービジョンと組み合わせることでアプリケーション全体の耐 障害性を高める 2018-11-10 Scala 関西Summit 2018 41
アクターのライフサイクルとは Akka 実践バイブルより引用 2018-11-10 Scala 関西Summit 2018 42
ライフサイクル - Akka Actors class IdPrinterActor extends Actor { override
def preStart(): Unit = { println(s"preStart ${self.path}") super.preStart() } override def preRestart(reason: Throwable, message: Option[Any]): Unit = { println(s"preRestart $message ${self.path}") super.preRestart(reason, message) } override def postRestart(reason: Throwable): Unit = { println(s"postRestart ${reason.getMessage} ${self.path}") super.postRestart(reason) } override def postStop(): Unit = { println(s"postStop ${self.path}") super.postStop() } 2018-11-10 Scala 関西Summit 2018 43
ライフサイクル - Akka Actors class IdPrinterActor extends Actor { //
...lifecycle hook override def receive: Receive = { case Message(id) => id match { case 0L => throw new Exception("Id is zero!") case 9L => context.stop(self) case _ => println(id) } } } 2018-11-10 Scala 関西Summit 2018 44
ライフサイクル - Akka Actors object IdPrinterActor { def name(id: Long):
String = s"id-printer-$id" def props: Props = Props(classOf[IdPrinterActor]) } val system = ActorSystem() val printer1 = system.actorOf(IdPrinterActor.props, IdPrinterActor.name(1L)) printer1 ! Message(1L) val printer0 = system.actorOf(IdPrinterActor.props, IdPrinterActor.name(0L)) printer0 ! Message(0L) val printer9 = system.actorOf(IdPrinterActor.props, IdPrinterActor.name(9L)) printer9 ! Message(9L) 2018-11-10 Scala 関西Summit 2018 45
ライフサイクル - Akka Actors 見やすいように調整しています preStart akka://default/user/id-printer-1 1 preStart akka://default/user/id-printer-0
[ERROR] [11/08/2018 23:12:35.727] [default-akka.actor.default-dispatcher-4] [akka: java.lang.Exception: Id is zero! at ... preRestart Some(Message(0)) akka://default/user/id-printer-0 postStop akka://default/user/id-printer-0 postRestart Id is zero! akka://default/user/id-printer-0 preStart akka://default/user/id-printer-0 preStart akka://default/user/id-printer-9 postStop akka://default/user/id-printer-9 2018-11-10 Scala 関西Summit 2018 46
ライフサイクル - Akka Typed val idPrintBehavior: Behavior[Message] = Behaviors.supervise {
Behaviors.setup[Message] { ctx => println(s"start ${ctx.self.path}") Behaviors.receiveMessage[Message] { msg => msg.id match { case 0L => throw new Exception("Id is zero!") case 9L => Behaviors.stopped case _ => println(msg.id);Behaviors.same } }.receiveSignal { case (context, PreRestart) => println(s"preRestart ${context.self.path}");Behaviors.same case (context, PostStop) => println(s"postStop ${context.self.path}");Behaviors.same } } }.onFailure(SupervisorStrategy.restart) 2018-11-10 Scala 関西Summit 2018 47
ライフサイクル - Akka Typed def idPrinterName(id: Long): String = s"id-printer-${id.toString}"
val system = ActorSystem(SpawnProtocol.behavior, "lifecycle") import akka.actor.typed.scaladsl.AskPattern._ implicit val ec: ExecutionContext = system.executionContext implicit val timeout: Timeout = Timeout(3.seconds) implicit val scheduler: Scheduler = system.scheduler for { printer1 <- system ? SpawnProtocol.Spawn(idPrintBehavior, idPrinterName(1L)) printer0 <- system ? SpawnProtocol.Spawn(idPrintBehavior, idPrinterName(0L)) printer9 <- system ? SpawnProtocol.Spawn(idPrintBehavior, idPrinterName(9L)) } { printer1 ! Message(1L) printer0 ! Message(0L) printer9 ! Message(9L) } 2018-11-10 Scala 関西Summit 2018 48
ライフサイクル - Akka Typed 見やすいように調整しています setup akka://lifecycle/user/id-printer-1 1 setup akka://lifecycle/user/id-printer-0
preRestart akka://lifecycle/user/id-printer-0 setup akka://lifecycle/user/id-printer-0 [ERROR] [11/08/2018 23:51:35.515] [lifecycle-akka.actor.default-dispatcher-2] [ java.lang.Exception: Id is zero! at ... setup akka://lifecycle/user/id-printer-9 postStop akka://lifecycle/user/id-printer-9 2018-11-10 Scala 関西Summit 2018 49
ライフサイクル Actors Typed フック定義 override して拡張 super 呼び出しが必須 receiveSignal にて
Behavior を拡張 フック箇所の種類 preStart , postStop preRestart , postRestart PreRestart , PostStop 再起動時の フック箇所 preRestart postStop postRestart preStart PreRestart 2018-11-10 Scala 関西Summit 2018 50
他のモジュールとの統合 2018-11-10 Scala 関西Summit 2018 51
他のモジュールとの統合 Akka Streams との統合用API を含むモジュールが提供されている libraryDependencies += "com.typesafe.akka" %% "akka-stream-typed"
% akkaVersion ActorSource や ActorSink などのコンポーネントをつかい バッファや OverflowStrategy を設定して Akka Streams の Graph に Akka Actors を組み込むことができる 2018-11-10 Scala 関西Summit 2018 52
他のモジュールとの統合 その他のモジュールとの統合API も絶賛開発されていっています ( 主にクラスター関連) "com.typesafe.akka" %% "akka-cluster-typed" % akkaVersion
"com.typesafe.akka" %% "akka-cluster-sharding-typed" % akkaVersion "com.typesafe.akka" %% "akka-persistence-typed" % akkaVersion 2018-11-10 Scala 関西Summit 2018 53
他のモジュールとの統合 詳しくは公式ドキュメントやリリースノートを参照 https://doc.akka.io/docs/akka/current/typed/index.html https://akka.io/blog/news-archive.html 2018-11-10 Scala 関西Summit 2018 54
まとめ 2018-11-10 Scala 関西Summit 2018 55
まとめ Akka Typed になり より型安全にコーディングができるようになった コーディングスタイルが大きく変わるので切り替えが必要 細かな部分で Akka Actors と挙動がことなる
他のモジュールとの統合API も充実してきている アクタープログラミングの本質的な部分は変わっていない 2018-11-10 Scala 関西Summit 2018 56
参考・引用 Akka Documentation Akka 実践バイブル Wikipedia アクターモデル 2018-11-10 Scala 関西Summit
2018 57