利用 nginx fastcgi_cache 及 golang-lru 解决接口瓶颈

2016-10-31 16:37:43 +08:00
 sophos

为满足特定的业务需求,我们有些接口数据极大,返回给客户端的数据 gzip 后大概是 80KB 左右, 不做 gzip 的话大概有 600KB 的样子。

实现方案

  1. nginx 做接入层,将请求转发到 golang/php 实现的接口服务
  2. golang/php 接收请求,先查 redis 集群,如果没有数据则查 mysql ,对数据做 json 序列化再存入 redis 集群 如果查到数据则对其做 json 反序列化,然后做相应业务逻辑生成结果并返回给 nginx
  3. nginx 对数据做 gzip 再返回给客户端

存在问题

  1. redis 集群流量较高
  2. golang/php 服务的 cpu 消耗比较明显,但是内存并没占用多少
  3. 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
}

通过这个方案,我们实现了以下几个目标:

  1. 极大降低了 redis 集群流量
  2. cpu 资源消耗降低,内存利用率提升
  3. 避免过多 json 反序列化

从线上监控情况来看,目前的服务无论从响应时间、缓存命中率还是接口可用性来看,都比之前有了大幅提升。

作者: Sophos
链接: http://zhuanlan.zhihu.com/p/23326080
来源:知乎
著作权归作者所有,转载请联系作者获得授权。
1068 次点击
所在节点    Go 编程语言
3 条回复
mooncakejs
2016-10-31 20:14:28 +08:00
不怎么更新的我一般扔 cdn
sophos
2016-10-31 21:00:55 +08:00
@mooncakejs 静态接口的确可以扔 cdn , fastcgi_cache 实际上也就是扮演这个角色,但动态接口还是得靠自己 : )
denghongcai
2016-11-01 11:00:45 +08:00
简单点讲:从完全使用外部缓存( Redis )改成了外部缓存和进程内缓存并用

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/316837

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX