WebSocket 压缩对于减少带宽消耗和提升响应速度至关重要,尤其是在传输 JSON 等重复性数据时。permessage-deflate 扩展会即时压缩每个 WebSocket 帧——但压缩速度直接影响应用程序的吞吐量。
从 sgcWebSockets 2026.4.0 起,permessage-deflate 的实现已经过全面重写,性能显著提升。在我们的基准测试中,小消息的压缩和解压速度最高提升 15 倍,所有负载大小均有明显改善。
改动了什么?
之前的实现会在每个 WebSocket 帧上初始化并销毁压缩引擎。这意味着即使是 1 KB 的小消息,也要承担设置压缩器、压缩数据、再销毁的全部开销——下一条消息又要重复整个过程。
新实现让压缩引擎在帧间保持存活。它在第一个帧到来时初始化一次,并在整个连接生命周期内复用。这消除了每帧的初始化开销,同时允许引擎从之前的消息中学习,对重复数据模式实现更快的压缩。
除了持久化压缩上下文外,新实现还包含若干其他优化:
- 预分配内存缓冲区——缓冲区分配一次后复用,避免每帧重复分配内存。
- 直接内存访问——当输入已在内存中时,引擎直接读取,无需先复制到中间缓冲区。
- 复用临时流——内部工作流在构造函数中创建一次,而非在每次压缩/解压调用时创建和销毁。
基准测试结果
我们对每种消息大小执行了 10,000 次压缩+解压往返测试。每次往返压缩一个 JSON 负载后再解压,并验证输出与原始内容一致。测试在 Windows 64 位机器上使用 Delphi 12 Athens 编译执行。
默认配置(持久化上下文)
这是默认模式,压缩上下文在帧间保持——也是最常见的实际场景:
| 消息大小 | 之前(毫秒) | 之后(毫秒) | 提速倍数 |
|---|---|---|---|
| 1 KB | 437 ms | 28 ms | 快 15.6 倍 |
| 4 KB | 480 ms | 88 ms | 快 5.5 倍 |
| 16 KB | 546 ms | 431 ms | 快 1.3 倍 |
| 64 KB | 1,994 ms | 1,725 ms | 快 1.2 倍 |
启用 NoContextTakeOver(独立帧)
当启用 NoContextTakeOver 时,每个帧独立压缩。即便在此模式下,缓冲区复用和直接内存访问优化仍带来显著提升:
| 消息大小 | 之前(毫秒) | 之后(毫秒) | 提速倍数 |
|---|---|---|---|
| 1 KB | 149 ms | 75 ms | 快 2.0 倍 |
| 4 KB | 173 ms | 100 ms | 快 1.7 倍 |
| 16 KB | 302 ms | 228 ms | 快 1.3 倍 |
| 64 KB | 1,216 ms | 1,094 ms | 快 1.1 倍 |
哪些场景受益最大?
对于频繁交换小消息的应用,改进效果最为显著——这正是 WebSocket 的典型使用场景:
|
聊天与即时通讯 短文本消息(通常低于 4 KB)的增益最大:压缩速度提升 5~15 倍。 |
实时数据推送 仪表盘、股票行情和 IoT 传感器的 JSON 更新,既受益于速度提升,又能利用持久化上下文对重复数据模式进行学习。 |
|
游戏与多人联机 频繁的小状态更新受益于较低的单帧开销。 |
高并发服务器 每帧 CPU 时间减少,服务器可处理更多并发连接。 |
完全兼容
此优化完全透明——您的应用无需任何代码修改。网络上传输的压缩数据与之前版本完全相同,因此升级后的服务器可与现有客户端无缝协作,反之亦然。
新实现支持所有平台和编译器:
- Delphi 7 至 Delphi 13(含 C++Builder)
- Windows、macOS、Linux、Android、iOS
- 32 位和 64 位目标平台
升级至 2026.4.0
permessage-deflate 优化已在 sgcWebSockets 2026.4.0 中提供。只需更新至最新版本,您的 WebSocket 连接将自动受益于更快的压缩。请前往 esegece.com 下载。
特别感谢 Michael 贡献了最初的优化实现,启发了这项工作。他对持久化 zlib 上下文和直接内存访问的研究为这些性能改进奠定了基础。
