SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

Akkaで学ぶアクターモデル入門

Akkaクラスターでアクターを用いた大規模分散システムを構築する

Akkaで学ぶアクターモデル入門 第6回

適切なノードにメッセージを送信するクラスターシャーディングの仕組み

 Akkaクラスターには関連するクラスターシャーディングというモジュールがあり、組み合わせて使うことがAkkaのベストプラクティスとされています。クラスターはクラスターシャーディングから依存されているので、通常はクラスターの仕組みを先に説明しますが、この記事ではアクターの延長で理解しやすいクラスターシャーディングの仕組みから先に説明しましょう。

 仕組みを説明する準備段階として、クラスターシャーディングが必要となる背景を、ロードバランサーを経由したリクエスト処理を例に紹介します。アプリケーションの外部から、ロードバランサーを経由して、クラスター内のあるアクター宛にメッセージが送られたとしましょう。このアクターは、クラスターを構成するノードのどれかに存在するはずですが、ロードバランサーはそれを知りません。

 ロードバランサーはアクターが存在するノードがどれなのかを知らずに、どうやってアクターにメッセージを届けるのでしょう? 力技で無理矢理解決しようとすれば、アクターにIDを割り当てる際に

  • IDがaaaから始まるアクターはノードA
  • IDがbbbから始まるアクターはノードB

といった規則に従わせることができます。ロードバランサーはこの規則性をもとに適切なノード上のアクターにメッセージを届けられますが、とても現実の運用に耐えられる仕組みではありません。多種多様なアクターのID割当規則を設定するのは非常に手間がかかりますし、長時間ノードがダウンしたら、そのノードに割当てられるべきアクターはずっと復元できないままです。さらに、クラスターを構成するノードは時間と共に増減します。

 そこで、クラスターシャーディングです。これを使えば、メッセージの送信元は、宛先のアクターがどのノード上に存在するかという情報を知る必要なくメッセージを届けられます。クラスターを構成するノード間のコミュニケーションを通じて、メッセージは宛先のアクターが存在するノードへと送られます。下図を見ればその大まかな動作がわかるでしょう。

 以下では、クラスターシャーディングに関する用語とともに、仕組みの説明をします。クラスターシャーディングにとってアクターのIDは、メッセージの送信経路を決定する重要な意味を持ちます。IDによって特定されるアクターを「エンティティ」、そのIDを「エンティティID」と呼びます。複数のエンティティをまとめたグループはシャードと紐づき、シャードもまたIDを持ちます。さらに複数のシャードは各ノードに1つだけ存在するシャード・リージョンに紐づきます。これらが成す階層構造を視覚的に表現すると、以下の図のようになります。

 シャード・リージョンは受け取ったメッセージから、シャードIDとエンティティIDを割り出します。シャード・リージョン自身は、メッセージの宛先であるエンティティがどのシャードに属し、そのシャードがどのシャード・リージョンに属すのかわかりません。そこで、シャード・コーディネーターに問い合わせて、目的のシャード・リージョンを特定します。

 目的のシャード・リージョンが、別のシャード・リージョンの場合は上図のように、メッセージを受け取ったシャード・リージョン自身の場合は下図のような動作になります。この仕組みによって、メッセージの最初の送信元はどのノードに対してメッセージを送っても、最終的に正しいエンティティにメッセージを送れます。

 非常に複雑な仕組みに見えるクラスターシャーディングですが、開発者が書くソースコードは単純になるように工夫されていて、クラスターシャーディングでもメッセージの送信にはtell APIを使います。これはクラスターを一切使わないときと同じです。

ClusterSharding sharding = ClusterSharding.get(actorSystem);

EntityTypeKey typeKey =
  EntityTypeKey.create(MessageType.class, "EntityName");

EntityRef entityRef =
  sharding.entityRefFor(typeKey, "entity-id-aaa");

entityRef.tell(message);

 クラスター利用の有無にかかわらず、同じtell APIを使えるのがAkkaの設計の優れたところです。Akkaは最初から分散システムを念頭において開発されたので、1台のノードでもクラスターでも、メッセージの送り方は共通しているのです。そして上記のソースコードで、ノードを意識することなく、エンティティIDだけで送信先が特定できることに注目してください。ノードの情報、例えばそのIPアドレスを意識せずメッセージを送信できることは、Akkaを使ったプログラミングを楽にしてくれます。

 クラスターシャーディングを使えば、あるIDを持つアクターは、クラスター内に基本的に1つだけ存在します。では、そのアクターが存在するノードがダウンしたらどうなるでしょう? クラスターがノードのダウンを検知した場合、そのアクターを別のノードで復元します。その際に前回説明したイベント・ソーシングを用いれば、永続化した履歴から内部状態を復元できます。

 クラスターシャーディングはこのように良くできた仕組みなのですが、ノードのダウンを検知するというのは、実は非常に奥が深く、現実の世界では多くの人が想像する以上に困難なことです。ここから先は、ノードのダウンを入り口に、分散システムの理論を紹介します。

次のページ
ノードから見る分散システムの概要

この記事は参考になりましたか?

Akkaで学ぶアクターモデル入門連載記事一覧

もっと読む

この記事の著者

リチャード 伊真岡(リチャード イマオカ)

 大学卒業後、9年間証券会社にてプログラマ兼技術サポートとして勤務。その後いくつかの企業でバックエンド・エンジニアや技術広報などを務める。  プライベートでは過去にScala/JavaのOSSであるakkaへ貢献。 Twitter:@RichardImaokaJP

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/13588 2021/05/10 11:00

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー