クラスター機能

警告

クラスター機能は実験的機能のため、正式版では仕様が変更される可能性があります

概要

これは Sora でクラスターを構成し、冗長化、負荷分散を行うための仕組みです。

クラスター内では、ひとつのチャネル ID への接続は、担当するひとつの Sora ノードにすべて割り当てられます。 クライアントがクラスターを構成しているいずれかの Sora に接続した際には、 そのチャネル ID で、接続すべき Sora の Signaling URL を提示する仕組みです。

目的

可用性を高めるため Sora 複数台でクラスターを組み、冗長化やロードバランシングを実現します。

仕組み

Sora のクラスター機能の仕組みは、ひとつのチャネル ID への接続は、 担当するひとつの Sora ノードにすべて割り当てるものです。 これを実現するために、Sora のクラスターに参加しているそれぞれの Sora ノードは、 どのノードがどのチャネルを担当するべきかを把握しています。 そして、自分が担当でなかったら担当者にリダイレクトすることにより、 クライアントは担当ノードを意識することなく、任意のノードにアクセスするだけで担当ノードに接続できます。

特徴

注釈

これらの仕組みは sora.conf にてクラスター機能を有効にした場合に使用できます

クライアントへの複数シグナリング設定

Sora SDK にシグナリング URL を複数指定することで、いずれかの Sora ノードが正常に動作していれば Sora に繋がります。

Sora ノード選択 / ロードバランス機能

クラスターを構築している Sora ノードの中で 現在の同時接続数ライセンスの最大同時接続数 で割った値が一番小さい Sora ノードに新規チャネル ID の担当を割り当てます。 値が全て同じ場合は接続しに行ったノードが担当します。

すでにそのチャネル ID がクラスター内部で利用されている場合は、 そのチャネル ID を担当している Sora ノードへ割り当てられます。

シグナリングのリダイレクト機能

重要

Sora の SDK を利用している場合は、基本的にここに書かれているリダイレクトの 細かい仕様を把握する必要はありません。

"type": "connect" を送った際、認証に入る前に {"type": "redirect", "location": "wss://sora1.example.com/signaling"} が戻ってくる場合があります。

この場合は送られてきたシグナリング URL に切り替えて再度 type: connect を行ってください。 その際は {type: connect, redirect: true} のように redirect: true を追加情報として入れてください。

HTTP API のリダイレクト機能

チャネル ID を指定する HTTP API を利用する場合、リダイレクトが発生することがあります。 指定されたチャネル ID を他ノードが担当している場合に、ステータスコード 307 (Temporary Redirect)の HTTP 応答により、クライアントにそのノードへのリダイレクトを要求します。

ステータス 307 の処理は HTTP のクライアントとするツールやライブラリにより異なります。 必要に応じて、リダイレクト応答の Location ヘッダーへアクセスを継続するようにしてください。

たとえば、curl コマンドの場合は、 -L オプションを指定することでリダイレクト先への再要求を行います。

クラスター自動参加機能

複数の Sora ノードでクラスターを自動構築する機能です。

Sora はクラスターが有効な際、起動時に sora.confcontact_node_name_list に存在する ノード名に対してクラスターの参加を自動で試みます。

もし、そのノードが一度でもクラスターに参加したことがある場合は、そのクラスターに参加していた時の ノード一覧 利用して、クラスターへの参加を自動で試みます。

クラスター手動参加機能

重要

sora.confcontact_node_name_list を利用した自動参加の利用を推奨しています。

複数の Sora でクラスターを手動で組む機能です。クラスターに参加する際に JoinCluster API を叩きます。

すでにクラスターが存在している場合には、そこに参加しているノードのいずれかを引数の contact_node_name で指定してくだ さい。クラスターに参加していれば、どのノードでもかまいません。新規にクラスターを作成する場合には、起動中の任意のノードを contact_node_name に指定して大丈夫です。

クラスター自動復旧

クラスターで利用しているネットワークに障害が発生した際、個々のノードはクラスターを構成する他のノードへの接続を試み、復旧 処理を行います。

ネットワーク分断時の接続受付の停止

ネットワーク分断時には Sora のノード間で通信ができず、クラスター内の情報の整合性が取れなくなる可能性があります。 不整合を回避するために、Sora は自分が過半数未満のグループに属した場合に、既存の接続を切断した上で、 新規接続の受付を停止します。

