1
0
Files
nex/openspec/specs/stats-buffer/spec.md
lanyuanxiaoyao df253559a5 feat(cache): 实现 RoutingCache 和 StatsBuffer 优化数据库写入
- 新增 RoutingCache 组件,使用 sync.Map 缓存 Provider 和 Model
- 新增 StatsBuffer 组件,使用 sync.Map + atomic.Int64 缓冲统计数据
- 扩展 StatsRepository.BatchUpdate 支持批量增量更新
- 改造 RoutingService/StatsService/ProviderService/ModelService 集成缓存
- 更新 usage-statistics spec,新增 routing-cache 和 stats-buffer spec
- 新增单元测试覆盖缓存命中/失效/并发场景
2026-04-22 19:24:36 +08:00

157 lines
4.3 KiB
Markdown
Raw 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.
# Stats Buffer
## Purpose
TBD - 为统计数据提供内存缓冲,优化写入性能。
## Requirements
### Requirement: StatsBuffer 内存缓冲
系统 SHALL 为统计数据提供内存缓冲,使用 sync.Map + atomic.Int64 进行计数。
#### Scenario: 缓冲数据结构
- **WHEN** 创建 StatsBuffer
- **THEN** SHALL 使用 sync.Map 存储计数器key = providerID/modelName/date
- **THEN** SHALL 使用 atomic.Int64 进行计数
- **THEN** SHALL 支持配置刷新间隔和阈值
### Requirement: 原子计数
StatsBuffer SHALL 使用原子操作进行计数。
#### Scenario: Increment 计数
- **WHEN** 调用 StatsBuffer.Increment
- **THEN** SHALL 使用 atomic.AddInt64 增加计数
- **THEN** SHALL 无锁操作
- **THEN** SHALL 线程安全
#### Scenario: Increment 创建计数器
- **WHEN** 调用 StatsBuffer.Increment 且计数器不存在
- **THEN** SHALL 使用 sync.Map.LoadOrStore 创建计数器
- **THEN** SHALL 初始化计数器为 0
- **THEN** SHALL 原子增加计数
#### Scenario: 并发计数
- **WHEN** 多个 goroutine 并发 Increment
- **THEN** SHALL 计数准确
- **THEN** SHALL 无竞态条件
### Requirement: 定时刷新
StatsBuffer SHALL 支持定时刷新到数据库。
#### Scenario: 定时刷新触发
- **WHEN** 后台刷新协程运行
- **THEN** SHALL 每隔 flushInterval 触发刷新
- **THEN** SHALL 调用 StatsRepository.BatchUpdate 写入数据库
#### Scenario: 刷新间隔配置
- **WHEN** 创建 StatsBuffer
- **THEN** 默认 flushInterval 为 5 秒
- **THEN** 可通过 WithFlushInterval 选项配置
### Requirement: 阈值触发刷新
StatsBuffer SHALL 支持累计阈值触发刷新。
#### Scenario: 阈值触发
- **WHEN** 累计计数达到 flushThreshold
- **THEN** SHALL 异步触发刷新
- **THEN** SHALL 不阻塞请求
#### Scenario: 阈值配置
- **WHEN** 创建 StatsBuffer
- **THEN** 默认 flushThreshold 为 100
- **THEN** 可通过 WithFlushThreshold 选项配置
### Requirement: 批量写入数据库
StatsBuffer SHALL 批量写入统计数据到数据库。
#### Scenario: 批量写入
- **WHEN** 刷新触发
- **THEN** SHALL 遍历所有计数器
- **THEN** SHALL 使用 atomic.SwapInt64(counter, 0) 获取并清零计数器
- **THEN** SHALL 调用 StatsRepository.BatchUpdate 批量写入
- **THEN** SHALL 重置 totalCount 为 0
#### Scenario: SwapInt64 清零计数器
- **WHEN** flush 收集计数器
- **THEN** SHALL 使用 SwapInt64 原子操作获取当前计数并清零
- **THEN** SHALL 保证计数不丢失(新计数会累加到已清零的计数器)
- **THEN** SHALL 不阻塞后续 Increment 操作
#### Scenario: 写入失败保留计数器
- **WHEN** BatchUpdate 失败
- **THEN** SHALL 将计数加回计数器(使用 atomic.AddInt64
- **THEN** SHALL 记录错误日志
- **THEN** SHALL 继续处理其他条目
### Requirement: 优雅关闭
StatsBuffer SHALL 支持优雅关闭,确保最后的统计写入数据库。
#### Scenario: Stop 等待刷新完成
- **WHEN** 调用 StatsBuffer.Stop
- **THEN** SHALL 停止后台刷新协程
- **THEN** SHALL 执行最后一次刷新
- **THEN** SHALL 等待刷新完成
- **THEN** SHALL 保证统计数据不丢失
#### Scenario: 无超时
- **WHEN** Stop 等待刷新
- **THEN** SHALL 无超时限制
- **THEN** SHALL 等待刷新完成
### Requirement: StatsService 使用缓冲
StatsService SHALL 使用 StatsBuffer 进行统计记录。
#### Scenario: Record 使用缓冲
- **WHEN** 调用 StatsService.Record
- **THEN** SHALL 调用 StatsBuffer.Increment
- **THEN** SHALL 不直接调用 StatsRepository.Record
- **THEN** SHALL 立即返回,不阻塞
### Requirement: StatsRepository 扩展
StatsRepository SHALL 新增 BatchUpdate 方法。
#### Scenario: BatchUpdate 方法
- **WHEN** 调用 StatsRepository.BatchUpdate
- **THEN** SHALL 使用事务更新或创建统计记录
- **THEN** SHALL 使用 request_count + delta 更新
- **THEN** SHALL 支持批量增量更新
### Requirement: 并发安全
StatsBuffer SHALL 支持并发访问。
#### Scenario: 并发 Increment 和 flush
- **WHEN** 并发 Increment 和 flush
- **THEN** SHALL 无竞态条件
- **THEN** SHALL 计数准确(可能延迟到下次 flush
#### Scenario: flush 期间 Increment
- **WHEN** flush 正在执行
- **THEN** 新的 Increment SHALL 继续计数
- **THEN** SHALL 不会丢失计数