高频加密放中间件导致cpu爆,因aes/sha纯cpu密集且无i/o等待;100 qps×5ms=500ms/s,单核迅速打满,并阻塞go调度器。

高频加密运算放在中间件里为什么CPU会爆?
因为中间件每次请求必执行,而AES/SHA等加密函数是纯CPU密集型操作,没有I/O等待。100 QPS × 单次加密耗时5ms = 每秒500ms CPU时间,单核很快打满。更糟的是,Go默认复用Goroutine,阻塞型计算会抢占调度器,拖慢其他请求。
把加密逻辑从中间件移出来最直接的改法
不是所有请求都需要实时加密;多数场景只需对敏感字段(如用户token、支付回调签名)做校验或生成,且往往只发生在特定路由下。强行全局拦截是典型过设计。
- 用
router.Group("/api/v1/secured")包裹需要加密的路由,只在该组注册加密中间件 - 把加密逻辑下沉到具体 handler 里,比如
c.GetString("raw_payload")后再调用encryptPayload() - 若必须前置校验(如API签名验证),改用轻量级校验:HMAC-SHA256 比 RSA 签名快两个数量级,且可提前验证 key 是否存在
中间件内做加密时必须加缓存和复用
如果确实无法移出中间件(例如统一审计日志需加密原始请求体),至少避免重复计算和内存抖动。
- 用
sync.Pool复用加密器实例:var aesCipherPool = sync.Pool{New: func() interface{} { return cipher.NewCBCEncrypter(...) }} - 请求体先用
c.Request.Body读一次,c.Set("encrypted_body", encrypted)后续 handler 直接取,别反复解密 - 禁用中间件内的
log.Printf或 JSON 序列化 —— 这些会触发额外 GC,和加密争抢 CPU
用异步或预计算绕开同步阻塞
加密结果不总需要立刻返回给客户端。比如日志脱敏、审计存档,完全可以异步处理,释放主线程。
- 在中间件末尾启动 goroutine:
go func() { encryptAndStore(c.Copy(), payload) }() - 用 Redis 缓存已加密结果,键为
"enc:" + sha256.Sum256(payload).String(),命中则跳过计算 - 对固定 salt+key 的场景,启动时预热生成常用密钥对象,避免 runtime 初始化开销











