perf: Sprint 19 P0/P1 性能优化落地
P0(高优先级): - P0-1: 确认数据库复合索引已存在(GORM tag),composite_index_test 验证通过 - P0-2: 连接池调优 MaxIdleConns 5→10, ConnMaxLifetime 30min→5min - P0-3: Redis 智能探测(ProbeRedis),无 Redis 自动降级到纯内存模式 P1(中优先级): - P1-1: GZIP 压缩中间件(compress/gzip 标准库,零新依赖) - P1-2: 权限缓存 TTL 30min→5min - P1-3: Argon2id 启动自适应校准(CalibrateArgon2id) 历史优化(含本次提交): - L1Cache O(n)→O(1) LRU 重构 - Auth 中间件 DB 查询合并 + 5s L1 缓存 - Logger 异步化(4096 缓冲通道) 验证: go build/vet/test 41/41 PASS, govulncheck 无漏洞
This commit is contained in:
@@ -6,8 +6,10 @@ import (
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"golang.org/x/crypto/argon2"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
@@ -35,6 +37,78 @@ func NewPassword() *Password {
|
||||
}
|
||||
}
|
||||
|
||||
// CalibrateArgon2id 在当前机器上自动校准 Argon2id 参数,确保单次哈希时间不超过 budget。
|
||||
//
|
||||
// 校准策略(优先保留 memory,其次降低 iterations):
|
||||
// 1. 用默认参数(64MB/5iter)测量一次哈希耗时。
|
||||
// 2. 若耗时 ≤ budget,直接返回:默认参数已安全。
|
||||
// 3. 若耗时 > budget,先尝试降低 iterations(最低 2)。
|
||||
// 4. 若仍超预算,再二分降低 memory(最低 16MB)。
|
||||
// 5. 若仍超预算,打印 warn 但不更改参数(避免参数过弱)。
|
||||
//
|
||||
// 建议在 main() 启动阶段调用一次,结果会更新全局 defaultPasswordManager。
|
||||
// budget 推荐值:500ms(登录接口 P99 目标 < 1000ms,留出网络/DB 余量)。
|
||||
func CalibrateArgon2id(budget time.Duration) {
|
||||
if budget <= 0 {
|
||||
budget = 500 * time.Millisecond
|
||||
}
|
||||
|
||||
probe := func(mem uint32, iter uint32, par uint8) time.Duration {
|
||||
salt := make([]byte, 16)
|
||||
_, _ = rand.Read(salt)
|
||||
start := time.Now()
|
||||
_ = argon2.IDKey([]byte("calibration-probe"), salt, iter, mem, par, 32)
|
||||
return time.Since(start)
|
||||
}
|
||||
|
||||
mem := defaultPasswordManager.memory
|
||||
iter := defaultPasswordManager.iterations
|
||||
par := defaultPasswordManager.parallelism
|
||||
|
||||
elapsed := probe(mem, iter, par)
|
||||
log.Printf("argon2id calibration: default params (m=%dKB, t=%d, p=%d) → %v", mem, iter, par, elapsed)
|
||||
|
||||
if elapsed <= budget {
|
||||
log.Printf("argon2id calibration: default params are within budget (%v ≤ %v), no adjustment needed", elapsed, budget)
|
||||
return
|
||||
}
|
||||
|
||||
// Step 1:尝试降低 iterations(最低 2,低于 2 不满足 OWASP 最低要求)
|
||||
for iter > 2 {
|
||||
iter--
|
||||
elapsed = probe(mem, iter, par)
|
||||
log.Printf("argon2id calibration: trying m=%dKB t=%d p=%d → %v", mem, iter, par, elapsed)
|
||||
if elapsed <= budget {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Step 2:若仍超预算,二分降低 memory(最低 16MB = 16*1024 KiB)
|
||||
if elapsed > budget {
|
||||
const minMem = 16 * 1024
|
||||
for mem > minMem && elapsed > budget {
|
||||
mem /= 2
|
||||
if mem < minMem {
|
||||
mem = minMem
|
||||
}
|
||||
elapsed = probe(mem, iter, par)
|
||||
log.Printf("argon2id calibration: trying m=%dKB t=%d p=%d → %v", mem, iter, par, elapsed)
|
||||
}
|
||||
}
|
||||
|
||||
if elapsed > budget {
|
||||
log.Printf("argon2id calibration: WARN — even minimum params (m=%dKB, t=%d) take %v > %v; check server load", mem, iter, elapsed, budget)
|
||||
// 不降低到不安全参数,保持当前已尝试的最低值
|
||||
} else {
|
||||
log.Printf("argon2id calibration: adjusted params m=%dKB t=%d p=%d → %v (budget: %v)", mem, iter, par, elapsed, budget)
|
||||
}
|
||||
|
||||
// 更新全局默认管理器(仅在此阶段修改,后续不再变更)
|
||||
defaultPasswordManager.memory = mem
|
||||
defaultPasswordManager.iterations = iter
|
||||
}
|
||||
|
||||
|
||||
// Hash 哈希密码(使用Argon2id + 随机盐)
|
||||
func (p *Password) Hash(password string) (string, error) {
|
||||
// 使用 crypto/rand 生成真正随机的盐
|
||||
|
||||
Reference in New Issue
Block a user