ngx_srcache + lua异步更新缓存----提升10倍的响应速度

nginx_lua异步更新缓存

NGINX

一直使用nginx作为反向代理服务器,一来nginx基于事件驱动,速度快。而来nginx的反向代理模块能很好的支持页面缓存负载均衡

页面缓存

nginx有proxy_cache这个内置的缓存功能,是基于文件的。如果把缓存路径设置到RAMDISK上面,可以达到和内存缓存差不多的缓存读写速度。这样做虽然解决了文件读写慢的问题,但是如果分布式部署的时候,这个缓存不能跨机器共享。

srcache-nginx-module

章大神写的这个模块支持和另一个模块配合将页面缓存写入redis集群。就很好的解决了

  1. 缓存不能跨机器共享的问题

  2. 也使得缓存大小不受单机资源限制

  3. 同时,redis本身还能提供快速的读写速度

问题

看上面列的几点,似乎已经很完美了。
但是在实际使用的时候还是发现有需要改善的地方:

  1. 缓存不存在的时候:
    第一个请求查询redis失败,到后端,最后还要存储redis。比没有缓存的情况还多出两次redis访问,一次读一次写。而且当并发访问的时候还可能请求都会进入后端服务器,后端不够健壮的时候会导致“雪崩效应”。(如果使用默认的proxy_cache模块还能通过proxy_cache_use_stale命令避免,但是srcache模块没有实现类似功能)

  2. 缓存失效的时候
    通常我们为页面设置缓存时间,缓存失效的时候,需要重新更新缓存。这个时候也会出现第一种情况类似的问题。

以上两种情况,第一种出现较少,第二种情况出现较多。都是由于redis自动删除过期缓存,导致的缓存缺失。

解决办法

由于nginx不知道redis里面数据的缓存时间,所以会频繁的导致缓存缺失的情况出现。
既然知道原因了,那么咱们就来针对性的解决一下这个问题。让nginx能够知道甚至参与到缓存时间的管理里面,就能有效的避免被动的缓存缺失问题,能有意识的主动更新缓存

ngx_lua

这里需要提到一个nginx的第三方模块就是把lua集成到nginx里面扩展了nginx配置文件语法,支持在配置文件里面直接使用lua语言编写逻辑。

lua-resty-cache

我将自己在项目中使用的一个仓库开源到github上面了。

  1. 能让nginx主动的检测缓存的过期时间

  2. 在快过期的时候,直接返回旧的缓存数据

  3. 使用异步任务更新缓存

以上的第二第三两点,就能在缓存快过期的时候,主动的异步更新缓存,让终端用户感知不到更新缓存的过程。
项目中实测,使用这个缓存机制之后,用户感知到的平均响应速度提升了10倍(nginx access log分析结果),而这都是在原有系统性能不变的情况下实现的!是不是有点不可思议。

原理

下面就来说一说提升速度的原理:

  1. 如果缓存缺失,直接跳过srcache_fetch步骤,将请求发到后端server。同时申请一个共享内存锁,并发而来的相同的请求不用发送到后端,而是等待这个请求返回。

  2. 更新缓存的时候,在过期时间expire基础上加上一个stale time。那么在到了过期时间的时候,redis还不会立即删掉这个数据。

  3. 如果检测到数据过期,但是redis还能拿到这个“过期”数据,则立即返回过期数据给终端用户。

  4. 在结束请求的同时,使用一个异步任务去更新缓存,考虑到并发情况,这里也需要使用一个共享内存锁。

这样,即使在缓存过期的时候,用户也很少会遇到只能从后端server拿数据的情况。所以能节省相当的时间,在速度上有这么大的提升。

后记

这个库运行了有好几个月了,非常的稳定。当然这得益于nginx的稳定。
但是也不得不说,使用这个库之后,后端server能够收到的请求,已经绝大部分都是由那个异步的任务发出的。用户基本都能在缓存里面直接拿到数据。所以,后端server的性能,没有提升,但是给用户的感觉却是快了很多!!!

    原文作者:lloyd_zhou
    原文地址: https://segmentfault.com/a/1190000003874328
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