Laravel Reverb 101

https://reverb.laravel.com/

https://github.com/laravel/reverb

# 導入

[Laravel Reverb](https://github.com/laravel/reverb) は、超高速でスケーラブルなリアルタイム WebSocket 通信を Laravel アプリケーションに直接提供し、Laravel の既存の[イベント ブロードキャスト ツール](https://laravel.com/docs/11.x/broadcasting)スイートとのシームレスな統合を提供します。

# インストール

`install:broadcasting`Artisan コマンドを使用して Reverb をインストールできます。

```bash
php artisan install:broadcasting
```

# 構成

バックグラウンドで`install:broadcasting`Artisan コマンドが`reverb:install`コマンドを実行し、適切なデフォルト設定オプションのセットを使用して Reverb をインストールします。設定を変更したい場合は、Reverb の環境変数を更新するか、`config/reverb.php`設定ファイルを更新することで変更できます。

## アプリケーションの資格情報

Reverb への接続を確立するには、クライアントとサーバーの間で Reverb の「アプリケーション」資格情報のセットを交換する必要があります。これらの資格情報はサーバー上で構成され、クライアントからの要求を検証するために使用されます。これらの資格情報は、次の環境変数を使用して定義できます。

```php
REVERB_APP_ID=my-app-id
REVERB_APP_KEY=my-app-key
REVERB_APP_SECRET=my-app-secret
```

## 許可されたオリジン

`config/reverb.php`構成ファイルの`app`セクション内の`allowed_origins`構成値の値を更新することで、クライアント要求の発信元を定義することもできます。許可されたオリジンにリストされていないオリジンからのリクエストは拒否されます。次を使用してすべてのオリジンを許可できます。*

```php
'apps' => [
    [
        'id' => 'my-app-id',
        'allowed_origins' => ['laravel.com'],
        // ...
    ]
]
```

## 追加のアプリケーション

通常、Reverb は、インストールされているアプリケーションに WebSocket サーバーを提供します。ただし、単一の Reverb インストールを使用して複数のアプリケーションを提供することは可能です。

たとえば、Reverb を介して複数のアプリケーションに WebSocket 接続を提供する単一の Laravel アプリケーションを維持したい場合があります。これは、アプリケーションの`config/reverb.php`構成ファイルで複数`apps`を定義することで実現できます。

```php
'apps' => [
    [
        'id' => 'my-app-one',
        // ...
    ],
    [
        'id' => 'my-app-two',
        // ...
    ],
],
```

## SSL

ほとんどの場合、安全な WebSocket 接続は、リクエストが Reverb サーバーにプロキシされる前に、上流の Web サーバー (Nginx など) によって処理されます。

ただし、ローカル開発中など、Reverb サーバーが安全な接続を直接処理すると便利な場合があります。[Laravel Herd](https://herd.laravel.com/) の安全なサイト機能を使用している場合、または[Laravel Valet](https://laravel.com/docs/11.x/valet)を使用していてアプリケーションに対して[secure コマンド](https://laravel.com/docs/11.x/valet#securing-sites)を実行している場合は、サイト用に生成された Herd / Valet 証明書を使用して Reverb 接続を保護できます。これを行うには、REVERB_HOST環境変数をサイトのホスト名に設定するか、Reverb サーバーの起動時にホスト名オプションを明示的に渡します。

```bash
php artisan reverb:start --host="0.0.0.0" --port=8080 --hostname="laravel.test"
```

Herd ドメインと Valet ドメインは `localhost`に解決されるため、上記のコマンドを実行すると、`wss://laravel.test:8080`で安全な WebSocket プロトコル ( `wss`)を介して Reverb サーバーにアクセスできるようになります。

アプリケーションの`config/reverb.php`構成ファイルで`tls`オプションを定義して、証明書を手動で選択することもできます。`tls`オプションの配列内で、 PHP の [SSL コンテキストオプション](https://www.php.net/manual/en/context.ssl.php)でサポートされているオプションのいずれかを指定できます。

```php
'options' => [
    'tls' => [
        'local_cert' => '/path/to/cert.pem'
    ],
],
```

# サーバーの実行

Reverb サーバーは`reverb:start`Artisan コマンドを使用して起動できます。

```bash
php artisan reverb:start
```
デフォルトでは、リバーブ サーバーは `0.0.0.0:8080`に起動され、すべてのネットワーク インターフェイスからアクセスできるようになります。

カスタム ホストまたはポートを指定する必要がある場合は、サーバーの起動時に`--host`および`--port`オプションを使用して指定できます。

```bash
php artisan reverb:start --host=127.0.0.1 --port=9000
```

あるいは、アプリケーションの`.env`構成ファイルで環境変数を`REVERB_SERVER_HOST`と`REVERB_SERVER_PORT`定義することもできます。

## デバッグ

パフォーマンスを向上させるために、Reverb はデフォルトではデバッグ情報を出力しません。Reverb サーバーを通過するデータのストリームを確認したい場合は、`reverb:start`コマンドに`--debug`オプションを指定できます。


```bash
php artisan reverb:start --debug
```

## 再起動中

Reverb は長時間実行されるプロセスであるため、`reverb:restart`Artisan コマンドでサーバーを再起動しない限り、コードへの変更は反映されません。

この`reverb:restart`コマンドは、サーバーを停止する前にすべての接続が正常に終了することを保証します。Supervisor などのプロセス マネージャーを使用して Reverb を実行している場合、すべての接続が終了した後、サーバーはプロセス マネージャーによって自動的に再起動されます。

```bash
php artisan reverb:restart
```

# 本番環境でリバーブを実行する

WebSocket サーバーは長時間実行される性質があるため、Reverb サーバーがサーバー上で利用可能なリソースに対して最適な接続数を効果的に処理できるように、サーバーとホスティング環境を最適化する必要がある場合があります。

:::note info
サイトが[Laravel Forge](https://forge.laravel.com/)によって管理されている場合は、「アプリケーション」パネルから直接 Reverb 用にサーバーを自動的に最適化できます。Reverb 統合を有効にすることで、Forge は、必要な拡張機能のインストールや許可される接続数の増加など、サーバーを運用準備が整った状態にします。
:::

## ファイルを開く

各 WebSocket 接続は、クライアントまたはサーバーのいずれかが切断されるまでメモリ内に保持されます。Unix および Unix 類似の環境では、各接続はファイルによって表されます。ただし、多くの場合、オペレーティング システム レベルとアプリケーション レベルの両方で、開くことを許可されるファイルの数に制限があります。

### オペレーティング·システム

Unix ベースのオペレーティング システムでは、次の`ulimit`コマンドを使用して、オープンできるファイルの数を決定できます。

```bash
ulimit -n
```

このコマンドは、さまざまなユーザーに許可されているオープン ファイルの制限を表示します。`/etc/security/limits.conf`ファイルを編集することで、これらの値を更新できます。たとえば、`forge`ユーザーが開いているファイルの最大数を 10,000 に更新すると、次のようになります。

```bash
# /etc/security/limits.conf
forge        soft  nofile  10000
forge        hard  nofile  10000
```

## イベントループ

内部では、Reverb は ReactPHP イベント ループを使用してサーバー上の WebSocket 接続を管理します。デフォルトでは、このイベント ループは `stream_select`によって強化されており、追加の拡張機能は必要ありません。ただし、通常`stream_select`は開いているファイルの数が 1,024 に制限されます。そのため、1,000 を超える同時接続を処理する予定がある場合は、同じ制限に束縛されない代替イベント ループを使用する必要があります。

リバーブは、利用可能な場合、 、`ext-event`, `ext-ev`, `ext-uv`、またはパワードループに自動的に切り替わります。これらの PHP 拡張機能はすべて、PECL 経由でインストールできます。

```bash
pecl install event
# or
pecl install ev
# or
pecl install uv
```

## ウェブサーバー

ほとんどの場合、Reverb はサーバー上の Web に接続されていないポートで実行されます。したがって、トラフィックを Reverb にルーティングするには、リバース プロキシを構成する必要があります。Reverb がホスト`0.0.0.0`とポート`8080`で実行されており、サーバーが Nginx Web サーバーを利用していると仮定すると、次の Nginx サイト構成を使用して Reverb サーバーにリバース プロキシを定義できます。


```nginx
server {
    ...
 
    location / {
        proxy_http_version 1.1;
        proxy_set_header Host $http_host;
        proxy_set_header Scheme $scheme;
        proxy_set_header SERVER_PORT $server_port;
        proxy_set_header REMOTE_ADDR $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";
 
        proxy_pass http://0.0.0.0:8080;
    }
 
    ...
}
```

通常、Web サーバーは、サーバーの過負荷を防ぐために、許可される接続の数を制限するように構成されています。Nginx Web サーバーで許可される接続数を 10,000 に増やすには、`nginx.conf`ファイルの`worker_rlimit_nofile`と`worker_connections` の値を更新する必要があります。

```nginx
user forge;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;
worker_rlimit_nofile 10000;
 
events {
  worker_connections 10000;
  multi_accept on;
}
```

上記の構成では、プロセスごとに最大 10,000 個の Nginx ワーカーを生成できます。さらに、この構成では、Nginx のオープン ファイル制限が 10,000 に設定されます。

## ポート

Unix ベースのオペレーティング システムでは、通常、サーバー上で開くことができるポートの数が制限されています。次のコマンドを使用して、現在の許可範囲を確認できます。

```bash
cat /proc/sys/net/ipv4/ip_local_port_range
# 32768    60999
```

上記の出力は、各接続に空きポートが必要なため、サーバーが最大 28,231 (60,999 ～ 32,768) の接続を処理できることを示しています。許可される接続数を増やすには[水平スケーリング](https://laravel.com/docs/11.x/reverb#scaling)をお勧めしますが、サーバーの`/etc/sysctl.conf`構成ファイルで許可されるポート範囲を更新することで、使用可能なオープン ポートの数を増やすこともできます。

## プロセス管理

ほとんどの場合、Reverb サーバーが継続的に実行されるようにするには、Supervisor などのプロセス マネージャーを使用する必要があります。Supervisor を使用して Reverb を実行している場合は、サーバーの`supervisor.conf`ファイルの`minfds`設定を更新して、Reverb サーバーへの接続を処理するために必要なファイルを Supervisor が確実に開けるようにする必要があります。

```conf
[supervisord]
...
minfds=10000
```

## スケーリング

単一サーバーで許容されるより多くの接続を処理する必要がある場合は、Reverb サーバーを水平方向に拡張できます。Redis のパブリッシュ/サブスクライブ機能を利用して、Reverb は複数のサーバー間の接続を管理できます。アプリケーションの Reverb サーバーの 1 つでメッセージが受信されると、サーバーは Redis を使用して受信メッセージを他のすべてのサーバーにパブリッシュします。

水平スケーリングを有効にするには、アプリケーションの`.env`構成ファイルで`REVERB_SCALING_ENABLED`環境変数を`true`に設定する必要があります。


```php
REVERB_SCALING_ENABLED=true
```

次に、すべての Reverb サーバーが通信する専用の中央 Redis サーバーを用意する必要があります。Reverb は、[アプリケーションに設定されたデフォルトの Redis 接続](https://laravel.com/docs/11.x/redis#configuration)を使用して、すべての Reverb サーバーにメッセージをパブリッシュします。

Reverb のスケーリング オプションを有効にして Redis サーバーを構成したら、Redis サーバーと通信できる複数のサーバーで`reverb:start`コマンドを呼び出すだけで済みます。これらの Reverb サーバーは、受信リクエストをサーバー間で均等に分散するロード バランサーの背後に配置する必要があります。