⚡️ perf(fqapi): 移除缓存层全局串行锁

- 删除 cache_manager/audio_proxy/device_key_pool 中 21 处 cacheMutex:database/sql 连接池本身并发安全,SQLite 已配 WAL + busy_timeout,PostgreSQL 无并发写限制
- contentRequestCount 三函数由互斥锁改为 atomic.Int64
- cache_manager 中 config.GetConfig() 改为 GetAppConfig(),消除配置未初始化时 log.Fatal 崩溃整个进程的隐患
- VACUUM 与写操作的低频并发冲突由 busy_timeout 兜底(已注释说明)
- 新增 TestConcurrentCacheAccess:8 goroutine 并发读写缓存,-race 验证无死锁无竞争
This commit is contained in:
chenxin committed 2026-09-29 23:21:10 +08:00
1 parent 24c7e4b6fd
commit f0d89b462b
4 files changed
+68 -68

No files matched your search

-9
View File
@@ -35,8 +35,6 @@ func GenerateAudioProxyURL(originalURL, deviceID string, headers map[string]stri
// 存储到数据库
if cacheDB != nil {
cacheMutex.Lock()
defer cacheMutex.Unlock()
_, err := cacheDB.Exec(q(`
INSERT INTO audio_cache (key, original_url, device_id, headers, created_at)
@@ -71,12 +69,10 @@ func HandleAudioProxy(key string) ([]byte, string, error) {
var headersJSON string
var createdAt int64
cacheMutex.Lock()
err := cacheDB.QueryRow(q(`
SELECT original_url, device_id, headers, created_at
FROM audio_cache WHERE key = ?
`), key).Scan(&originalURL, &deviceID, &headersJSON, &createdAt)
cacheMutex.Unlock()
if err == sql.ErrNoRows {
return nil, "", fmt.Errorf("音频信息不存在,请先调用 /audio 接口")
@@ -88,9 +84,7 @@ func HandleAudioProxy(key string) ([]byte, string, error) {
// 检查缓存是否过期(2小时,匹配CDN链接有效期)
if time.Now().Unix()-createdAt > 7200 { // 2小时 = 7200秒
// 清理过期缓存
cacheMutex.Lock()
cacheDB.Exec(q("DELETE FROM audio_cache WHERE key = ?"), key)
cacheMutex.Unlock()
return nil, "", fmt.Errorf("音频信息已过期,请重新调用 /audio 接口")
}
@@ -121,9 +115,6 @@ func CleanExpiredAudioCache() {
return
}
cacheMutex.Lock()
defer cacheMutex.Unlock()
// 删除2小时前的缓存
result, err := cacheDB.Exec(q("DELETE FROM audio_cache WHERE created_at < ?"), time.Now().Unix()-7200)
if err != nil {