Nginx反向代理緩存架構設計

朋友站點是CMS門戶類網站經常需要被各種爬蟲蹂躪,服務器亞歷山大。現使用Nginx緩存降低服務器壓力。

首先http段增加

proxy_cache_path /usr/local/nginx/proxy_cache levels=1:2 keys_zone=cache_item:10m max_size=5g inactive=1d;

proxy_cache_path 指定硬盤緩存路徑
levels 緩存目錄最高級別,每層1-2個字符表示。如1:1:2三層
key_cache_zone 緩存名稱及內存塊大小,如cache_item:10m表示聲明一個名稱爲cache_item大小爲10m.超出大小後最早的數據被清楚
max_size 緩存區硬盤的最大值。超出閒置數據將被清除
inactive 最長閒置時間,如1d,如果一個數據1天沒被請求,則將清除

然後在

        location /  {
                include vhost/proxy.cnf;
                proxy_pass http://backend;
                location ~ ^/(news/articles)/ {
                        add_header x-cache-hit $upstream_cache_status;      #獲取是否被緩存命中
                        proxy_cache cache_item;                                             #緩存的區塊
                        proxy_cache_key $host$uri$is_args$args;                  #緩存的key已url全路徑保存
                        proxy_cache_valid 200 304 12h;                                 #設置狀態碼爲200,304的爲12小時
                        proxy_cache_valid   any 10m;                                     #其他設置爲10分鐘
                        proxy_ignore_headers Cache-Control;                       #注意這裏如果沒有忽略緩存頭部,則可能一直不能命中,而且不會生成緩存目錄
                        #expires 12h;                                                              #設置瀏覽器緩存時間
                        proxy_pass http://backend;
                }

        }

上線之後發現同樣是一個URL,本來PC端訪問顯示的是PC端,移動端顯示的就是移動端的樣式。但是因爲URL是一樣的所以移動端和PC端都亂了,PC端部分顯示的是移動端,移動端顯示的是PC端,咋辦呢?
我們可不可以針對移動端加個標識?

        location / {
                include vhost/proxy.cnf;
                proxy_pass http://backend;
                location ~ ^/(news/articles) {
                        if ($http_user_agent ~* "mobile|android|iphone|ios|iOS"){
                                set $device '/m';        #判斷是否移動端加一個標記
                        }
                        add_header x-cache-hit $upstream_cache_status;
                        proxy_cache cache_item;
                        proxy_cache_key $host$device$uri$is_args$args;    #注意緩存的key在$host後面加了個$device
                        proxy_cache_valid 200 304 12h;
                        proxy_cache_valid 404 5m;
                        proxy_cache_valid   any 10m;
                        proxy_ignore_headers Cache-Control;
                        #expires 12h;
                        proxy_pass http://backend;
                }
        }

如何清除nginx緩存呢?
這個需要用到nginx的第三方模塊ngx_cache_purge(http://labs.frickle.com/nginx_ngx_cache_purge/)

編譯nginx的時候

./configure --user=nobody --group=nobody --prefix=/opt/nginx --with-http_stub_status_module --with-http_ssl_module --with-http_v2_module --with-http_gzip_static_module --with-http_sub_module --with-openssl=../openssl-1.1.0k --add-module=../ngx_cache_purge-2.3

這裏是把最新版本的openssl也自動安裝進來了,同時外掛ngx_cache_purge模塊

        location / {
                include vhost/proxy.cnf;
                proxy_pass http://backend;
                location ~ ^/(news/articles) {
                        if ($http_user_agent ~* "mobile|android|iphone|ios|iOS"){
                                set $device '/m';
                        }
                        add_header x-cache-hit $upstream_cache_status;
                        proxy_cache cache_item;
                        proxy_cache_key $host$device$uri$is_args$args;
                        proxy_cache_valid 200 304 12h;
                        proxy_cache_valid 404 5m;
                        proxy_cache_valid   any 10m;
                        proxy_ignore_headers Cache-Control;
                        #expires 12h;
                        proxy_pass http://backend;
                }
                location ~ ^/purge(/.*) {
                        include trust.conf;
                        proxy_cache_purge cache_item $host$1$is_args$args;
                }

        }

trust.conf文件內容:

        satisfy any;
        allow 127.0.0.1;     #只有127.0.0.1訪問不需要密碼,其餘IP訪問均需要密碼
        deny all;
        auth_basic "JIA Login";
        auth_basic_user_file passwd;

事例:

清除以下URL的緩存:
http://www.abc.com/news/2019/009.html
如果是PC端: http://www.abc.com/purge/news/2019/009.html
如果是移動端:  http://www.abc.com/purge/m/news/2019/009.html

這也是爲何我會按照上面來設計緩存的key。

![](https://s1.51cto.com/images/blog/201907/24/fc0904dd799ad50ae22040e34b47219b.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=)

系統上線後如何瞭解緩存命中率呢?
1.在日誌中增加$upstream_cache_status變量

        log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for" $request_time $upstream_cache_status ';

        access_log  logs/access.log  main;

$upstream_cache_status變量有5個值:

  1. MISS 未命中,請求被傳送到後臺處理
  2. HIT 命中緩存
  3. EXPIRED 緩存已經過期,請求被傳送到後臺處理
  4. UPDATING 正在更新緩存,將使用舊的應答
  5. STALE 後端得到過期的應答

根據在日誌中的記錄我們計算命中率

awk '{if($NF==""HIT"") hit++} END {printf "%.2f%",hit/NR}' access.log

假如需要記錄每天的命中率:

#!/bin/bash
LOG_FILE='/usr/local/nginx/logs/access.log.1'
LAST_DAY=$(date +%F -d "-1 day")
awk '{if($NF==""HIT"") hit++} END {printf "'$LAST_DAY': %d %d %.2f%n", hit,NR,hit/NR}' $LOG_FILE

然後在每天的0點1分計算上一天的

# crontab -l
1 0 * * * /opt/shell/get_ngx_hit.sh >> /usr/local/nginx/logs/hit
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章