execve_hook/COMPRESSION.md

142 lines
3.5 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 协议压缩支持
## 概述
协议栈支持可选的 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 端
```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 端
```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 端
```bash
# 安装 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% |
## 调试
启用调试模式可以看到压缩详情:
```bash
# C 端
make DEBUG=1
# 运行后会输出类似:
# [DEBUG] 压缩成功: 1024 -> 412 (40.2%)
# [DEBUG] 解压成功: 412 -> 1024 字节
```