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

4.3 KiB
Raw Blame History

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 不会丢失计数