Ubuntu 22.04 Nginx 快取策略設定

Ubuntu 22.04 Nginx Caching Configuration

Nginx 快取概述

Nginx 快取是一種強大的效能優化技術,能夠將後端伺服器的回應暫存於記憶體或磁碟中,減少重複請求對後端的壓力。透過適當的快取策略,可以顯著提升網站的回應速度,降低伺服器負載,並改善整體使用者體驗。

在 Ubuntu 22.04 上設定 Nginx 快取,我們需要了解幾個核心概念:

  • 快取區域 (Cache Zone):定義快取儲存的位置和大小
  • 快取鍵 (Cache Key):決定如何識別和儲存不同的快取項目
  • 快取有效期 (Cache Validity):控制快取內容的存活時間
  • 快取繞過 (Cache Bypass):設定何時不使用快取

快取類型

Proxy Cache

Proxy Cache 用於反向代理情境,當 Nginx 作為前端伺服器代理請求到後端應用程式時使用:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# /etc/nginx/nginx.conf

http {
    # 定義快取區域
    proxy_cache_path /var/cache/nginx/proxy_cache
        levels=1:2
        keys_zone=my_proxy_cache:10m
        max_size=1g
        inactive=60m
        use_temp_path=off;

    server {
        listen 80;
        server_name example.com;

        location / {
            proxy_pass http://backend_server;
            proxy_cache my_proxy_cache;
            proxy_cache_valid 200 302 10m;
            proxy_cache_valid 404 1m;
        }
    }
}

FastCGI Cache

FastCGI Cache 專門用於 PHP-FPM 等 FastCGI 應用程式:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
# /etc/nginx/nginx.conf

http {
    # 定義 FastCGI 快取區域
    fastcgi_cache_path /var/cache/nginx/fastcgi_cache
        levels=1:2
        keys_zone=my_fastcgi_cache:10m
        max_size=1g
        inactive=60m;

    server {
        listen 80;
        server_name example.com;

        location ~ \.php$ {
            fastcgi_pass unix:/var/run/php/php8.1-fpm.sock;
            fastcgi_cache my_fastcgi_cache;
            fastcgi_cache_valid 200 10m;
            include fastcgi_params;
        }
    }
}

設定快取區域

快取區域是 Nginx 快取的基礎設定,需要在 http 區塊中定義:

1
2
3
4
5
6
proxy_cache_path /var/cache/nginx/proxy_cache
    levels=1:2
    keys_zone=main_cache:50m
    max_size=2g
    inactive=120m
    use_temp_path=off;

proxy_cache_path 參數說明

參數說明
/var/cache/nginx/proxy_cache快取檔案儲存路徑
levels=1:2目錄層級結構,1:2 表示兩層子目錄
keys_zone=main_cache:50m快取區域名稱與共享記憶體大小
max_size=2g快取最大磁碟空間
inactive=120m未被存取的快取項目存活時間
use_temp_path=off直接寫入快取目錄,避免額外 I/O

建立快取目錄並設定權限:

1
2
3
sudo mkdir -p /var/cache/nginx/proxy_cache
sudo chown -R www-data:www-data /var/cache/nginx
sudo chmod -R 755 /var/cache/nginx

快取鍵設定

快取鍵決定了如何唯一識別快取項目,預設使用完整的 URL:

1
2
3
4
5
6
7
8
# 預設快取鍵
proxy_cache_key $scheme$proxy_host$request_uri;

# 自訂快取鍵(包含查詢參數)
proxy_cache_key "$scheme$request_method$host$request_uri";

# 忽略特定查詢參數
proxy_cache_key "$scheme$host$uri$is_args$args";

針對不同需求的快取鍵設定範例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
server {
    listen 80;
    server_name example.com;

    location /api/ {
        proxy_pass http://api_backend;
        proxy_cache main_cache;

        # API 快取鍵包含請求方法
        proxy_cache_key "$request_method$scheme$host$request_uri";
    }

    location /static/ {
        proxy_pass http://static_backend;
        proxy_cache main_cache;

        # 靜態資源使用簡單快取鍵
        proxy_cache_key "$uri";
    }
}

快取有效期設定

設定不同 HTTP 狀態碼的快取時間:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
server {
    listen 80;
    server_name example.com;

    location / {
        proxy_pass http://backend;
        proxy_cache main_cache;

        # 依狀態碼設定快取時間
        proxy_cache_valid 200 301 302 10m;
        proxy_cache_valid 404 1m;
        proxy_cache_valid any 5m;

        # 使用後端 Cache-Control 標頭
        proxy_cache_use_stale error timeout updating
            http_500 http_502 http_503 http_504;

        # 快取鎖定,避免驚群效應
        proxy_cache_lock on;
        proxy_cache_lock_timeout 5s;
    }
}

繞過快取條件

