微信搜索superit|邀请体验:大数据, 数据管理、OLAP分析与可视化平台 | 赞助作者:赞助作者

Nginx 用 Lua 控制 Fastcgi cache 缓存实现服务优雅降级

未分类 aide_941 76℃

Nginx 用 Lua 控制 Fastcgi cache 缓存实现服务优雅降级
技巧 shanhuhai 10个月前 (06-12) 1907℃ 0评论
如果服务都是动态页面没有做静态化,当某个页面转发很高,访问量很大,可能会有很高的瞬时并发请求进到php-fpm 中,导致数据库和 php-fpm 崩溃。

这种情况下要不就是加服务器提升并发,要不就是优化程序性能,但都是事后手段了。

这里我们提供一种弹性的可以根据用户并发请求量来触发的服务降级方式,请求正常时,缓存并部启用,当并发请求量高时,Nginx 自带的 Fastcgi cache 将被触发启用,将 php-fpm 返回的内容缓存,后续的请求如果是已经被缓存过的请求地址可以将缓存中的内容直接返回,避免了请求进入到 php-fpm 中导致 数据库 和 php-fpm 崩溃。

下面是实现方式:

首先 nginx 要先安装 lua 模块:lua-nginx-module
或者你已经使用了 openresty 也可以

1.创建 nginx 缓存目录

mkdir /tmp/ngx_cache
2.打开 nginx.conf

在 http 块定义一个缓存块,

log_format fs '$remote_addr - $remote_user [$time_local] "$request" '
                  '$status $body_bytes_sent "$http_referer" '
                  '"$upstream_cache_status"';
lua_shared_dict reqqs 10m;
lua_shared_dict cachemap 10m;
fastcgi_cache_path 
    /tmp/ngx_cache
    levels=1:2
    keys_zone=mcontent:1000m
    inactive=20m
    max_size=1g;
    ``` 
log_format 指令用于自定义一个nginx access log 的日志格式,方便我们统计Fastcgi cache的命中率等
lua_shared_dict 用于定义一块共享内存字典,这个字典是在 nginx 的所有worker 都可以共享的, 这里定义了两个共享内存字典,”reqqs” 用于计数单个请求在指定时间段内的请求次数, “cachemap” 用于标记哪些请求地址是要走缓存的

关于 fastcgi_cache_path 指令参考: Nginx 开启Fastcgi 缓存

3. 在 Nginx 的配置中找到解析 php 脚本的 location 块加入以下代码 :
    set $cache_bypass "1";
    set_by_lua $use_cache '
       local function getextension(filename)
            return filename:match(".+%.(%w+)")
       end
       local function stripfilename(filename)
            return string.match(filename, "(.+)%??.*$")
       end

       local reqqs = ngx.shared.reqqs
       local cachemap = ngx.shared.cachemap
       local uri = stripfilename(ngx.var.request_uri)

       -- if request method is not "GET" then bypass
       if ngx.var.request_method ~= "GET" then
            return "1"
       end

       -- check request uri and extension
       local ext = getextension(uri)
       if ext ~= "html" and ext ~= "shtml" and ext ~= "htm" then
            return "1"
       end

       -- if in cache then use cache
       local cached = cachemap:get(uri)
       if cached then
           return "0"
       end

       -- requested 2 times in 1 sec then cache 3 min
       local num = reqqs:get(uri)
       if num then 
            if num >= 2 then
                cachemap:set(uri, 1, 180)
                return "0"
            else
                reqqs:incr(uri,1)
                return "1"
            end
       else
            reqqs:set(uri,1,2)
            return "1"
       end
';

    fastcgi_cache mcontent;
    fastcgi_cache_valid 200 301 302 3m;
    fastcgi_cache_min_uses 1;
    fastcgi_cache_lock on;
    fastcgi_cache_lock_timeout 3s;
    fastcgi_cache_use_stale
        error
        timeout
        invalid_header
        updating
        http_500
        http_503;
    fastcgi_cache_key $request_method://$host$request_uri;
    fastcgi_cache_bypass $use_cache;
    fastcgi_ignore_headers "Cache-Control" "Expires" "Set-Cookie";
    add_header X-Cache-Status $upstream_cache_status;

    access_log /var/log/server/tengine/user.{{domain}}.fs.log fs;

“`
以上脚本实现了所有以 html、 htm、 shtml后缀结尾的请求,如果被1秒内请求了两次,则启用该请求的 fastcgi 缓存 3分钟。

其中比较重要的参数有 fastcgi_cache_lock , 这个参数设为 “on”, 如果多个瞬时并发请求,如果缓存还没有生成,则只有第一个请求会进到 php-fpm 中, 当缓存生成后其他请求再会被响应,这样可以避免缓存失效时,并发请求将php-fpm 压垮。

fastcgi_cache_bypass 用于决定请求是否要走 Fastcgi 缓存, 如果为非0的值则不走缓存。

向春哥的 openresty 致敬.

转载请注明:大后端 » Nginx 用 Lua 控制 Fastcgi cache 缓存实现服务优雅降级

转载请注明:SuperIT » Nginx 用 Lua 控制 Fastcgi cache 缓存实现服务优雅降级

喜欢 (0)or分享 (0)