提升 Laravel Reverb WebSocket 性能需五步缓存优化:一、缓存连接元数据;二、缓存频道策略;三、缓存广播消息序列化结果;四、缓存 Pub/Sub 映射表;五、缓存心跳响应内容。

如果您在使用 Laravel Reverb 提供 WebSocket 服务时遭遇连接延迟、消息积压或高并发下响应变慢,则很可能是由于重复计算、未缓存的连接元数据或低效的状态同步机制所致。以下是提升 WebSocket 性能的具体方法:
一、缓存客户端连接元数据
Reverb 默认每次处理消息时需动态解析客户端身份、权限及会话状态,若这些信息频繁从数据库加载,将显著拖慢广播与私有频道逻辑。通过缓存用户身份与连接上下文,可跳过重复查询。
1、在握手阶段(如自定义 AuthController 或 Reverb 的 auth callback 中),将用户 ID、角色、所属频道组等关键字段写入 Redis 缓存,键名格式为 reverb:conn:{connection_id}:meta,TTL 设为 30 分钟。
2、在消息广播前,使用 Cache::get('reverb:conn:'.$connectionId.':meta') 快速获取权限信息,避免调用 Auth::user() 或 DB 查询。
3、当用户权限变更时,主动执行 Cache::forget('reverb:conn:*:meta') 配合通配符清除(需 Redis 服务支持 SCAN 命令)或使用缓存标签标记所有连接元数据。
二、缓存频道存在性与订阅状态
Reverb 在处理 SUBSCRIBE/PING/UNSUBSCRIBE 请求时,默认每次均需校验频道是否启用、是否允许匿名访问等。对静态配置频道(如 public:notifications、private:chat.{id} 模板)进行缓存,可消除重复验证开销。
1、在 config/reverb.php 的 apps 配置中,为每个频道预定义标识符,例如 'channel_prefixes' => ['public:', 'private:chat.']。
2、启动时遍历 config/channels.php 或硬编码规则,将合法频道前缀与访问策略序列化后存入缓存,键名为 reverb:channel:policy,TTL 设为永不过期(null)或 24 小时。
3、在 Reverb 的 ChannelAuthorizer 中,优先读取该缓存项,仅当缓存未命中时才执行完整策略判断逻辑。
三、缓存广播消息模板与序列化结果
对于高频发送的结构化通知(如在线状态更新、系统公告),其 JSON 序列化结果固定且不依赖请求上下文。直接缓存已序列化的 payload 字节流,可绕过 PHP 数组→JSON 的 CPU 密集型操作。
1、定义广播事件类(如 UserOnlineUpdated),在 handle() 方法中生成标准化数组后,调用 json_encode() 并存入缓存,键名格式为 reverb:broadcast:template:{event_class}:{hash},其中 hash 由 payload 内容 md5 计算得出。
Laravel Cloud(cloud.laravel.com)。此技能用于处理所有 Laravel Cloud 请求,包括搜索和读取数据。只要任务涉及 Laravel Cloud,即使用此技能。
2、在 Reverb 的 broadcast() 调用链中(如 Publishing/RedisPubSubProvider::publish),优先尝试从缓存读取预序列化字符串,成功则直接 write() 到 Redis Pub/Sub 通道。
3、当模板内容变更时(如语言包更新、字段增减),自动触发缓存刷新,确保字节级一致性。
四、缓存 Redis Pub/Sub 订阅映射表
Reverb 启动时需扫描所有频道并建立 Redis Pub/Sub channel → Laravel 频道处理器的映射关系。该映射在运行期极少变动,但每次新连接加入频道时仍会重复构建,造成冗余开销。
1、在服务提供者(如 ReverbServiceProvider)boot() 阶段,将全部有效频道与对应处理器类名构建成关联数组。
2、对该数组执行 serialize() 后存入 Redis,键名为 reverb:pubsub:channel_map,设置永久 TTL(即不设过期时间)。
3、在 ConnectionHandler::subscribeToChannel() 中,直接反序列化该缓存值,跳过正则匹配与反射查找流程。
五、缓存连接心跳响应内容
Reverb 默认每 ping_interval 秒向客户端发送纯文本 PONG 或空帧。若启用了自定义心跳响应(如携带服务器负载、时间戳),每次生成均需调用 Carbon::now() 等函数,累积开销不可忽视。
1、将心跳响应体(如 {"pong":true,"ts":1744623180})作为固定字符串缓存,键名为 reverb:heartbeat:payload,TTL 设为 1 秒以保证时间戳轻微滞后可接受。
2、在 PingResponder 类中,直接返回 Cache::get('reverb:heartbeat:payload'),避免重复构造 JSON 对象。
3、使用 Laravel 的 cache:prune 命令定期清理过期心跳缓存,防止内存无序增长。