某些情況下需要繞過快取,直接從後端取得資料:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
server {
    listen 80;
    server_name example.com;

    # 定義繞過快取的條件
    set $skip_cache 0;

    # 登入使用者不使用快取
    if ($http_cookie ~* "session_id") {
        set $skip_cache 1;
    }

    # POST 請求不使用快取
    if ($request_method = POST) {
        set $skip_cache 1;
    }

    # 管理後台不使用快取
    if ($request_uri ~* "/admin/") {
        set $skip_cache 1;
    }

    location / {
        proxy_pass http://backend;
        proxy_cache main_cache;

        # 套用繞過條件
        proxy_cache_bypass $skip_cache;
        proxy_no_cache $skip_cache;

        # 添加快取狀態標頭
        add_header X-Cache-Status $upstream_cache_status;
    }
}

清除快取

方法一:手動刪除快取檔案

1
2
3
4
5
# 清除所有快取
sudo rm -rf /var/cache/nginx/proxy_cache/*

# 重新載入 Nginx
sudo systemctl reload nginx

方法二:使用 proxy_cache_purge 模組

需要編譯 nginx-cache-purge 模組:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
server {
    listen 80;
    server_name example.com;

    location / {
        proxy_pass http://backend;
        proxy_cache main_cache;
    }

    # 清除快取端點
    location ~ /purge(/.*) {
        allow 127.0.0.1;
        deny all;
        proxy_cache_purge main_cache "$scheme$request_method$host$1";
    }
}

使用 curl 清除特定 URL 的快取:

1
curl -X PURGE http://example.com/purge/path/to/resource

監控快取狀態

添加快取狀態標頭

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
server {
    listen 80;
    server_name example.com;

    location / {
        proxy_pass http://backend;
        proxy_cache main_cache;

        # 顯示快取狀態
        add_header X-Cache-Status $upstream_cache_status always;
        add_header X-Cache-Key $scheme$proxy_host$request_uri always;
    }
}

快取狀態值說明:

狀態說明
HIT快取命中,直接回傳快取內容
MISS快取未命中,從後端取得並快取
EXPIRED快取已過期,從後端重新取得
STALE快取過期但後端不可用,回傳舊快取
UPDATING快取正在更新中
BYPASS快取被繞過

完整設定範例

以下是一個完整的 Nginx 快取設定範例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# /etc/nginx/nginx.conf

user www-data;
worker_processes auto;
pid /run/nginx.pid;

events {
    worker_connections 1024;
}

http {
    include /etc/nginx/mime.types;
    default_type application/octet-stream;

    # 日誌格式包含快取狀態
    log_format cache_log '$remote_addr - $remote_user [$time_local] '
                         '"$request" $status $body_bytes_sent '
                         '"$http_referer" "$http_user_agent" '
                         'cache_status=$upstream_cache_status';

    access_log /var/log/nginx/access.log cache_log;

    # 定義快取區域
    proxy_cache_path /var/cache/nginx/proxy_cache
        levels=1:2
        keys_zone=main_cache:100m
        max_size=5g
        inactive=24h
        use_temp_path=off;

    server {
        listen 80;
        server_name example.com;

        # 快取繞過條件
        set $skip_cache 0;

        if ($request_method = POST) {
            set $skip_cache 1;
        }

        if ($http_cookie ~* "session_id|logged_in") {
            set $skip_cache 1;
        }

        location / {
            proxy_pass http://127.0.0.1:8080;
            proxy_cache main_cache;
            proxy_cache_key "$scheme$request_method$host$request_uri";

            proxy_cache_valid 200 301 302 1h;
            proxy_cache_valid 404 10m;
            proxy_cache_valid any 1m;

            proxy_cache_bypass $skip_cache;
            proxy_no_cache $skip_cache;

            proxy_cache_use_stale error timeout updating
                http_500 http_502 http_503 http_504;
            proxy_cache_lock on;

            add_header X-Cache-Status $upstream_cache_status always;

            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }

        # 靜態資源長期快取
        location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff2?)$ {
            proxy_pass http://127.0.0.1:8080;
            proxy_cache main_cache;
            proxy_cache_valid 200 7d;
            add_header X-Cache-Status $upstream_cache_status always;
            add_header Cache-Control "public, max-age=604800";
        }
    }
}

效能調校建議

  1. 適當設定 keys_zone 大小:每 1MB 約可儲存 8000 個快取鍵
  2. 使用 use_temp_path=off:減少磁碟 I/O
  3. 啟用 proxy_cache_lock:避免多個相同請求同時存取後端
  4. 設定合理的 inactive 時間:平衡記憶體使用與快取效率
  5. 監控快取命中率:透過日誌分析優化快取策略

參考資料

comments powered by Disqus
Built with Hugo
Theme Stack designed by Jimmy