これをポイントに分けて、意味をなすことを願っています。The Hitchhiker's Guide to Concurrencyに書いたことを少し再ハッシュするかもしれません。Erlang でメッセージ パッシングが行われる方法の背後にある理論的根拠の詳細を得るために、それを読みたいと思うかもしれません。
1.メッセージ送信
Erlang でのメッセージ パッシングは、メールボックス (データを格納するための一種のキュー) に送信される非同期メッセージを通じて行われます。メッセージが受信されたかどうか、または有効なプロセスに送信されたかどうかについても、まったく仮定がありません。これは、[言語レベルで] 誰かがおそらく 4 日でメッセージを処理したいと考え、特定の状態に達するまでその存在を認めようとしないと想定するのがもっともらしいためです。
このランダムな例として、データを 4 時間処理する長時間実行プロセスを想像してみてください。メッセージを処理できない場合、メッセージを受信したことを本当に認めるべきでしょうか? そうすべきかもしれませんし、そうでないかもしれません。それは本当にあなたのアプリケーションに依存します。そのため、仮定は行われません。メッセージの半分を非同期にすることができ、そうでないものは 1 つだけにすることができます。
Erlang は、必要に応じて確認メッセージを送信する (そしてタイムアウトで待機する) ことを期待しています。タイムアウトに関係する規則と応答の形式は、指定するプログラマーに任されています -- Erlang は、タスクが完了したときに、メッセージが一致するかどうか (メッセージコードの新しいバージョンがホットロードされると、4 時間以内に一致する可能性があります) など。
簡単に言えば、メッセージが読まれなかったり、受信に失敗したり、送信中に誰かがプラグを抜いて中断したりしても、あなたがそれを望まなければ問題ではありません。それを問題にしたい場合は、プロセス全体のロジックを設計する必要があります。
Erlang プロセス間で高レベルのメッセージ プロトコルを実装する負担は、プログラマに与えられます。
2. メッセージプロトコル
あなたが言ったように、これらのメッセージは一時的なメモリに保存されます。プロセスが終了すると、まだ読み取られていないすべてのメッセージが失われます。もっと欲しい場合は、さまざまな戦略があります。それらのいくつかは次のとおりです。
- メッセージをできるだけ速く読み取り、必要に応じてディスクに書き込み、確認応答を返信して後で処理します。これを、RabbitMQ や ActiveMQ などの永続的なキューを持つキュー ソフトウェアと比較してください。
- プロセス グループを使用して、複数のノード上のプロセス グループ全体でメッセージを複製します。この時点で、トランザクションのセマンティクスを入力できます。これは、トランザクション コミット用の mnesia データベースに使用されます。
- すべてがうまくいったという確認応答または失敗メッセージを受け取るまで、何も機能していると思い込まないでください。
- プロセス グループと失敗メッセージの組み合わせ。最初のプロセスが (ノードがダウンしたために) タスクの処理に失敗した場合、通知が VM によって自動的にフェールオーバー プロセスに送信され、そこで代わりに処理されます。この方法は、ハードウェア障害を処理するために完全なアプリケーションで使用されることがあります。
当面のタスクに応じて、これらの 1 つまたは複数を使用できます。それらはすべて Erlang で実装することが可能であり、多くの場合、モジュールはすでに作成されており、面倒な作業を行うことができます。
したがって、これはあなたの質問に答えるかもしれません。プロトコルは自分で実装するため、メッセージが複数回送信されるかどうかはユーザーが選択できます。
3. 耐障害性とは
上記の戦略のいずれを選択するかは、フォールト トレランスがあなたにとって何を意味するかによって異なります。場合によっては、「データが失われることはなく、タスクが失敗することもありません」と言う意味があります。フォールト トレランスを使用して、「ユーザーがクラッシュすることは決してない」と言う人もいます。Erlang システムの場合、通常の意味は、システムを稼働させ続けることです。全員が電話を切るよりも、1 人のユーザーが電話を切っても問題ありません。
ここでのアイデアは、失敗したものは失敗させますが、残りは実行し続けることです。これを実現するために、VM が提供するものがいくつかあります。
- プロセスが停止した時期とその理由を知ることができます
- 相互に依存しているプロセスのいずれかが失敗した場合、それらのプロセスを一緒に停止させることができます
- キャッチされていないすべての例外を自動的にログに記録するロガーを実行でき、独自の例外を定義することもできます
- ノードを監視できるので、ノードがいつダウンしたか (または切断されたか) を知ることができます
- 失敗したプロセス (または失敗したプロセスのグループ) を再起動できます。
- 1 つのノードで障害が発生した場合、アプリケーション全体を別のノードで再起動する
- OTP フレームワークにはさらに多くのものがあります
これらのツールと、さまざまなシナリオを処理する標準ライブラリのいくつかのモジュールを使用すると、Erlang の非同期セマンティクスの上に必要なものをほとんど実装できます。
4. いくつかの注意事項
ここでの私の個人的な意見は、純粋なトランザクション セマンティクスが必要でない限り、Erlang に存在する以上の仮定を持つことはかなり難しいということです。常に問題になる問題の 1 つは、ノードがダウンすることです。サーバーが実際にクラッシュしたためにダウンしたのか、ネットワークに障害が発生したためにダウンしたのかはわかりません。
サーバーがクラッシュした場合、タスクをやり直すだけで十分です。ただし、ネット スプリットでは、いくつかの重要な操作が 2 回実行されないようにする必要がありますが、失われることもありません。
それは通常、基本的に 3 つのオプションを提供するCAP 定理に要約され、そのうちの 2 つを選択する必要があります。
- 一貫性
- 分割耐性
- 可用性
自分の位置に応じて、さまざまなアプローチが必要になります。CAP 定理は通常、データベースを説明するために使用されますが、データを処理する際にある程度の耐障害性が必要な場合は常に、同様の質問をする必要があると思います。