Goで実践 アクターモデル はじめに

まえがき

アクターモデルといえばErlang、もしくはScala/Javaなどで利用できるAkka/Pekkoがデファクトですが、
Go言語でも不自由なく利用できるProto Actorというツールキットがあります。

Akka/Pekkoほど機能はないため いくつかは自分で実装しなければいけません。
が、不自由ないくらいに機能が揃っています(筆者はPekkoとともにProto Actorも実際に利用しています)。

アクターモデルはプログラミングパラダイムでもあるため、
これまで利用してきたプログラミングの考え方などから少しだけ奇妙に見えるかもしませんが、
理解することで高いレベルで並行処理や分散処理を導入することができ、
イミュータブルで、弾力性や耐障害性なども大きく進歩したシステム作りのヒントになると思います。
ぜひこのシリーズものになる予定のブログ記事などから触れてみてください。

初めての方でもある程度理解できるように解説していきます。
ただしプログラミングを習得し始めの方や、Goなどがわからない方、
並行処理などに明るくない方には難しいかもしれません。
そういった方向けの解説にはなりませんのでご了承ください。

アクターモデルについて

アクターモデルをしっかりと理解するには、これまでのプログラミングに対する考え方と
多少見方を変える必要があります。

アクターモデルを学ぶ上で必要なのは、
OOPに慣れている方はOOPと切り離して考える必要があります。

対象などオブジェクトとして捉えないわけではありませんが、少しだけ考え方が異なります。
当然ですが言語的な構文などの違いは当然ありませので、
言語機能的な実装や抽象化などはそのまま取り組むことができますが、
アクターは情報伝達の経路自体を作る感覚に近く、
誰がどうするか、といったものは全てアクターで表現します。

そして状態管理とメッセージ設計がポイントになります。

SQSやKinesis、Kafkaといったメッセージングシステムを使ったことがある方は、
あのメッセージングシステム自体を作るような印象を持つかもしれません。

アクターモデルは
メッセージがあり、誰が受け取り、受け取った時にどうするかでしかありません。

メッセージのみのやり取りが許可されており、それはどこから送られてきても良い
所在地さえわかれば誰でもメッセージを送ることができる、という仕組みになっています。

そしてこのメッセージはイミュータブルで変更することはできません。
受け取るアクターを意図的に操作することもできません。

メッセージは変更できないイベントとして状態と共に永続化することができ、
任意の状態から復元することができます。
つまりイベントソーシングを実現できるようになっています。

慣れ親しんだプログラミングでは、
オブジェクトを疎結合にしても、戻り値を利用するのが基本になっていますが、
(オブジェクトや関数間でも値のやり取りはメッセージとして考えられます。)
アクターモデルでは全てをアクターとして考える哲学がベースになっており、
基本的に並行・非同期となるため戻り値は利用しません。
(全く利用できないわけではありません)
戻り値を利用する場合は、
結果どうなったかをメッセージとしてアクターに送信する必要があります。

またアクターそれぞれにライフサイクルがあり、
送信元も送信先も同時に存在せずとも機能します。

アクターそれぞれに固有の識別可能なIDが割り当てられ(アドレスになります)、
アドレス宛にメッセージの送受信(非同期)でやり取りを行い、すべて並行で処理されます。
指定したアドレスのアクターが存在しない場合は、自動的にアクターが起動します。
受け取ったメッセージはアクターのmailboxに格納されFIFOで処理されます。

基本的な動作はこれだけです。

実生活を例に

学校生活を例にアクターを考えてみましょう。

学校の中にはたくさんのアクターがあります。
先生や生徒、校長先生などそれぞれの役割を担う人がいます。
有機的なものだけでなく、学校自体や教室などもアクターとして考えることができます。
(どうモデリングするか次第ではありますが)

これらのアクターはそれぞれが自分で行動することができます。
生徒であれば勉強したり、校庭で遊んだり友達会話したり、
先生は授業をしたり、テストを作るなどがあります。
教室も授業の時間や休み時間なども存在しそれぞれ時間軸があります。

学校生活では宿題が避けられませんので、宿題を考えてみましょう。

先生は生徒みんなに宿題を出します(媒体問わず)

生徒は宿題をうけとります
生徒は家に持ち帰るなどして、それぞれの生徒が好きなタイミングで宿題を始めます。

宿題と向き合っている時、他の生徒のことを気にすることはありませんし、
先生が何をしているか考えることもありませんし、先生がそこにいる必要もありません。

宿題をするには自分ことだけを考えれば良いということになります。
その宿題は期限までに宿題を提出します。

それぞれの生徒がそれぞれのペースで宿題をおわらせて
先生に提出します。
ある生徒は宿題が間に合わないかもしれませんが、その場合は間に合わないと先生に伝えます。

これらはアクターが自分の仕事だけをして、
自分の仕事が終わったタイミングでメッセージ(状態)を伝える
のと同じです。

先生は宿題を出し、それが期限までに提出されれば良いだけです。
その場で同期・非同期問わず戻り値を期待するのではなく、
生徒全員が同期・非同期関係なく宿題をやりました、やった宿題の内容はこれです(イベントソーシング)、とだけわかれば良いのです。

生徒は宿題を完了させて、任意のタイミングでその内容を送るだけです。
生徒それぞれ宿題と向き合うため分散でそれぞれが行動することになります。

つまり生徒からのメッセージは、生徒ごとに状態を持っている必要があり、
とあるIDだけをもらい、
そのIDから情報を構築するようなメッセージにはならないということでもあります。

文章はこの辺で、次回はコードと合わせて解説をしていきます。