execve_hook/COMPRESSION.md

3.5 KiB
Raw Permalink Blame History

协议压缩支持

概述

协议栈支持可选的 LZ4 压缩,可以显著减少网络带宽消耗,特别适用于终端输出等重复性较高的数据。

压缩算法选择

我们选择 LZ4 作为压缩算法,原因如下:

特性 LZ4 zlib zstd
压缩速度 ~500 MB/s ~50 MB/s ~300 MB/s
解压速度 ~1500 MB/s ~250 MB/s ~800 MB/s
压缩比 2:1 ~ 3:1 3:1 ~ 5:1 3:1 ~ 5:1
延迟影响 极低 中等

对于终端数据流LZ4 的极低延迟和高速度是最佳选择。

消息头格式

+--------+--------+------------+------------+
| Magic  |  Type  | PayloadLen |  Reserved  |
| 4字节  | 4字节  |   4字节    |   4字节    |
+--------+--------+------------+------------+

Reserved 字段用法:

  • 低 16 位:压缩标志
    • bit 0: MSG_FLAG_COMPRESSED (0x01) - 载荷已压缩
    • bit 1: MSG_FLAG_COMPRESS_LZ4 (0x02) - 使用 LZ4 压缩
    • bit 2: MSG_FLAG_COMPRESS_HC (0x04) - 使用高压缩比模式
  • 高 16 位:原始大小 / 256用于解压缓冲区分配

使用方法

C 端

#include "socket_protocol.h"
#include "compression.h"

// 初始化协议上下文(启用 LZ4 压缩)
ProtocolContext ctx;
protocol_init(&ctx, COMPRESS_LZ4, 0);  // 0 = 默认级别

// 发送压缩消息
write_message_compressed(sock, &ctx, MSG_TYPE_TERMINAL_OUTPUT, data, data_len);

// 接收并解压消息
MessageType type;
void* payload;
uint32_t payload_len, original_len;
read_message_decompressed(sock, &type, &payload, &payload_len, &original_len);

// 获取压缩统计
uint64_t in, out, count, skip;
compression_get_stats(&ctx.compress_ctx, &in, &out, &count, &skip);
printf("压缩比: %d%%\n", compression_get_ratio(&ctx.compress_ctx));

Go 端

import "go_service/internal/socket"

// 创建带压缩的连接
conn := socket.NewConnectionWithCompression(netConn, socket.CompressLZ4, 0)

// 或者在现有连接上启用压缩
conn.EnableCompression(socket.CompressLZ4, 0)

// 发送压缩消息
ctx := socket.NewCompressionContext(socket.CompressLZ4, 0)
socket.WriteMessageCompressed(netConn, ctx, socket.MsgTypeServerResponse, data)

// 接收并自动解压
msgType, payload, err := socket.ReadMessageWithDecompression(netConn)

// 获取统计信息
bytesIn, bytesOut, compCount, skipCount, ratio := conn.GetCompressionStats()
fmt.Printf("压缩比: %d%%\n", ratio)

编译配置

C 端

# 安装 LZ4 库
make install-lz4

# 编译(自动检测 LZ4
make

# 禁用压缩
make LZ4=0

# 查看是否启用了压缩
make pre_build

Go 端

LZ4 库会自动通过 go mod tidy 安装。

压缩阈值

  • 小于 64 字节的数据不会被压缩(开销大于收益)
  • 如果压缩后数据更大,会自动回退到原始数据

兼容性

  • 新版本可以读取旧版本(无压缩)的消息
  • 旧版本可以读取新版本的未压缩消息
  • 旧版本无法读取压缩消息(会因为 reserved 字段不为 0 而有不同行为,但基本功能仍可工作)

性能预期

典型终端场景压缩效果:

数据类型 原始大小 压缩后 节省
ls 输出 1000 B 400 B 60%
代码文件 10 KB 3.5 KB 65%
日志输出 5 KB 1.2 KB 76%
二进制数据 1 KB 900 B 10%

调试

启用调试模式可以看到压缩详情:

# C 端
make DEBUG=1

# 运行后会输出类似:
# [DEBUG] 压缩成功: 1024 -> 412 (40.2%)
# [DEBUG] 解压成功: 412 -> 1024 字节