Files
cache-proxy/memory-bank/systemPatterns.md
guochao 2a0bd28958
Some checks failed
build container / build-container (push) Has been cancelled
use cline and prepare to test the project for further development
2025-06-10 14:14:32 +08:00

2.6 KiB
Raw Blame History

系统架构与设计模式

cache-proxy 的系统设计遵循了几个关键的模式和原则,以实现其高性能和高可用性的目标。

核心架构

系统可以分为三个主要部分:

  1. HTTP 服务器层: 负责接收客户端请求,并使用中间件进行日志记录、错误恢复等通用处理。
  2. 缓存处理层: 检查请求的文件是否存在于本地缓存中,并根据缓存策略决定是直接提供缓存文件还是向上游请求。
  3. 上游选择与下载层: 这是系统的核心,负责并发地从多个上游服务器获取数据,并管理下载过程。

关键设计模式

1. 竞争式请求 (Racing Requests)

这是实现“选择最快”功能的核心模式。

  • fastesUpstream 函数为每个上游服务器创建一个 goroutine。
  • 所有 goroutine 并发地向上游服务器发送请求。
  • 使用 sync.Once 来确保只有一个 goroutine 能够“胜出”并成为最终的数据源。
  • 一旦有 goroutine 胜出,它会调用 context.CancelFunc 来通知所有其他 goroutine 停止工作,从而避免不必要的资源消耗。

2. 生产者-消费者模式 (Producer-Consumer)

在文件下载过程中,使用了生产者-消费者模式。

  • 生产者: tryUpstream 函数中的 goroutine 负责从上游服务器读取数据块chunk并将其放入一个 chan Chunk 中。
  • 消费者: streamOnline 函数中的代码从 chan Chunk 中读取数据,并执行两个操作:
    1. 将数据写入 bytes.Buffer,供后续的请求者使用。
    2. 将数据写入本地临时文件,用于持久化缓存。

3. 并发访问控制 (Mutex for Concurrent Access)

为了处理多个客户端同时请求同一个文件的情况,系统使用了 sync.Mutex 和一个 map[string]*StreamObject

  • 当第一个请求到达时,它会获得一个锁,并创建一个 StreamObject 来代表这个正在进行的下载任务。
  • 后续对同一文件的请求会发现 StreamObject 已存在,它们不会再次向上游发起请求,而是会等待并从这个共享的 StreamObject 中读取数据。
  • 下载完成后,StreamObject 会从 map 中移除。

4. 中间件 (Middleware)

项目使用了 Go 的标准 http.Handler 接口和中间件模式来构建请求处理链。

  • pkgs/middleware 目录中定义了可重用的中间件,如 httplogrecover
  • 这种模式使得在不修改核心业务逻辑的情况下,可以轻松地添加或删除日志、认证、错误处理等功能。