RPC 契约
设计思想
Deepsight 在通信层的设计彻底摒弃了传统的 RESTful/JSON 模式,全面拥抱 gRPC + Protobuf。在解决高频采集带来带宽痛点的同时,通过强类型约束与延迟翻译机制,完美兼顾了物理资源的极限保护与大模型对数据的语义可达性。
数据压缩
在每秒数千次的内核事件上报中,任何冗余的字节都会引发带宽灾难,但大模型又必须依赖完整的纯文本字符串进行推理。系统采用了“网络层高压缩,表示层全透明”的分层解耦策略:
- 握手状态剥离:抛弃每次请求携带机器信息的做法,连接第一秒传输静态数据,后续高频流只认极短的
session_token。 - 双重压缩引擎:
- 时间 Delta 压缩:采用“批次基准时间 (Base) + 内部相对偏移 (Delta)”,利用 Protobuf Varint 将 8 字节时间戳压缩至 1~2 字节。
- 字符串字典化 (String Interning) 与延迟翻译:Probe 在边缘侧将高频重复的堆栈调用链、函数名映射为极小的
uint32整数 ID 进行网络传输,彻底消灭文本冗余;当二进制流抵达 Server 网关时,网关利用同步好的全量字典执行“延迟翻译”,将 ID 反向解析为完整的明文字符串,确保最终交付给大模型的 JSON 数据 100% 语义透明。
模块化
系统未来会从“网络排查”扩展到“存储 I/O”、“CPU 调度”等多个子系统。为了保证数据结构的严谨性,确保大模型始终能拿到结构化且可解释的载荷,系统全面采用 Protobuf 的 oneof 强类型联合体进行载荷分发,彻底屏蔽毫无语义的泛型黑盒。
契约映射
proto/
├── common/
│ └── common.proto # 基础类型 (TaskID, 全局枚举如 Severity)
├── modules/
│ ├── network.proto # 网络专属载荷: NetworkMetric, NetworkEvent
│ ├── storage.proto # 存储专属载荷: StorageMetric, StorageEvent
│ └── process.proto # 进程专属载荷: ProcessMetric, ProcessEvent
└── v1/
└── telemetry.proto # 核心网关入口: 负责总线通信,使用 oneof 联合各业务模块入口契约
网关服务入口
syntax = "proto3";
package deepsight.v1;
import "common/common.proto";
import "modules/network.proto";
import "modules/process.proto";
import "modules/storage.proto";
service DeepsightGateway {
// 阶段 0:握手认证 (获取 Token 与初始化字典)
rpc Register(RegisterRequest) returns (RegisterResponse);
// 阶段 1:数据面上行通道 (单向客户端流)
rpc PushTelemetry(stream TelemetryBatch) returns (TelemetryAck);
// 阶段 2:控制面指令通道 (双向流)
rpc TaskChannel(stream TaskChannelUpstream) returns (stream TaskChannelDownstream);
}状态一致性与会话管理
为了在网络闪断或进程重启时保持连接状态可解释,通信层引入了基于 Session 的隔离机制。当前 wire contract 已包含字典字段,但完整 dictionary compression / wire closure 仍是后续能力;Server 不能假设字典字段必然非空。
- Session 隔离:Server 接收到注册请求后,应颁发非空
session_token,并用该 token 关联后续TelemetryBatch。 - 字典字段边界:
pre_defined_dict和incremental_dict是总线预留字段;Bob 端必须允许它们为空。 - 持久化要求:未来若启用 dictionary compression,Server 必须先完成语义重组,再把事件或任务结果持久化为自包含明文对象。
message RegisterRequest {
string node_id = 1; // 机器唯一标识
string kernel_version = 2; // 宿主机内核版本
// 预留:Probe 启动时可同步的静态字符串字典。
// 当前 consumer 必须允许其为空;完整字典生命周期是后续能力。
map<uint32, string> pre_defined_dict = 3;
}
message RegisterResponse {
string session_token = 1; // 颁发令牌
}数据面高频推送
message TelemetryBatch {
string session_token = 1;
// Delta 压缩基准时间
uint64 base_timestamp_ns = 2;
// 常态指标集合
repeated MetricWrapper metrics = 3;
// 突发事件集合
repeated EventWrapper spontaneous_events = 4;
// 预留:运行中动态发现的新字符串增量字典。
// 当前 consumer 必须允许其为空。
map<uint32, string> incremental_dict = 5;
}
message MetricWrapper {
uint32 time_offset_ns = 1; // 相对基准的偏移量
// 强类型联合体:明确区分不同子系统的指标载荷
oneof payload {
modules.NetworkMetric network = 2;
modules.StorageMetric storage = 3;
modules.ProcessMetric process = 4;
}
}
message EventWrapper {
uint32 time_offset_ns = 1;
common.Severity level = 2;
// 发生边缘熔断时,附加的被截断的同质化事件数量
uint32 truncated_count = 3;
// 强类型联合体:包含已被 Server 字典解析准备好的明文事件载荷
oneof payload {
modules.NetworkEvent network = 4;
modules.StorageEvent storage = 5;
modules.ProcessEvent process = 6;
}
}控制面双向流动
message TaskRequest {
string task_id = 1; // 大模型任务关联 ID
common.Action action = 2; // e.g., ATTACH_TRACE, DETACH_TRACE
// 大模型下发的特定指令参数(如抓取网络、抓取内存)
oneof command_args {
modules.TraceNetworkArgs network_args = 3;
modules.TraceStorageArgs storage_args = 4;
modules.TraceProcessArgs process_args = 5;
}
}
message TaskResponse {
string task_id = 1;
common.Status status = 2;
string error_msg = 3;
// 捕获到的病理事件数组
repeated EventWrapper trace_results = 4;
// 任务窗口内形成的指标结果,例如连接快照或接口流量 delta
repeated MetricWrapper metric_results = 5;
}TaskChannel envelope gate
当前 TaskChannel wire shape 是显式 stream envelope:
rpc TaskChannel(stream TaskChannelUpstream) returns (stream TaskChannelDownstream);该变更是当前分支内的 lockstep breaking replacement;不支持旧 stream shape fallback,也不支持混合版本 Probe/Server。
Envelope gate 要求:
- Probe 打开 TaskChannel 后首帧必须是
TaskChannelHello。 - Server 在 hello 校验成功前不得下发
TaskRequest。 - hello 必须携带
node_id和session_token,Server 用它绑定 active session。 - 缺失 hello、非 hello 首帧、缺失 token、unknown session、stale session 或 node mismatch 必须明确关闭 stream。
- 后续
TaskResponse按task_id进入 TaskState,不重复携带 node/session。
进阶架构
为了达到稳定的生产级 SLA,通信层必须处理各种极端物理异常:
死点检测
- 场景:目标机器 Kernel Panic,根本来不及发送 TCP 断开握手包。
- 防御机制:通信底层强依赖
gRPC Keepalive机制。设置Time = 10s, Timeout = 3s。若 Server 在 13 秒内未收到物理层的心跳,立即触发Context.Done()。 - 系统闭环:Server 侧的【任务状态机】捕获到断连事件,立即将该节点关联的所有处于“同步阻塞”或“凭证等待”状态的 Task 标记为
FAILED_NODE_DEAD,大模型瞬间得到明确反馈,避免无意义的死等。
通信保障
- 场景:节点发生雪崩,海量 Metrics 和极其重要的 Critical Events(如 OOM 栈)挤满同一根管道,导致重要事件由于 TCP 拥塞控制而延迟。
- 防御机制:客户端隔离与熔断,Probe 端的发包队列(Channel)必须分离,并强制启用令牌桶限流。当网络拥塞时,触发事件同质化截断,优先全力保障核心样本 Events 的发送。
模块扩展
采用了 oneof 联合体后,每当系统扩展新的观测子系统(如增加 storage.proto),Server 端均需要增加对应的分支处理逻辑并重新编译。在面向 AI 的架构中,这种为了保证数据载荷**“100% 强类型与语义透明”**而付出的网关重编代价是极其必要且完全值得的。