Nginx 用 Lua 控制 Fastcgi cache 緩存實現服務優雅降級

技巧 shanhuhai 4957℃ 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;

以上腳本實現了所有以 htmlhtmshtml后綴結尾的請求,如果被1秒內請求了兩次,則啟用該請求的 fastcgi 緩存 3分鐘。

其中比較重要的參數有 fastcgi_cache_lock , 這個參數設為 “on”, 如果多個瞬時并發請求,如果緩存還沒有生成,則只有第一個請求會進到 php-fpm 中, 當緩存生成后其他請求再會被響應,這樣可以避免緩存失效時,并發請求將php-fpm 壓垮。

fastcgi_cache_bypass 用于決定請求是否要走 Fastcgi 緩存, 如果為非0的值則不走緩存。

向春哥的 openresty 致敬.

轉載請注明:大后端 » Nginx 用 Lua 控制 Fastcgi cache 緩存實現服務優雅降級

喜歡 (4)or分享 (0)
發表我的評論
取消評論

表情

Hi,您需要填寫昵稱和郵箱!

  • 昵稱 (必填)
  • 郵箱 (必填)
  • 網址
春梓美 种子,av全裸挂历,日本女护士mm裸照写真,超碰地址发布页 <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <文本链> <文本链> <文本链> <文本链> <文本链> <文本链>