一直使用nginx做为反向代理服务器,一来nginx基于事件驱动,速度快。而来nginx的反向代理模块能很好的支持页面缓存和负载均衡。nginx
nginx有proxy_cache这个内置的缓存功能,是基于文件的。若是把缓存路径设置到RAMDISK上面,能够达到和内存缓存差很少的缓存读写速度。这样作虽然解决了文件读写慢的问题,可是若是分布式部署的时候,这个缓存不能跨机器共享。git
章大神写的这个模块支持和另外一个模块配合将页面缓存写入redis集群。就很好的解决了github
缓存不能跨机器共享的问题redis
也使得缓存大小不受单机资源限制。后端
同时,redis自己还能提供快速的读写速度。缓存
看上面列的几点,彷佛已经很完美了。
可是在实际使用的时候仍是发现有须要改善的地方:服务器
缓存不存在的时候:
第一个请求查询redis失败,到后端,最后还要存储redis。比没有缓存的状况还多出两次redis访问,一次读一次写。并且当并发访问的时候还可能请求都会进入后端服务器,后端不够健壮的时候会致使“雪崩效应”。(若是使用默认的proxy_cache模块还能经过proxy_cache_use_stale命令避免,可是srcache模块没有实现相似功能)并发
缓存失效的时候
一般咱们为页面设置缓存时间,缓存失效的时候,须要从新更新缓存。这个时候也会出现第一种状况相似的问题。负载均衡
以上两种状况,第一种出现较少,第二种状况出现较多。都是因为redis自动删除过时缓存,致使的缓存缺失。异步
因为nginx不知道redis里面数据的缓存时间,因此会频繁的致使缓存缺失的状况出现。
既然知道缘由了,那么我们就来针对性的解决一下这个问题。让nginx可以知道甚至参与到缓存时间的管理里面,就能有效的避免被动的缓存缺失问题,能有意识的主动更新缓存。
这里须要提到一个nginx的第三方模块就是把lua集成到nginx里面扩展了nginx配置文件语法,支持在配置文件里面直接使用lua语言编写逻辑。
我将本身在项目中使用的一个仓库开源到github上面了。
能让nginx主动的检测缓存的过时时间
在快过时的时候,直接返回旧的缓存数据
使用异步任务更新缓存
以上的第二第三两点,就能在缓存快过时的时候,主动的异步更新缓存,让终端用户感知不到更新缓存的过程。
项目中实测,使用这个缓存机制以后,用户感知到的平均响应速度提高了10倍(nginx access log分析结果),而这都是在原有系统性能不变的状况下实现的!是否是有点难以想象。
下面就来讲一说提高速度的原理:
若是缓存缺失,直接跳过srcache_fetch步骤,将请求发到后端server。同时申请一个共享内存锁,并发而来的相同的请求不用发送到后端,而是等待这个请求返回。
更新缓存的时候,在过时时间expire基础上加上一个stale time。那么在到了过时时间的时候,redis还不会当即删掉这个数据。
若是检测到数据过时,可是redis还能拿到这个“过时”数据,则当即返回过时数据给终端用户。
在结束请求的同时,使用一个异步任务去更新缓存,考虑到并发状况,这里也须要使用一个共享内存锁。
这样,即便在缓存过时的时候,用户也不多会遇到只能从后端server拿数据的状况。因此能节省至关的时间,在速度上有这么大的提高。
这个库运行了有好几个月了,很是的稳定。固然这得益于nginx的稳定。可是也不得不说,使用这个库以后,后端server可以收到的请求,已经绝大部分都是由那个异步的任务发出的。用户基本都能在缓存里面直接拿到数据。因此,后端server的性能,没有提高,可是给用户的感受倒是快了不少!!!