Laravel Reverb
简介
Laravel Reverb 为你的 Laravel 应用带来极速且可扩展的实时 WebSocket 通信,并与 Laravel 现有的事件广播工具套件实现无缝集成。
安装
你可以使用 install:broadcasting Artisan 命令安装 Reverb
1php artisan install:broadcasting
配置
在底层,install:broadcasting Artisan 命令会运行 reverb:install 命令,该命令将使用一套合理的默认配置选项安装 Reverb。如果你需要更改配置,可以通过更新 Reverb 的环境变量或修改 config/reverb.php 配置文件来完成。
应用凭据
为了建立到 Reverb 的连接,客户端和服务器之间必须交换一组 Reverb “应用”凭据。这些凭据在服务器端配置,并用于验证客户端的请求。你可以通过以下环境变量来定义这些凭据
1REVERB_APP_ID=my-app-id2REVERB_APP_KEY=my-app-key3REVERB_APP_SECRET=my-app-secret
允许的来源 (Allowed Origins)
你还可以通过更新 config/reverb.php 配置文件中 apps 部分的 allowed_origins 配置项,来定义允许客户端请求的来源。任何不在允许来源列表中的请求都将被拒绝。你可以使用 * 来允许所有来源。
1'apps' => [2 [3 'app_id' => 'my-app-id',4 'allowed_origins' => ['laravel.com'],5 // ...6 ]7]
额外应用
通常,Reverb 为安装它的应用提供 WebSocket 服务器。不过,也可以通过单个 Reverb 安装服务于多个应用。
例如,你可能希望维护一个单一的 Laravel 应用,并通过 Reverb 为多个应用提供 WebSocket 连接。这可以通过在应用的 config/reverb.php 配置文件中定义多个 apps 来实现。
1'apps' => [ 2 [ 3 'app_id' => 'my-app-one', 4 // ... 5 ], 6 [ 7 'app_id' => 'my-app-two', 8 // ... 9 ],10],
SSL
在大多数情况下,安全 WebSocket 连接由上游 Web 服务器(如 Nginx 等)处理,然后再将请求代理到你的 Reverb 服务器。
然而,在某些场景下(例如本地开发期间),让 Reverb 服务器直接处理安全连接会很有用。如果你正在使用 Laravel Herd 的安全站点功能,或者你正在使用 Laravel Valet 并针对你的应用运行了 secure 命令,你可以使用为你的站点生成的 Herd / Valet 证书来保护你的 Reverb 连接。要实现这一点,请将 REVERB_HOST 环境变量设置为你的站点主机名,或者在启动 Reverb 服务器时显式传递主机名选项。
1php 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 上下文选项。
1'options' => [2 'tls' => [3 'local_cert' => '/path/to/cert.pem'4 ],5],
运行服务器
Reverb 服务器可以使用 reverb:start Artisan 命令启动
1php artisan reverb:start
默认情况下,Reverb 服务器将在 0.0.0.0:8080 启动,使其可以从所有网络接口访问。
如果你需要指定自定义主机或端口,可以在启动服务器时通过 --host 和 --port 选项进行设置
1php 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 发送广播消息的位置。例如,在生产环境中,你可以将公共 Reverb 主机名端口 443 的请求路由到运行在 0.0.0.0:8080 的 Reverb 服务器。在这种情况下,你的环境变量配置如下:
1REVERB_SERVER_HOST=0.0.0.02REVERB_SERVER_PORT=80803 4REVERB_HOST=ws.laravel.com5REVERB_PORT=443
调试
为了提高性能,Reverb 默认不输出任何调试信息。如果你想查看流经 Reverb 服务器的数据,可以在 reverb:start 命令中提供 --debug 选项。
1php artisan reverb:start --debug
重启
由于 Reverb 是一个长驻进程,代码的变更在没有通过 reverb:restart Artisan 命令重启服务器的情况下不会生效。
reverb:restart 命令确保所有连接在停止服务器前被优雅地终止。如果你使用 Supervisor 等进程管理器运行 Reverb,服务器将在所有连接终止后被进程管理器自动重启。
1php artisan reverb:restart
监控
Reverb 可以通过与 Laravel Pulse 的集成进行监控。启用 Reverb 的 Pulse 集成后,你可以追踪服务器处理的连接数和消息数。
要启用该集成,首先确保你已经安装了 Pulse。然后,将 Reverb 的记录器添加到应用的 config/pulse.php 配置文件中。
1use Laravel\Reverb\Pulse\Recorders\ReverbConnections; 2use Laravel\Reverb\Pulse\Recorders\ReverbMessages; 3 4'recorders' => [ 5 ReverbConnections::class => [ 6 'sample_rate' => 1, 7 ], 8 9 ReverbMessages::class => [10 'sample_rate' => 1,11 ],12 13 // ...14],
接下来,将每个记录器的 Pulse 卡片添加到你的 Pulse 仪表盘中。
1<x-pulse>2 <livewire:reverb.connections cols="full" />3 <livewire:reverb.messages cols="full" />4 ...5</x-pulse>
连接活动是通过定期轮询新更新来记录的。为了确保这些信息能正确渲染在 Pulse 仪表盘上,你必须在 Reverb 服务器上运行 pulse:check 守护进程。如果你是在横向扩展配置下运行 Reverb,则只需在其中一台服务器上运行该守护进程。
在生产环境中运行 Reverb
由于 WebSocket 服务器的长驻特性,你可能需要对服务器和托管环境进行一些优化,以确保 Reverb 服务器能够根据服务器可用的资源有效地处理最佳数量的连接。
Laravel Cloud 提供由 Laravel Reverb 集群驱动的全托管 WebSocket 基础设施,让你无需管理基础设施即可扩展并交付启用了 Reverb 的应用。
打开的文件
每个 WebSocket 连接都保存在内存中,直到客户端或服务器断开连接。在 Unix 和类 Unix 环境中,每个连接都由一个文件表示。然而,操作系统和应用层通常对允许打开的文件数有限制。
操作系统
在基于 Unix 的操作系统上,你可以使用 ulimit 命令确定允许打开的文件数。
1ulimit -n
该命令将显示不同用户允许的打开文件限制。你可以通过编辑 /etc/security/limits.conf 文件来更新这些值。例如,将 forge 用户的最大打开文件数更新为 10,000,如下所示:
1# /etc/security/limits.conf2forge soft nofile 100003forge hard nofile 10000
事件循环
在底层,Reverb 使用 ReactPHP 事件循环来管理服务器上的 WebSocket 连接。默认情况下,此事件循环由 stream_select 驱动,不需要任何额外的扩展。然而,stream_select 通常限制为 1,024 个打开文件。因此,如果你计划处理超过 1,000 个并发连接,则需要使用不受相同限制约束的替代事件循环。
当可用时,Reverb 会自动切换到由 ext-uv 驱动的循环。此 PHP 扩展可通过 PECL 安装。
1pecl install uv
Web 服务器
在大多数情况下,Reverb 运行在服务器的非 Web 对外端口上。因此,为了将流量路由到 Reverb,你应该配置一个反向代理。假设 Reverb 运行在主机 0.0.0.0 和端口 8080,且你的服务器使用 Nginx Web 服务器,你可以使用以下 Nginx 站点配置为 Reverb 服务器定义反向代理:
1server { 2 ... 3 4 location / { 5 proxy_http_version 1.1; 6 proxy_set_header Host $http_host; 7 proxy_set_header Scheme $scheme; 8 proxy_set_header SERVER_PORT $server_port; 9 proxy_set_header REMOTE_ADDR $remote_addr;10 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;11 proxy_set_header Upgrade $http_upgrade;12 proxy_set_header Connection "Upgrade";13 14 proxy_pass http://0.0.0.0:8080;15 }16 17 ...18}
Reverb 在 /app 处监听 WebSocket 连接,并在 /apps 处处理 API 请求。你应该确保处理 Reverb 请求的 Web 服务器可以同时服务这两个 URI。如果你使用 Laravel Forge 管理服务器,你的 Reverb 服务器默认会被正确配置。
通常,Web 服务器会被配置为限制允许的连接数,以防止服务器过载。要将 Nginx Web 服务器上允许的连接数增加到 10,000,应更新 nginx.conf 文件的 worker_rlimit_nofile 和 worker_connections 值。
1user forge; 2worker_processes auto; 3pid /run/nginx.pid; 4include /etc/nginx/modules-enabled/*.conf; 5worker_rlimit_nofile 10000; 6 7events { 8 worker_connections 10000; 9 multi_accept on;10}
上述配置将允许每个进程生成多达 10,000 个 Nginx 工作进程。此外,此配置将 Nginx 的打开文件限制设置为 10,000。
端口
基于 Unix 的操作系统通常限制服务器上可以打开的端口数量。你可以通过以下命令查看当前允许的范围:
1cat /proc/sys/net/ipv4/ip_local_port_range2# 32768 60999
上面的输出显示服务器最多可以处理 28,231 (60,999 - 32,768) 个连接,因为每个连接都需要一个空闲端口。尽管我们建议使用横向扩展来增加允许的连接数,但你也可以通过更新服务器 /etc/sysctl.conf 配置文件中允许的端口范围来增加可用端口数量。
进程管理
在大多数情况下,你应该使用 Supervisor 等进程管理器来确保 Reverb 服务器持续运行。如果你使用 Supervisor 运行 Reverb,你应该更新服务器 supervisor.conf 文件中的 minfds 设置,以确保 Supervisor 能够打开处理连接到 Reverb 服务器所需的文件。
1[supervisord]2...3minfds=10000
横向扩展
如果你需要处理比单台服务器所允许的更多的连接,可以横向扩展 Reverb 服务器。利用 Redis 的发布/订阅功能,Reverb 能够跨多台服务器管理连接。当其中一台应用 Reverb 服务器收到消息时,它将使用 Redis 将传入的消息发布给所有其他服务器。
要启用横向扩展,应在应用的 .env 配置文件中将 REVERB_SCALING_ENABLED 环境变量设置为 true。
1REVERB_SCALING_ENABLED=true
接下来,你需要一个专用的中央 Redis 服务器,所有 Reverb 服务器都将与之通信。Reverb 将使用为你的应用配置的默认 Redis 连接来向所有 Reverb 服务器发布消息。
一旦启用了 Reverb 的扩展选项并配置了 Redis 服务器,你只需在多台能够与 Redis 服务器通信的服务器上调用 reverb:start 命令。这些 Reverb 服务器应放置在负载均衡器后面,将传入的请求均匀地分发到各个服务器。
活动
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。