特定ノードへの新規チャネル ID の割り当て停止

モード機能イニシャルモード新規コネクションブロックモード または 新規セッションブロックモード になっている場合は、

そのノードに対して新規チャネル ID の割り当てを行いません。

録画情報の共有

録画の情報はクラスター内部で共有されます。 たとえば StartRecording API をあるノードに対して実行した後にそのノードが停止しても 録画情報は他のノードに残り続けます。

ポート番号の開放

以下のポート番号を開放して下さい

  • epmd(Erlang Port Mapper Daemon)で利用する TCP/IP ポート番号

    • 4369

  • ノード間通信に利用する TCP/IP ポート番号

    • 49010 - 49020

    • sora.confcluster_listen_(min|max)_port にて指定可能です

注意

ライセンス

クラスターの 1 Sora ノードにつき 1 ライセンスが必要になります。 3 台の Sora ノードでクラスターを組む場合は 3 ライセンス必要になります。

注釈

最大ノード数ライセンス を利用することで、同一ライセンスを複数 Sora ノードで利用することが可能になります。

クラスターのノード数

クラスター機能を有効にしている場合は 1 ノードだけでは利用できず、必ず 2 ノード以上である必要があります。

注釈

1 ノードの場合は接続を受け付けません

重要

2022 年 12 月リリースの Sora からは 2 ノードでのクラスター構築には非対応となり、3 ノード以上が必須となる予定です。

クラスターからのノードの消去について

クラスターからノードを完全に消去させる場合は bin/sora stop で停止させた後に、 クラスターを構成してる実行中のノードのいずれかに対し、PurgeClusterNode API を実行します。

クラスターノードリストファイル

危険

このファイルは Sora が内部で利用するためのファイルなので触らないでください。

Sora でクラスターを利用する場合、クラスター参加後のノード情報を永続化する data/cluster-nodes.bin というファイルを生成します。

アップデート時にこのファイルをコピーする必要はありません。ファイルが無い場合、クラスターに参加した際に生成されます。

障害時の録画情報の消去

将来的にこの問題は解決する予定はありますが、時期は未定です

クラスターに所属するすべてのノードが過半数未満に所属した場合に、録画情報は消去されます。 この場合には recording.report イベントウェブフックは発火せず、 report-<recording_id>.json レポートファイルも生成されません。

クラスター機能有効時のモード

クラスター機能を有効にした場合、 Sora は :ref:`イニシャルモード`という クラスター機能だけで利用される特殊なモードで起動します。

ネットワーク障害やノード障害

Sora のクラスター機能はネットワーク障害やノード障害が発生した際に、 自動で新規接続の受付の停止とそこからの復旧を試みます。

発生しうる問題と新規接続の受付停止

ネットワーク障害等が発生した場合には、 Sora のノード間で通信ができず、クラスター内の情報の整合性が取れなくなる可能性があります。

たとえば、5 ノードのクラスターが 3 ノードからなるグループ A と 残りの 2 ノードからなるグループ B の 2 グループに分断されるということが起こりえます。 それぞれのグループ内では通信ができるものの、他グループへの通信ができないという状態です。 この状態ですべてのノードが接続を受け付けると、同じチャネル ID を指定していても、 あるクライアントはグループ A に繋がり、別のクライアントは グルーブ B につながる可能性があり、 その場合はクライアント間で音声と映像が届かなくなります。

このような状況を防止するため、Sora は自分が過半数未満のグループに属した場合に、新規接続の受付を停止します。 特に、自分が孤立した場合もこれに含まれます。

その後、クラスター自動復旧により、通信できるノードがで過半数以上となった場合には、自動で新規接続の受付を再開します。

新規接続の受付がまったくできなくなる場合

障害の状況によっては新規接続の受付がまったくできなくなる場合もあります。 例えばネットワークの分断と状態によって、5 ノードのクラスターが 2 ノード、2 ノード、1 ノードという 3 つ以上のグループに分断された状況を考えます。 この場合にはどのノードも過半数未満となるため、新規接続の受付はまったくできなくなります。

ネットワーク障害ではなくても、5 ノードクラスターで、3 ノードが停止してしまった場合には、残った 2 ノードは 過半数未満となるため、新規接続の受付はできません。

タイブレークによる特別な「過半数」

重要

2022 年 12 月リリースの Sora からはタイブレーク処理は廃止される予定です。 それに伴い 2 ノードでのクラスター構築には非対応となり 3 ノード以上が必須となります。

クラスターを構成するノードが偶数の場合、ネットワーク分断時に自分と通信可能なノード数がちょうど半数になることがあります。 たとえば 4 ノードクラスターで 2 ノードのグループがふたつできる状態です。

単純にノード数を数えた場合には両グループともに過半数には届かず、新規接続の受付が完全に停止してしまいます。 これを避けるために、Sora は「過半数」の判断に特別なタイブレークを適用します。

タイブレークのロジックは、辞書順に見てノード名が一番小さなノードが参加しているクラスターを「過半数」とするものです。

上記の 4 ノードクラスターで、 sora1@192.0.2.1sora4@192.0.2.4 がひとつの通信可能なグループ、 sora2@192.0.2.2sora3@192.0.2.3 がもうひとつのグループと分断された例を考えます。 辞書順の一番小さなノードは sora1@192.0.2.1 であるため、このノードと sora4@192.0.2.4 は 新規接続の受付を継続し、他の 2 ノードは停止します。

このドキュメントでは「過半数」という用語を、単純なノード数を数えた過半数だけではなく、 このタイブレークでの勝者グループを含めた意味で用います。

通信できるノードが過半数未満となった場合の挙動

ノード数が過半数未満のクラスターに参加しているノードは、接続中のすべての接続を切断し、その後は接続を受け入れません。

また、その時のモードによってモードが変わることがあります。

その後はクラスター自動復旧を試みます。

通信できるノードが過半数以上となった場合の挙動

通信できるノードが過半数未満から過半数以上に変わったタイミングで、そのときのモードによってモードが変わることがあります。

遷移後のモードに従って、新規接続を受け付けます。

全ノードが過半数未満に所属した場合の挙動

ネットワーク障害等が発生したことで、いずれのノードも通信できるノードが過半数未満になった場合、 新規接続はまったく受け付けられない状態になります。

この場合でも、永続化しておいたノード一覧を利用し自動でクラスターの復旧を試みます。 復旧して過半数以上のグループができた場合は新規接続が可能になります。

クラスター環境での録画

録画情報の共有

録画の情報はクラスター内部で共有されます。 たとえば StartRecording API をあるノードに対して実行した後にそのノードが停止しても 録画情報は他のノードに残り続けます。 また StopRecording API はどのノードに対しても実行することができます。

たとえば、あるチャネルで StartRecording API が実行された後に、 ノード A に接続がきて録画が開始したとします。 このノード A がノード障害等で終了した後に、同じチャネルで別の接続がノード B に来た場合には ノード B で録画が進行します。

録画ファイルの出力ノード

archive-<connection_id>.json, archive-<connection_id>.webm の録画ファイルは、接続を担当するノードで 出力されます。

次のような場合には同一の recording_id に属する録画ファイルが、 複数ノードにまたがって出力されることがありますのでご注意ください。

  1. 録画開始

  2. ノード A に接続が来てしばらくして終了、録画ファイルがノード A に作られる

  3. ノード A が停止

  4. ノード B に接続が来てしばらくして終了、録画ファイルがノード B に作られる

report-<recording_id>.json ファイルの出力ノード

あるチャネルに対して、 StopRecording API を実行した場合には録画が終了し、 report-<recording_id>.json ファイルが出力されます。

このファイルの出力ノードは次のとおりです。

  • そのチャネルに接続したクライアントがひとつもなかった場合はどのノードで出力されるかは未定です

    • ただし、クラスター内のいずれかのノードで出力されます

  • そのチャネルに接続中のクライアントがいる場合は、チャネルの担当ノードで出力されます

  • そのチャネルに接続したクライアントが過去にいた場合は 2 パターンがありえます

    • クライアントが接続したノードが生存し続けている場合はそのノードで出力されます

    • ノードが落ちている、または停止した後に再起動した場合にはどのノードで出力されるかは未定です

      • ただし、クラスター内のいずれかのノードで出力されます

report-<recording_id>.json ファイルが出力されない場合

全ノードが過半数未満に所属した場合には report-<recording_id>.json ファイルが出力されません。 また、録画情報自体も消去されます。

