Golang Go语言中利用 nginx fastcgi_cache 及 golang-lru 解决接口瓶颈
为满足特定的业务需求,我们有些接口数据极大,返回给客户端的数据 gzip 后大概是 80KB 左右, 不做 gzip 的话大概有 600KB 的样子。
实现方案
- nginx 做接入层,将请求转发到 golang/php 实现的接口服务
- golang/php 接收请求,先查 redis 集群,如果没有数据则查 mysql ,对数据做 json 序列化再存入 redis 集群 如果查到数据则对其做 json 反序列化,然后做相应业务逻辑生成结果并返回给 nginx
- nginx 对数据做 gzip 再返回给客户端
存在问题
- redis 集群流量较高
- golang/php 服务的 cpu 消耗比较明显,但是内存并没占用多少
- json 反序列化效率极差,尤其在大数据量的场景下
解决方案
由于 golang 与 php 的实现是分别由两个团队完成的,考虑到实现的可行性,我们先考虑通过 nginx 的 fastcgi_cache 来实现静态接口的缓存。这类接口并不要求实时更新,且大多通过 php 实现,因此完全可以通过 nginx fastcgi_cache 实现。而且此方案还有一些额外的好处,譬如避免请求蜂拥至后端,若后端出错可直接返回老数据等等。
然而,对于动态接口而言,这个方案完全没有办法满足需求。幸而动态接口基本都是基于 golang 实现的,因此我们只需要引入一种本地内存缓存方案,就可以很好的解决前面提及的三个问题。
经过一周左右时间的调研,我们考察了 golang-lru 、 go-cache 、 groupcache 、 freecache 及 bigcache 等各种缓存库,出于简单稳定高效的角度,我们最终选用了 golang-lru ,并在此基础上实现了 expire feature ,参考链接:GitHub - hnlq715/golang-lru: Golang LRU cache with expire feature.
与此同时,我们也参考了 groupcache 的特性,实现了类似逻辑,避免同时涌入过多请求到 redis :
func (l *lruCache) GetWithLoader(ctx context.Context, key string, load GetterFunc) (interface{}, error) {
l.stats.Gets.Add(1)
data, ok := l.arc.Get(key)
if !ok && load != nil {
return l.g.Do(key, func() (interface{}, error) {
l.stats.Loads.Add(1)
data, err := load()
if err != nil {
return nil, err
}
l.Set(ctx, key, data)
return data, err
})
}
l.stats.Hits.Add(1)
return data, nil
}
通过这个方案,我们实现了以下几个目标:
- 极大降低了 redis 集群流量
- cpu 资源消耗降低,内存利用率提升
- 避免过多 json 反序列化
从线上监控情况来看,目前的服务无论从响应时间、缓存命中率还是接口可用性来看,都比之前有了大幅提升。
作者: Sophos
链接: http://zhuanlan.zhihu.com/p/23326080
来源:知乎
著作权归作者所有,转载请联系作者获得授权。
Golang Go语言中利用 nginx fastcgi_cache 及 golang-lru 解决接口瓶颈
更多关于Golang Go语言中利用 nginx fastcgi_cache 及 golang-lru 解决接口瓶颈的实战教程也可以访问 https://www.itying.com/category-94-b0.html
不怎么更新的我一般扔 cdn
更多关于Golang Go语言中利用 nginx fastcgi_cache 及 golang-lru 解决接口瓶颈的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
静态接口的确可以扔 cdn , fastcgi_cache 实际上也就是扮演这个角色,但动态接口还是得靠自己 : )
简单点讲:从完全使用外部缓存( Redis )改成了外部缓存和进程内缓存并用
在Golang应用中遇到接口瓶颈时,结合Nginx的fastcgi_cache
和Golang的lru
缓存库可以显著提升性能。以下是一个专业建议的解决方案:
-
Nginx fastcgi_cache配置:
- 首先,确保Nginx已安装并配置好
fastcgi_cache
模块。 - 配置Nginx的
fastcgi_cache_path
指令,设置缓存存储路径、缓存大小、缓存级别等参数。 - 在对应的
location
块中,启用fastcgi_cache
,并设置缓存的key、有效期等。 - 通过
fastcgi_cache_valid
指令为不同类型的响应设置不同的缓存时间。
- 首先,确保Nginx已安装并配置好
-
Golang-lru缓存库:
- 在Golang应用中,使用
golang.org/x/exp/maps/lru
或类似的LRU(Least Recently Used)缓存库。 - 初始化LRU缓存,设置合适的容量。
- 对于频繁访问的数据,如数据库查询结果,将其存入LRU缓存中。
- 在处理请求时,首先检查LRU缓存,若命中则直接返回缓存结果,否则执行数据库查询等操作,并将结果存入缓存。
- 在Golang应用中,使用
-
综合应用:
- Nginx作为反向代理,可以缓存静态内容以及部分动态接口的响应。
- Golang应用通过LRU缓存减少数据库访问,提升接口响应速度。
- 两者结合,形成多级缓存体系,有效缓解接口瓶颈。
请注意,缓存的引入需要谨慎处理数据一致性问题,并定期清理过期或无效缓存。同时,根据实际负载和性能需求,调整缓存配置和策略。