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.phpapps 中通过 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_HOSTREVERB_SERVER_PORT

请勿将 REVERB_SERVER_HOST / REVERB_SERVER_PORTREVERB_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_nofileworker_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