Skip to content
全部文档

Laravel Reverb ​

简介 ​

Laravel Reverb 为 Laravel 应用带来极速、可扩展的实时 WebSocket 通信,并与 Laravel 现有的事件广播工具无缝集成。

安装 ​

可使用 install:broadcasting Artisan 命令安装 Reverb:

shell
php artisan install:broadcasting

配置 ​

幕后,install:broadcasting 会运行 reverb:install,以合理的默认配置安装 Reverb。若需调整,可修改 Reverb 的环境变量或 config/reverb.php 配置文件。

应用凭证 ​

要与 Reverb 建立连接,客户端与服务器之间需交换一组 Reverb「应用」凭证。凭证在服务器端配置,用于验证客户端请求。可通过以下环境变量定义:

ini
REVERB_APP_ID=my-app-id
REVERB_APP_KEY=my-app-key
REVERB_APP_SECRET=my-app-secret

允许的来源 ​

还可在 config/reverb.php 的 apps 中通过 allowed_origins 定义允许的客户端来源。未列出的来源请求将被拒绝。使用 * 可允许所有来源:

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

额外应用 ​

通常,Reverb 为安装它的应用提供 WebSocket 服务器。不过,单次安装也可为多个应用提供服务。

例如,你可能希望用一个 Laravel 应用,通过 Reverb 为多个应用提供 WebSocket。可在 config/reverb.php 中定义多个 apps:

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

SSL ​

多数情况下,安全 WebSocket 连接由上游 Web 服务器(Nginx 等)处理后再代理到 Reverb 服务器。

不过有时(例如本地开发)让 Reverb 服务器直接处理安全连接也很有用。若你使用 Laravel Herd 的安全站点功能,或使用 Laravel Valet 并对应用运行了 secure 命令,可使用为站点生成的 Herd / Valet 证书来保护 Reverb 连接。为此,将 REVERB_HOST 环境变量设为站点主机名,或在启动 Reverb 服务器时显式传入 hostname 选项:

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

由于 Herd 与 Valet 域名解析到 localhost,上述命令会使 Reverb 可通过安全 WebSocket(wss)在 wss://laravel.test:8080 访问。

也可在应用的 config/reverb.php 配置文件中定义 tls 选项以手动选择证书。在 tls 选项数组中,可提供 PHP SSL 上下文选项 支持的任意选项:

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

运行服务器 ​

可使用 reverb:start Artisan 命令启动 Reverb 服务器:

shell
php artisan reverb:start

默认启动在 0.0.0.0:8080,可从所有网络接口访问。

若需自定义主机或端口,启动时可使用 --host 与 --port:

shell
php artisan reverb:start --host=127.0.0.1 --port=9000

也可在应用的 .env 中定义 REVERB_SERVER_HOST 与 REVERB_SERVER_PORT。

请勿将 REVERB_SERVER_HOST / REVERB_SERVER_PORT 与 REVERB_HOST / REVERB_PORT 混淆。前者指定 Reverb 服务器自身监听的主机与端口,后者告诉 Laravel 向何处发送广播消息。例如在生产环境中,可将公网主机名的 443 端口流量路由到运行在 0.0.0.0:8080 的 Reverb。此时环境变量可如下:

ini
REVERB_SERVER_HOST=0.0.0.0
REVERB_SERVER_PORT=8080

REVERB_HOST=ws.laravel.com
REVERB_PORT=443

调试 ​

为提升性能,Reverb 默认不输出调试信息。若要查看经过服务器的数据流,可向 reverb:start 传入 --debug:

shell
php artisan reverb:start --debug

重启 ​

由于 Reverb 是长时运行进程,代码变更需通过 reverb:restart 重启服务器后才会生效。

reverb:restart 会在停止服务器前优雅终止所有连接。若用 Supervisor 等进程管理器运行 Reverb,连接全部结束后会由进程管理器自动重启:

shell
php artisan reverb:restart

监控 ​

可通过与 Laravel Pulse 的集成监控 Reverb。启用 Reverb 的 Pulse 集成后,可跟踪服务器处理的连接数与消息数。

要启用集成,请先确保已安装 Pulse。然后将任意 Reverb recorder 添加到应用的 config/pulse.php 配置文件:

php
use Laravel\Reverb\Pulse\Recorders\ReverbConnections;
use Laravel\Reverb\Pulse\Recorders\ReverbMessages;

'recorders' => [
    ReverbConnections::class => [
        'sample_rate' => 1,
    ],

    ReverbMessages::class => [
        'sample_rate' => 1,
    ],

    // ...
],

接下来,将各 recorder 的 Pulse 卡片添加到你的 Pulse 仪表盘:

blade
<x-pulse>
    <livewire:reverb.connections cols="full" />
    <livewire:reverb.messages cols="full" />
    ...
</x-pulse>

连接活动通过定期轮询新更新来记录。为确保该信息在 Pulse 仪表盘上正确渲染,必须在 Reverb 服务器上运行 pulse:check 守护进程。若 Reverb 以水平扩展配置运行,应仅在其中一台服务器上运行该守护进程。

在生产环境运行 Reverb ​

由于 WebSocket 服务器长时运行,可能需要对服务器与托管环境做一些优化,以便在现有资源下有效处理尽可能多的连接。

INFO

Laravel Cloud 提供由 Laravel Reverb 集群驱动的全托管 WebSocket 基础设施,让你无需管理基础设施即可扩展并交付启用 Reverb 的应用。

打开文件数 ​

每个 WebSocket 连接会常驻内存,直到客户端或服务器断开。在 Unix 及类 Unix 环境中,每个连接对应一个文件。操作系统与应用层通常都有打开文件数上限。

操作系统 ​

在基于 Unix 的系统上,可用 ulimit 查看允许的打开文件数:

shell
ulimit -n

该命令会显示各用户的打开文件限制。可编辑 /etc/security/limits.conf 调整。例如将 forge 用户上限设为 10,000:

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

事件循环 ​

底层上,Reverb 使用 ReactPHP 事件循环管理 WebSocket 连接。默认由 stream_select 驱动,无需额外扩展,但通常限制为 1,024 个打开文件。若计划处理超过 1,000 个并发连接,需使用不受相同限制的替代事件循环。

若可用,Reverb 会自动切换到 ext-uv 驱动的循环。该 PHP 扩展可通过 PECL 安装:

shell
pecl install uv

Web 服务器 ​

多数情况下,Reverb 运行在非对外暴露的端口上,因此需配置反向代理。假设 Reverb 在 0.0.0.0:8080,且使用 Nginx,可用如下站点配置:

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;
    }

    ...
}

WARNING

Reverb 在 /app 监听 WebSocket 连接,并在 /apps 处理 API 请求。请确保处理 Reverb 请求的 Web 服务器能提供这两个 URI。若使用 Laravel Forge 管理服务器,Reverb 服务器默认会正确配置。

Web 服务器通常会限制连接数以防过载。若要将 Nginx 允许连接数提高到 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 worker,并将 Nginx 打开文件上限设为 10,000。

端口 ​

基于 Unix 的系统通常限制可打开的端口数量。可用以下命令查看当前允许范围:

shell
cat /proc/sys/net/ipv4/ip_local_port_range
# 32768	60999

上述输出表明服务器最多可处理 28,231(60,999 - 32,768)个连接,因为每个连接需要一个空闲端口。虽然我们建议通过水平扩展增加允许的连接数,但你也可以通过更新服务器 /etc/sysctl.conf 中的允许端口范围来增加可用打开端口数。

进程管理 ​

多数情况下应使用 Supervisor 等进程管理器确保 Reverb 持续运行。若用 Supervisor,请更新服务器 supervisor.conf 中的 minfds,以便能打开处理连接所需的文件:

ini
[supervisord]
...
minfds=10000

扩展 ​

若单台服务器无法承载所需连接数,可水平扩展 Reverb。借助 Redis 的发布/订阅能力,Reverb 可跨多台服务器管理连接。某台 Reverb 收到消息后,会通过 Redis 发布给其他所有服务器。

启用水平扩展时,在 .env 中将 REVERB_SCALING_ENABLED 设为 true:

ini
REVERB_SCALING_ENABLED=true

接下来,应有一台专用的中央 Redis 服务器,供所有 Reverb 服务器通信。Reverb 将使用为应用配置的默认 Redis 连接向所有 Reverb 服务器发布消息。

启用扩展并配置 Redis 后,在能与 Redis 通信的多台服务器上运行 reverb:start 即可。这些服务器应放在负载均衡器后,以均匀分发请求。

事件 ​

Reverb 在连接与消息处理的生命周期中会派发内部事件。你可以监听这些事件,在连接被管理或消息交换时执行操作。

Reverb 会派发以下事件:

Laravel\Reverb\Events\ChannelCreated ​

在频道创建时派发,通常发生在第一个连接订阅某频道时。事件会收到 Laravel\Reverb\Protocols\Pusher\Channel 实例。

Laravel\Reverb\Events\ChannelRemoved ​

在频道移除时派发,通常发生在最后一个连接取消订阅时。事件会收到 Laravel\Reverb\Protocols\Pusher\Channel 实例。

Laravel\Reverb\Events\ConnectionPruned ​

服务器清理过期连接时派发。事件会收到 Laravel\Reverb\Contracts\Connection 实例。

Laravel\Reverb\Events\MessageReceived ​

从客户端连接收到消息时派发。事件会收到 Laravel\Reverb\Contracts\Connection 实例与原始字符串 $message。

Laravel\Reverb\Events\MessageSent ​

向客户端连接发送消息时派发。事件会收到 Laravel\Reverb\Contracts\Connection 实例与原始字符串 $message。