アクターモデルとは
アクターモデルは1973年に発表された並列演算モデルであり、現在では並行処理を行うためのモデルのひとつとして広く利用されています。このアクターモデルは独立したプロセスとして振る舞う「アクター」と呼ばれるオブジェクトがメッセージをやり取りすることで処理が行われます。
アクターモデルはオブジェクト指向プログラミングの一種であり、オブジェクト間の通信をメッセージパッシングで行うことが特徴で、これまでのPHPではあまり見かけないプログラミングスタイルとなっています。
Erlang、Java、Scala、Goなどの言語で使われることが多いアクターモデルですが、筆者はPHPでアクターモデルを実装するためのツールキット「Phluxor」を開発し、OSSとして公開しています。
筆者は、過去やGoやScalaでアクターモデルの導入を経験し、障害に強く、パフォーマンス面などでも強力なアドバンテージがあると感じていました。このアクターモデルをPHPで実現できたら、PHPのアプリケーション開発の開発者体験がよくなり、PHP自体の可能性を広げることができるのではと思い、この「Phluxor」を開発しました。
このアクターモデルを理解しておくと、他言語への転用も容易になり、開発者自身の可能性も広がります。本記事では、Phluxorを例として、アクターモデルの基本的な動作を少しだけ紹介します。通常触れているものとは異なるプログラミングパラダイムに触れ、アクターモデルの可能性を感じる機会になれば幸いです。
Phluxorとは
PhluxorはAkkaやPekko、Proto Actorといった他の言語で使われるアクターモデルのツールキットと同じ概念をもとに、アクターモデルの基本的な機能を提供しています。
Phluxorでは、アクターの生成、メッセージの送信、アクターの状態の管理・復元、試験的な機能ではありますがネットワークを介したアクター間の通信などを行うことができます。
すべてのアクターは独立して動作し、状態を共有することなくすべて並行で動作します。スケールアウトや高負荷に耐えるシステムを構築するための基盤作りを理解するためにも利用でき、CQRSやイベントソーシングなどを実現するための基盤としても利用できます。
これらはPHPの拡張機能のひとつ、Swooleを利用して実装しており、PHPのプログラムから難しい並行処理の課題を意識することなく簡単に利用できるようになっています。
アクターモデルを使ってみよう
まずはPhluxorのインストールをComposerで行います。
$ composer require phluxor/phluxor
アクターモデルを導入する場合は「すべてのものはアクターである」という哲学に基づいて実装を行っていきます。この例ではアクターモデルを使ってHello Worldを表示するプログラムを、以下のディレクトリ構成で作成します。
├── composer.json ├── main.php └── src ├── HelloActor.php └── Message ├── HelloRequest.php └── HelloResponse.php
アクターモデルを利用する場合はメッセージを使ったやり取りを行うため、送受信で利用するメッセージとアクターを作成します。
送信するメッセージはHelloRequest、受信するメッセージはHelloResponseとしてそれぞれのメッセージクラスを作成します。
<?php declare(strict_types=1); namespace Sample\Message; readonly class HelloRequest { public function __construct( public string $message ) { } }
<?php declare(strict_types=1); namespace Sample\Message; readonly class HelloResponse { public function __construct( public string $message ) { } }
次に、このメッセージに対応したアクターを作成します。PhluxorではPhluxor\ActorSystem\Message\ActorInterface
を実装することで、アクターとして振る舞うことができます。
<?php declare(strict_types=1); namespace Sample; use Phluxor\ActorSystem\Context\ContextInterface; use Phluxor\ActorSystem\Message\ActorInterface; class HelloActor implements ActorInterface { public function receive(ContextInterface $context): void { $message = $context->message(); if ($message instanceof Message\HelloRequest) { $response = new Message\HelloResponse('Hello, ' . $message->message); $context->respond($response); } } }
アクターはreceive
メソッドを実装することで、メッセージを受信できます。Phluxor\ActorSystem\Context\ContextInterface
からメッセージを取得し、メッセージに対応した処理を行います。
このコンテキストにはメッセージの送信元やアクターの情報などが含まれています。アクターはヒエラルキー構造を形成し、親アクターから子アクターへメッセージを送信することや、子アクターの監督・監視なども行うことができますので、本格的なアクターモデルを実装することも可能ですので興味のある方はぜひ試してみてください。
ここではHelloRequestメッセージを受信した場合に、HelloResponseメッセージを作成し、送信元に返信する処理を行っています。返信にはrespond
メソッドを利用していますが、このメソッドはアクターがメッセージを受信した際に送信元に返信するためのメソッドです。
他にもsend
メソッドを利用することで、他のアクターにメッセージを送信することもできます。send
メソッドはfire-and-forget
となりますので、返信を受け取ることはできません。
これらの動作はアクターモデルの基本的な動作となります。
PHPに慣れている方は戻り値を返すことが多いと思いますが、アクターモデルではreturn
を利用することはありません。アクターはすべて独立して動作し並行して処理を行いますので、返す値はメッセージを送信することで行います。
また、アクターは自身で状態管理を行いますので、外部からのアクセスや直接の操作なども行うこともできませんので、アクターモデルを利用する際はこの点に注意して実装するようにしてください。