Title here
Summary here
阅读时间: 约 15 分钟 适用人群: 架构师、高级开发者
本文分析 UCM 项目中的关键架构决策,解释每个决策的背景、权衡和最终选择的原因。
UCM 需要与 vLLM 深度集成,有三种可选方案:
| 方案 | 维护成本 | 灵活性 | 升级难度 | 功能覆盖 |
|---|---|---|---|---|
| Fork vLLM | 高 | 最高 | 困难 | 完全 |
| 官方插件 | 低 | 有限 | 简单 | 有限 |
| Monkey Patching | 中 | 高 | 中等 | 几乎完全 |
选择理由:
如何唯一标识 KV Cache Block,有两种主要思路:
| 方案 | 跨请求复用 | 分布式共享 | 计算开销 | 碰撞风险 |
|---|---|---|---|---|
| 位置寻址 | 不支持 | 不支持 | 极低 | 无 |
| 内容寻址 | 支持 | 支持 | 低 | 极低 |
选择理由:
| 算法 | 速度 | 碰撞率 | 输出长度 |
|---|---|---|---|
| MD5 | 快 | 极低 | 128 bit |
| SHA-256 | 中 | 更低 | 256 bit |
| xxHash | 最快 | 可接受 | 64/128 bit |
| 选择 MD5 因为: |
如何设计存储接口以支持多种后端:
设计理由:
class UcmKVStoreBase:
def lookup(self, block_ids) -> List[bool]
def load(self, block_ids, offset, tensor) -> Task
def dump(self, block_ids, offset, tensor) -> Task
# V1 接口 - 增强功能
class UcmKVStoreBaseV1(UcmKVStoreBase):
def load_data(self, block_ids, shard_indices, ...) -> Task
def dump_data(self, block_ids, shard_indices, ...) -> Task优势:
存储操作应该同步还是异步:
设计理由:
# 异步操作返回 Task
task = store.load(block_ids, offset, tensor)
do_something_else()
status = store.wait(task)优势:
如何支持多级存储层级:
设计理由:
store_pipeline: "Cache|Posix" # 内存缓存 + 本地存储
store_pipeline: "Cache|NFS" # 内存缓存 + 网络存储
store_pipeline: "Cache|DS3FS" # 内存缓存 + S3 存储优势:
如何设计一个支持多种稀疏算法的框架:
设计理由:
class UcmSparseBase:
# Scheduler 侧钩子
def request_begin(self, request_id, prompt_token_ids): ...
def build_sparse_meta(self, scheduler_output): ...
# Worker 侧钩子
def attention_begin(self, layer_idx, q, k, v): ...
def attention_finished(self, layer_idx, output): ...优势:
| 决策领域 | 选择 | 关键理由 |
|---|---|---|
| vLLM 集成 | Monkey Patching | 非侵入、灵活、可升级 |
| Block 标识 | MD5 内容寻址 | 跨请求复用、分布式友好 |
| 存储接口 | 分层 V0/V1 | 渐进增强、简化实现 |
| 操作模型 | 异步 Task | 计算传输重叠、批量操作 |
| 存储层级 | Pipeline 组合 | 灵活配置、易扩展 |
| 稀疏框架 | 生命周期钩子 | 统一接口、可组合 |