5 ノードのクラスターがあるとして、いくつか例を示します。

  • ネットワーク障害が発生し、2 + 2 + 1 に分断された場合

  • ノード障害(運用での停止も含む)が発生し、3 ノードが停止した場合

  • ノード障害で 1 ノードが停止した状態でネットワーク障害が発生し、 2 + 2 に分断された場合

設定

cluster

クラスター機能を利用する場合、 sora.conf にて clustertrue を設定する必要があります。

デフォルトでは cluster は有効になっていません。

重要

cluster = true にして Sora を起動した場合、 Sora はすべての接続を受け付けない イニシャルモード モードで起動します。

自動または手動でクラスターに参加した後、過半数以上のグループになった時点で ノーマルモード へ自動で切り替わります。

cluster = true

node_name

クラスター機能を利用する際のノード名を指定して下さい。

ここで指定するノード名は sora.confcontact_node_name_listJoinCluster API、 PurgeClusterNode API で指定する際に利用するノード名です。 ノード名の @ の前には、正規表現 [0-9A-Za-z_\\-]+ にマッチする文字列を指定してください。 また @ の後ろには、サーバーのドメイン名(FQDN)や、IP アドレスを指定してください。

重要

クラスターどうしの通信は暗号化されていないため、プライベートネットワークを利用するか 暗号化されたネットワークを利用してください。

重要

@ の後ろにホスト名("." を含まない文字列)を指定すると、ノード間で通信が行えなくなってしまいます。

重要

クラスター参加後にノード名を変更する場合には、古い方の名前は PurgeClusterNode API を用いて削除してください。

# ドメイン名を指定する例
node_name = [email protected]
# IP アドレスを指定する例
node_name = [email protected]

contact_node_name_list

クラスター機能が有効な場合で、 sora.confcontact_node_name_list が指定されていた場合、 起動時に自分以外のノード名に対して自動でクラスターの参加を試みます。

注釈

自分自身のノード名が concact_node_name_list に含まれていても無視します。

cluster_auto_reconnect

クラスター機能が有効な場合で、 sora.confcluster_auto_reconnecttrue の場合、 ネットワーク障害やノード障害の発生時に自動で再接続を試みます。

この設定はデフォルトで有効です。

cluster_auto_reconnect = true

external_signaling_url

sora.conf にてシグナリングの URL を指定して下さい。 この URL はクラスター機能を利用した際に "type": "redirect""location" の値として払い出されます。

external_signaling_url = wss://node1.example.com/signaling

上記の設定をした場合は {"type": "redirect", "location": "wss://node1.example.com/signaling"} として払い出されます。

external_api_url

sora.conf にて API の URL を指定して下さい。 この URL はクラスター機能を利用した際に API を適切なノードに HTTP 307 でリダイレクトする際、 HTTP ヘッダー "location" の値として払い出されます。

external_api_url = https://node1.example.com/

cluster_listen_(min|max)_port

sora.conf にてクラスター情報の同期に利用する TCP/IP の受信ポートの範囲を指定してください。

デフォルトでは 49010 - 49020 が指定されています。

cluster_listen_min_port = 49010
cluster_listen_max_port = 49020

API

クラスター参加 API

Tip

sora.confcontact_node_name_list を利用したクラスターへの自動参加の利用を推奨しています。

参加するノードに対して、すでにクラスターに参加しているノードを指定してクラスターへ参加をします。

詳細は JoinCluster API をご確認ください。

http POST 127.0.0.1:3000/ x-sora-target:Sora_20211215.JoinCluster \
    [email protected]
HTTP/1.1 200 OK
content-length: 646
content-type: application/json
date: Tue, 16 Nov 2021 08:42:25 GMT
server: Cowboy

{
    "node_name_list": [
        "[email protected]",
        "[email protected]",
        "[email protected]"
    ]
}

クラスターノード消去 API

ある Sora ノードが障害で再参加が難しい、またはスケールインのためにノード破棄する場合は PurgeClusterNode API を利用して、そのノード情報を消去してください。

これはクラスターのどのノードでもかまわないので 1 回だけ実行すれば、消去した結果はクラスター内部で共有されます。

$ http POST 127.0.0.1:3000/ x-sora-target:Sora_20220629.PurgeClusterNode \
    target_node_name=[email protected]

詳細は PurgeClusterNode API をご確認ください。

クラスターノード一覧 API

詳細は ListClusterNodes API をご確認ください。

$ http POST 127.0.0.1:3000/ x-sora-target:Sora_20211215.ListClusterNodes
HTTP/1.1 200 OK
content-length: 1051
content-type: application/json
date: Tue, 16 Nov 2021 08:36:25 GMT
server: Cowboy

[
    {
        "external_api_url": "http://192.0.2.8:3000/",
        "epoch": 1,
        "license_max_connections": 600,
        "license_max_nodes": 10,
        "license_serial_code": "ABCDEF-SRA-E003-203801-500",
        "license_type": "Experimental",
        "member_since": "2021-11-16T08:29:36.972932Z",
        "node_name": "[email protected]",
        "connected": true,
        "mode": "normal",
        "external_signaling_url": "wss://node-03.example.com/signaling",
        "version": "2022.1.0"
    },
    {
        "external_api_url": "http://192.0.2.7:3000/",
        "epoch": 1,
        "license_max_connections": 600,
        "license_max_nodes": 10,
        "license_serial_code": "ABCDEF-SRA-E002-203801-400",
        "license_type": "Experimental",
        "member_since": "2021-11-16T08:22:46.898730Z",
        "node_name": "[email protected]",
        "connected": true,
        "mode": "normal",
        "external_signaling_url": "wss://node-02.example.com/signaling",
        "version": "2022.1.0"
    },
    {
        "external_api_url": "http://192.0.2.5:3000/",
        "epoch": 1,
        "license_max_connections": 600,
        "license_max_nodes": 10,
        "license_serial_code": "ABCDEF-SRA-E001-203801-400",
        "license_type": "Experimental",
        "member_since": "2021-11-16T08:23:02.488711Z",
        "node_name": "[email protected]",
        "connected": true,
        "mode": "normal",
        "external_signaling_url": "wss://node-01.example.com/signaling",
        "version": "2022.1.0"
    }
]

クラスターチャネル割り当て一覧 API

詳細は ListClusterChannels API をご確認ください。

$ http POST 127.0.0.1:3000/ x-sora-target:Sora_20211215.ListClusterChannels
HTTP/1.1 200 OK
content-length: 646
content-type: application/json
date: Tue, 16 Nov 2021 08:42:25 GMT
server: Cowboy

[
    {
        "channel_id": "sora",
        "node_in_charge": "[email protected]",
        "node_in_charge_epoch": 1,
        "node_in_charge_epoch_stale": false,
        "node_in_charge_connected": true
    },
    {
        "channel_id": "lemon",
        "node_in_charge": "[email protected]",
        "node_in_charge_epoch": 1,
        "node_in_charge_epoch_stale": false,
        "node_in_charge_connected": true
    },
    {
        "channel_id": "hisui",
        "node_in_charge": "[email protected]",
        "node_in_charge_epoch": 2,
        "node_in_charge_epoch_stale": false,
        "node_in_charge_connected": true
    },
    {
        "channel_id": "zakuro",
        "node_in_charge": "[email protected]",
        "node_in_charge_epoch": 2,
        "node_in_charge_epoch_stale": false,
        "node_in_charge_connected": true
    }
]

クラスター構築

重要

node_name はクラスター内のすべてのノードでユニークである必要があります

ライセンス

Sora ノード数分のライセンスが必要になります。 Sora 3 台でクラスターを組む場合は通常のライセンスが 3 つ、もしくは 3 ノード以上に対応した 最大ノード数ライセンスが 1 つ必要です。

3 台での構築

