创建仓库

This commit is contained in:
2025-12-11 07:24:36 +08:00
commit 0d81c1792d
128 changed files with 15104 additions and 0 deletions

View File

@@ -0,0 +1,152 @@
---
tags: []
date created: 星期五, 十一月 21日 2025, 12:00:13 凌晨
date modified: 星期一, 十一月 24日 2025, 4:31:24 下午
---
# 2.3.2 全链路追踪上下文传递 (Trace Context Propagation)
## 一、 约束输入与对齐 (Constraints & Alignment)
基于设计文档和 C++14 环境,我们需要对齐以下硬性约束:
1. **无侵入性 (Non-Intrusive)**:业务逻辑代码(如算法计算)不应到处传递 `trace_id` 参数。追踪上下文的获取应当是“隐式”的。
2. **跨线程连续性 (Cross-Thread Continuity)**:系统大量使用异步队列(`EventBus::publishAsync`和工作线程池。TraceID 必须能跨越线程边界,不能断链。
3. **性能极其敏感**:追踪机制是**热路径 (Hot Path)**。获取当前 TraceID 的开销必须是纳秒级,严禁涉及锁竞争或复杂的哈希查找。
4. **来源明确**
- **数据面**:由 `DataReceiver` 在收到 UDP 包时生成。
- **控制面**:由 `TaskScheduler` 在定时任务或外部 API 调用时生成。
---
## 二、 权衡分析与选项呈现 (Trade-off Matrix)
### 议题 1上下文存储方式 (Storage Mechanism)
|**选项**|**A. 显式参数传递 (Explicit Parameter)**|**B. 全局 Map 映射 (Global Map)**|**C. 线程本地存储 (Thread Local Storage - TLS) (推荐)**|
|---|---|---|---|
|**机制**|每个函数增加 `const TraceId& tid` 参数。|维护 `Map<ThreadID, TraceID>`。|使用 C++ `thread_local` 关键字。|
|**侵入性**|**极高**。所有接口签名都要改,污染业务代码。|**低**。但在读写时需要加锁(或无锁 Map有性能开销。|**零**。业务代码无感。|
|**性能**|最佳。|差(锁竞争)。|**极佳**。直接的内存地址访问,无锁。|
|**缺陷**|代码丑陋。|性能瓶颈。|**跨线程时会丢失**(需额外机制弥补)。|
### 议题 2跨线程传递策略 (Propagation Strategy)
针对 TLS 跨线程丢失的问题:
|**选项**|**A. 手动拷贝 (Manual Copy)**|**B. 智能闭包捕获 (Smart Closure Capture) (推荐)**|
|---|---|---|
|**机制**|在 `publishAsync` 前手动取出 ID在回调里手动设置。|封装 `EventBus` 的任务包装器,**在入队瞬间自动捕获 TLS在执行瞬间自动恢复 TLS**。|
|**可靠性**|**低**。开发者容易忘,导致断链。|**高**。由基础设施层保证,业务无感。|
|**复杂度**|低。|中。需要编写通用的任务包装模板。|
---
## 三、 基线确立与实施规范
为了实现“高性能”与“全链路无感”,我们确立 **C. 线程本地存储 (TLS) + B. 智能闭包捕获** 为技术基线。
### 1. 核心数据结构基线
- **`TraceId` 类型**:使用 `uint64_t``uuid`(推荐 64 位整数配合 SnowFlake 算法,追求极致性能)。
- **`BaseEvent` 接口**:所有控制面事件必须继承此基类。
```cpp
struct BaseEvent {
uint64_t trace_id; // 事件携带的“信封”
uint64_t timestamp;
BaseEvent() {
// 构造时自动从当前线程 TLS 捕获 TraceID
// 如果当前是根源(无 ID则保持 0 或生成新 ID视策略而定
trace_id = TraceContext::getCurrentId();
timestamp = CurrentTimeMillis();
}
};
```
### 2. 上下文管理基线 (RAII + TLS)
我们定义一个静态辅助类 `TraceContext` 和一个 RAII 守卫 `TraceContextGuard`。
- **`TraceContext` (TLS 管理)**
```cpp
class TraceContext {
public:
static void set(uint64_t id) { current_trace_id_ = id; }
static uint64_t get() { return current_trace_id_; }
static void clear() { current_trace_id_ = 0; }
// 生成一个新的全局唯一 ID
static uint64_t generateNew();
private:
// 核心:每个线程独立一份,无锁,极速
static thread_local uint64_t current_trace_id_;
};
```
- **`TraceContextGuard` (RAII 自动恢复)**
- **作用**:在作用域结束时自动还原之前的 ID支持嵌套调用。
- **场景**:用于事件处理函数入口,确保处理完事件后,线程状态复原,不污染后续逻辑。
### 3. EventBus 集成规范 (跨线程核心)
这是本节最关键的设计:**如何在 `publishAsync` 时“偷渡”上下文?**
- **基线实现逻辑**
1. **Publish 时 (线程 A)**`publishAsync` 函数内部,获取当前线程 A 的 `TraceContext::get()`。
2. **入队时**:将取出的 `trace_id` 和用户的 `handler` 打包成一个 `WrappedTask`。
3. **Execute 时 (线程 B)**`WrappedTask` 被执行。它首先使用 `TraceContextGuard` 将线程 B 的 TLS 设置为保存的 `trace_id`,然后执行用户 `handler`,最后 RAII 自动清理。
- **伪代码范式**
```cpp
template <typename EventType>
void IEventBus::publishAsync(const EventType& event) {
// 1. 捕获上下文 (此时还在发送者线程)
uint64_t context_id = event.trace_id;
// 2. 包装任务 (Lambda Capture)
auto wrapped_task = [handler, event, context_id]() {
// 3. 恢复上下文 (此时已在接收者线程)
TraceContextGuard guard(context_id);
// 4. 执行业务逻辑 (此时日志库能读到正确的 TLS TraceID)
handler(event);
};
// 5. 推入队列
work_queue_.push(wrapped_task);
}
```
### 4. 日志集成规范
- **基线要求**:所有日志宏(如 `RADAR_INFO`)必须自动读取 `TraceContext::get()` 并打印。
- **格式**`[Time][Level][ThreadID][TraceID] Message`。
- **效果**:业务代码只需写 `RADAR_INFO("Processing data")`,日志文件里会自动出现 `… [TraceID: 12345] Processing data`。
---
## 总结2.3.2 基线图谱
|**维度**|**基线决策**|**关键技术点**|
|---|---|---|
|**存储**|**Thread Local Storage (TLS)**|`thread_local uint64_t`,无锁,纳秒级访问。|
|**载体**|**`BaseEvent` 继承**|所有事件自动携带 `trace_id` 字段。|
|**跨线程**|**智能闭包捕获 (Smart Capture)**|`EventBus` 在入队/出队时自动 Switch Context。|
|**作用域**|**RAII Guard**|`TraceContextGuard` 保证作用域内的上下文一致性和退出后的还原。|
---
**下一步行动**
我们已经搞定了“大喇叭总线”和“条形码TraceID”。接下来要定的是“握手暗号” —— **2.3.3 生命周期编排与状态同步协议**。
在这个系统中,模块启动不是简单的 `start()`,它涉及依赖检查、顺序控制和状态回执。比如,`SignalProcessor` 启动前必须确认 GPU 资源就绪,启动后必须告诉调度器“我好了”。
**提问**:您是否确认 **“TLS + 智能闭包捕获”** 的上下文传递基线?确认后我们将进入 2.3.3。