1. 背景
API 服务器 timewait 一直下不去
尝试阿里云优化方案, 修改内核配置, 也不管用
前端表现为:
- 页面访问卡顿
- 页面丢失(接口504)
- Postman start_trasfer 参数忽高忽低(100ms-10s)
推测 API 拒绝服务了
2. 分析
-
监控查看到 io 耗时增加
-
日志查询到后端微服务没问题, 响应很快
-
Postman 查看接口访问链接时间
-
阿里云ALB监控页面显示 5xx 状态码明显增加
3. 解决
- 为热点接口增加缓存
- 收紧该热点接口限流设置
- 修改日志级别到 warn (此项操作做完 io 明显下降)
4. 为热点接口增加缓存踩坑纪要
1. ORM缓存
- 线上业务仍在运行的情况下, 分步热更新 后台微服务
- 首先尝试为 ORM 加缓存, 因为快, 只需要增加两行代码
cacher := xorm.NewLRUCacher(xorm.NewMemoryStore(), 1000)
engine.MapCacher(&user, cacher)
但是这里有坑
不过需要特别注意不适用缓存或者需要手动编码的地方:
当使用了Distinct,Having,GroupBy方法将不会使用缓存
在Get或者Find时使用了Cols,Omit方法,则在开启缓存后此方法无效,系统仍旧会取出这个表中的所有字段。
在使用Exec方法执行了方法之后,可能会导致缓存与数据库不一致的地方。因此如果启用缓存,尽量避免使用Exec。如果必须使用,则需要在使用了Exec之后调用ClearCache手动做缓存清除的工作。
整个 后台 server 的开发工作不仅仅是我一人完成的, 这里也没有去查询是否有用到 Exec
方法, 最终导致用户锁单失败, 超售了
后来紧急回滚了
2. GIN 中间件缓存
基于架构设计, API 承上启下, 实现 HTTP 接口, 调用微服务; API 使用 GIN 框架作为 HTTP 服务框架, 尝试寻找一个 GIN 框架的缓存轮子
- 官方版本
不好用, 需要前端配合, 放弃 - 三方版本
优点: 中间件实现形式, 方便使用, 性能比官方好一些
缺点:- 只支持 URI 做接口缓存, 但是我这里的需求是 POST 形式, 参数在 body 内, 无法适用
- 暂不支持 redis 集群作为缓存介质
- 三方版本PR
修改了三方版本里只支持URI作为key缓存的情况, 增加了 body 的 hash 为key缓存, 刚好符合要求(用内存形式先上)
5. 小结
- ORM缓存不可轻易使用, 加了ORM缓存后, 需要回测
- 接口缓存注意缓存有效期, 根据具体业务需求来定