クラスターを構築する際、クラスターを同期するネットワークは可能な限りプライベートネットワークを利用してください。

  1. 必要なすべてのサーバーのポート開放

    • TCP/IP 4369

      • ポート番号の変更はできません、必ずこのポートを開放してください

    • TCP/IP 49010-49020

      • sora.conf にて変更可能ですがデフォルトをお勧めします

  2. 1 ノード目の sora.conf の設定を cluster 対応にする

    • node_name = sora1@192.0.2.101

      • @ 以下の IP アドレスまたはドメイン名は、可能な限りプライベートネットワークを指定してください

    • cluster = true

    • external_signaling_url = wss://sora-node1.example.com/signlaing

    • external_api_url = https://sora-node1.example.com/api

    • contact_node_name_list = sora1@192.0.2.101, sora2@192.168.0.102, sora3@192.168.0.103

  3. Sora を起動する

  4. http POST 192.0.2.101:3000/ x-sora-target:Sora_20211215.ListClusterNodes を実行する

  5. 1 台のノードリストが取得できれば、ここまでの手順は OK

  6. 2 ノード目の sora.conf の設定を cluster 対応にする

    • node_name = sora2@192.168.0.102

      • @ 以下の IP アドレスまたはドメイン名は、可能な限りプライベートネットワークを指定してください

    • cluster = true

    • external_signaling_url = wss://sora-node2.example.com/signlaing

    • external_api_url = https://sora-node2.example.com/api

    • contact_node_name_list = sora1@192.0.2.101, sora2@192.168.0.102, sora3@192.168.0.103

  7. Sora を起動する

  8. http POST 192.0.2.101:3000/ x-sora-target:Sora_20211215.ListClusterNodes を実行する

  9. 2 台のノードリストが取得できれば、、ここまでの手順は OK

  10. 3 ノード目の sora.conf の設定を cluster 対応にする

    • node_name = sora3@192.168.0.103

      • @ 以下の IP アドレスまたはドメイン名は、可能な限りプライベートネットワークを指定してください

    • cluster = true

    • external_signaling_url = wss://sora-node3.example.com/signlaing

    • external_api_url = https://sora-node3.example.com/api

    • contact_node_name_list = sora1@192.0.2.101, sora2@192.168.0.102, sora3@192.168.0.103

  11. Sora を起動する

  12. http POST 192.0.2.101:3000/ x-sora-target:Sora_20211215.ListClusterNodes を実行する

  13. 3 台のノードリストが取得できれば、クラスターの構築は完了

クラスター運用

ノード数

Sora は 2 ノードからクラスターを構築できますが、 2 ノードの場合は可用性が 1 ノードの場合と同じになるため、 3 ノード以上でのクラスター構築をお勧めしています。

重要

2022 年 12 月リリースの Sora からは 2 ノードでのクラスター構築には非対応となり、3 ノード以上が必須となる予定です。

クラスターからの一時的な離脱

モード切り替え API を利用し、 新規コネクションブロックモード または 新規セッションブロックモード に 切り替えます。 その後、すべての接続がいなくなったタイミングで Sora ノードを終了してください。

一時的に離脱したノードを含めるクラスターノード一覧

ListClusterNodes API では現在クラスターに参加しているノード一覧が返りますが、 include_all_known_nodestrue に指定し API を実行するとで、そのクラスターが一時的に離脱したノードを含めて知っているノード一覧を返します。

クラスターからノード情報の消去

重要

この作業は必ず行うようにしてください。

特定のクラスターノードが障害が起きた後、復旧が難しい場合は PurgeClusterNode API を利用して、 クラスター参加しているノードから、障害が起きたノード情報を消去してください。

また、スケールインのためにノードを破棄する場合も同様に PurgeClusterNode API を利用して破棄したノードの情報を消去してください。

この作業はクラスターの新鮮さを保つために必要な作業となります。 この作業を行わないと存在していないノードが残り続けることで過半数かどうかの判断を誤る場合があります。

クラスターのアップデート

注釈

ローリングアップデートを推奨しています

  1. アップデート対象の Sora ノードを ChangeMode API で 新規コネクションブロックモード または 新規セッションブロックモード に切り替えます

  2. すべての接続がなくなったら Sora を停止させます

  3. 新しいバージョンの Sora へ入れ替えます

  4. 新しいバージョンの Sora を起動します

  5. ListClusterNodes API で新しいバージョンの Sora がクラスターに参加できているかを確認します

これを 1 ノードごとに繰り返してください。

シーケンス図

type: redirect

blockdiag クライアント Sora1 Sora2 アプリケーションサ ーバー sora2 のシグナリング URL を返す "type": "connect" "type": "redirect" "type": "connect" 認証ウェブフック 200 OK {"allowed": true} "type": "offer" "type": "answer" "type": "candidate" イベントウェブフック "type": "connection.creat ed" 200 OK WebRTC 確立
© Copyright 2022, Shiguredo Inc Created using Sphinx 5.0.2