緩存基礎
緩存分類
某些場景下,Nginx
需要通過worker
到上有服務中獲取數據并將結果響應給客戶端,在高并發場景下,我們完全可以將這些數據視為熱點數據,并將其緩存到Nginx
服務上。
-
客戶端緩存:將緩存數據放到客戶端。
優點:數據直接本地獲取,響應快,無網絡開銷
缺點:僅對單一用戶生效 -
服務端緩存:將數據緩存到服務端
優點:有效降低上有服務器壓力,且對所有用戶生效。
缺點: 仍然存在網絡開銷。
所以綜合考慮上述的優缺點,我們建議合理利用緩存,必要時同時開啟客戶端和服務端的緩存。
緩存相關指令及參數含義
proxy_cache
語法: proxy_cache zone |off;
默認值:proxy_cache off;
上下文: http、server、location
作用:在Nginx中實現反向代理響應的緩存功能
proxy_cache_path
語法:proxy_cache_path path [levels=levels] keys_zone=name:size [inactive=time1] [max_size=size2] [loader_files=number] [loader_sleep=time2] [loader_threshold=time3];
默認值:proxy_cache_path:off;
上下文:http
參數含義:
- path:緩存文件存放路徑
- level: path的目錄層級,例如2:2 ,那么目錄就會類似:
/path/to/cache/00
/path/to/cache/01
/path/to/cache/10
/path/to/cache/11
- use_temp_path:若開啟則使用proxy_temp_path的路徑
- key_zone:name是共享名稱,size是共享內存的大小
- inactive:共享內存的值在規定時間內沒有被訪問就會被清理,默認配置為10min
- max_size: 設定最大的緩存文件大小,超過將有CM(cache manager)清理
- manager_files:CM一次清理的最大緩存文件數,默認為100
- manager_sleep:CM清理一次后進程的休眠時間,默認200毫秒
- manager_threshold:CM一次最長耗時,默認50ms
- loader_files:CL載入文件到共享內存每批最多的文件數,默認為100
- loader_sleep:CL加載文件到內存后,進程進入休眠時間,默認200毫秒
- loader_threshold:CL每次載入文件到共享內存的最大耗時,默認50毫秒
proxy_cache_key
語法:proxy_cache_key stirng;
默認值: proxy_cache_key $scheme%proxy_host$request_uir
上下文:http、server、location
作用:指定生成緩存鍵的方式
proxy_cache_valid
語法:proxy_cache_valid [code] time
默認值:無
上下文:http、server、location
配置示例: proxy_cache_valid 60m;
作用:設置緩存的有效時間
upstream_cache_status
作用:用于獲取反向代理請求是否命中緩存。
狀態值:
- MISS:未命中緩存
- HIT:命中緩存
- EXPIRED:緩存過期
- STALE:命中了陳舊的緩存
- REVALIDDATED:nginx驗證陳舊緩存依然有效
- UPDATING:內容陳舊,但正在更新
- BYPASS:響應從原始服務器獲取
我們只需按照下面所示的配置即可打印對應的狀態值:
location / {proxy_cache my_cache;proxy_pass http://backend;proxy_set_header X-Cache-Status $upstream_cache_status;...
}
配置示例
基礎示例
如下圖,我們會訪問服務器1,服務器1的nginx配置了負載均衡,會視情況訪問上游nginx服務器的1010或1011端口
我們先給出不走緩存的基礎配置,配置內容比較簡單,即輪詢不同的上游服務器。
http {include mime.types;default_type application/octet-stream;# 輪詢上游服務器兩個端口upstream cache_server {server 192.168.12.128:1010;server 192.168.12.128:1011;}sendfile on;keepalive_timeout 65;server {listen 80;server_name localhost;location / {proxy_pass http://cache_server;}
}
測試結果,可以看到請求結果每次都會交替指向不同端口的網頁內容(1010,1011分別對應上述兩個上有服務器兩個端口的網頁)
[root@localhost ~]# curl 192.168.12.127:80
1010
[root@localhost ~]# curl 192.168.12.127:80
1011
[root@localhost ~]# curl 192.168.12.127:80
1010
[root@localhost ~]# curl 192.168.12.127:80
1011
[root@localhost ~]# curl 192.168.12.127:80
1010
[root@localhost ~]# curl 192.168.12.127:80
1011
因為這些文件資源,比較固定,所以我們希望nginx能夠將這些網頁緩存起來,于是我們給出走緩存的配置。
需要注意的是,配置完緩存相關的配置之后,筆者為了能夠更直觀的看到緩存命中結果,在http的頭部添加了Nginx-Cache-Status
的值。
http {include mime.types;default_type application/octet-stream;
# 緩存配置,指定緩存路徑、每個目錄有2個層級,每個層級有兩個目錄、定義緩存鍵的共享內存區域名為cache_zone 為30m,最大值為32m,60min后緩存未被使用則會被刪除,并關閉臨時文件存儲proxy_cache_path /usr/local/nginx/cache_temp levels=2:2 keys_zone=cache_zone:30m max_size=32m inactive=60m use_temp_path=off;upstream cache_server {server 192.168.12.128:1010;server 192.168.12.128:1011;}sendfile on;keepalive_timeout 65;server {listen 80;server_name localhost;location / {# 引用上文的緩存配置proxy_cache cache_zone;# 僅對響應200的有效,保存5minproxy_cache_valid 200 5m;
# http請求頭記錄緩存狀態add_header Nginx-Cache-Status "$upstream_cache_status";proxy_pass http://cache_server;}
}
完成后我們重載一下配置,然后嘗試發起請求。可以看到我們往請求頭中放的Nginx-Cache-Status
從MISS
變為HIT
我們鍵入curl命令發起第一個請求,發送一個HEAD請求,并輸出服務器返回的HTTP響應頭信息,而不包括響應體
curl 192.168.12.127:80 -I
從結果來看,第一次的并沒有命中緩存,所以Nginx-Cache-Status返回MISS。
HTTP/1.1 200 OK
Server: nginx/1.10.2
Date: Tue, 19 Jul 2022 15:52:18 GMT
Content-Type: text/html
Content-Length: 5
Connection: keep-alive
Last-Modified: Tue, 19 Jul 2022 15:23:53 GMT
ETag: "62d6cc89-5"
Nginx-Cache-Status: MISS
Accept-Ranges: bytes
再一次curl后就會發現結果變為HIT,由此可知上一次將請求結果緩存,所以本次請求命中了緩存。
HTTP/1.1 200 OK
Server: nginx/1.10.2
Date: Tue, 19 Jul 2022 15:52:19 GMT
Content-Type: text/html
Content-Length: 5
Connection: keep-alive
Last-Modified: Tue, 19 Jul 2022 15:23:53 GMT
ETag: "62d6cc89-5"
Nginx-Cache-Status: HIT
Accept-Ranges: bytes
同樣的,我們也可以通過查看緩存文件夾看到我們緩存的文件
cat /usr/local/nginx/cache_temp/76/d1/608ccf55afd7b17fc84b73d835ecd176
可以看到緩存內容如下,這就是對應的html網頁的參數和內容。
^??b???b2??b?b????
"62d6cc89-5"
KEY: http://cache_server/
HTTP/1.1 200 OK
Server: nginx/1.10.2
Date: Tue, 19 Jul 2022 15:52:18 GMT
Content-Type: text/html
Content-Length: 5
Last-Modified: Tue, 19 Jul 2022 15:23:53 GMT
Connection: close
ETag: "62d6cc89-5"
Accept-Ranges: bytes1010
配置nginx不緩存特定內容
有時候我們希望緩存可以移除一些沒必要的內容,我們就可以基于這些參數做到不緩存某些內容。
proxy_no_cache
語法:proxy_no_cache string;
默認值:無
上下文:http、server、location
作用:用于判斷是否禁用緩存的條件表達式
proxy_cahce_bypass
語法:proxy_cache_bypass string;
默認值:無
上下文:http、server、location
作用:在特定條件下繞過緩存并直接向上游服務器發送請求
配置示例
我們希望txt、text文件不被緩存。對應nginx配置如下,我們只需判斷用戶請求文件是否是txt、text,如果是則添加一個標志變量 $cookie_name
為"no cahe"
,然后proxy_no_cache
看到當前請求存在這個$cookie_name
變量,就不緩存,配置文件示例如下:
http {include mime.types;default_type application/octet-stream;proxy_cache_path /usr/local/nginx/cache_temp levels=2:2 keys_zone=cache_zone:30m max_size=32m inactive=60m use_temp_path=off;upstream cache_server {server 192.168.12.128:1010;server 192.168.12.128:1011;}sendfile on;keepalive_timeout 65;server {listen 80;server_name localhost;# 如果是txt text文件就加個cookir的變量if ($request_uri ~ \.(txt|text)$ ) {set $cookie_name "no cahe";}location / {# 引用上文的緩存配置proxy_cache cache_zone;# 如果有cookie_name這個變量就不換緩存proxy_no_cache $cookie_name;# 僅對響應200的有效proxy_cache_valid 200 5m;
# http請求頭記錄緩存狀態add_header Nginx-Cache-Status "$upstream_cache_status";proxy_pass http://cache_server;}}
測試結果如下可以看到3次curl的及如果都是MISS索命txt文件的請求都不走緩存。
第一次curl請求,返回miss。
[root@localhost ~]# curl 192.168.12.127:80/index.txt -I
HTTP/1.1 200 OK
Server: nginx/1.10.2
Date: Tue, 19 Jul 2022 16:26:03 GMT
Content-Type: text/plain
Content-Length: 5
Connection: keep-alive
Last-Modified: Tue, 19 Jul 2022 16:25:30 GMT
ETag: "62d6dafa-5"
Nginx-Cache-Status: MISS
Accept-Ranges: bytes
第二次請求,還是返回miss。
[root@localhost ~]# curl 192.168.12.127:80/index.txt -I
HTTP/1.1 200 OK
Server: nginx/1.10.2
Date: Tue, 19 Jul 2022 16:26:04 GMT
Content-Type: text/plain
Content-Length: 5
Connection: keep-alive
Last-Modified: Tue, 19 Jul 2022 16:25:17 GMT
ETag: "62d6daed-5"
Nginx-Cache-Status: MISS
Accept-Ranges: bytes
緩存失效降低上游壓力機制
合并源請求
如下圖,三個相同的請求到達nginx,合并源請求做的就是讓紅色的請求去應用服務器獲取結果,其他兩個請求排隊等待,當紅色請求得到結果并緩存到nginx時,他們就不需要去應用服務器拿結果了,直接從緩存中拿到請求結果并返回即可。
相關配置
proxy_cache_lock
當多個客戶端請求一個緩存中不存在的文件(或稱之為一個MISS),只有這些請求中的第一個被允許發送至服務器。其他請求在第一個請求得到滿意結果之后在緩存中得到文件。如果不啟用proxy_cache_lock
,則所有在緩存中找不到文件的請求都會直接與服務器通信。
語法:proxy_cache_lock on|off;默認值:無上下文:http、server、location
proxy_cache_lock_age
語法:proxy_cache_lock_age time;默認值:proxy_cache_lock_age 5s;上下文:http、server、location作用:直緩存鎖的有效期
proxy_cache_lock_timeout
語法:proxy_cache_lock_timeout time;默認值:proxy_cache_lock_timeout 5s;上下文:http、server、location作用:指定等待獲取緩存鎖的超時時間
配置示例
具體配置筆者已詳盡注釋到下文中,讀者可自行參閱。
http {include mime.types;default_type application/octet-stream;proxy_cache_path /usr/local/nginx/cache_temp levels=2:2 keys_zone=cache_zone:30m max_size=32m inactive=60m use_temp_path=off;upstream cache_server {server 192.168.12.128:1010;server 192.168.12.128:1011;}sendfile on;keepalive_timeout 65;server {listen 80;server_name localhost;# 如果是txt text文件就加個cookir的變量if ($request_uri ~ \.(txt|text)$ ) {set $cookie_name "no cahe";}location / {# 引用上文的緩存配置proxy_cache cache_zone;# 如果有cookie_name這個變量就不換緩存proxy_no_cache $cookie_name;# 僅對響應200的有效proxy_cache_valid 200 5m;# http請求頭記錄緩存狀態add_header Nginx-Cache-Status "$upstream_cache_status";# 開啟lockproxy_cache_lock on;# 等待鎖超時時間為5sproxy_cache_lock_timeout 5s;# 鎖有效期為5sproxy_cache_lock_age 5s;proxy_pass http://cache_server;}}
啟用陳舊請求
原理
如下圖,當大量請求到達服務器亦或者上游服務器宕機等問題出現時,nginx支持將陳舊緩存先返回給前端,這種方案使用于對數據一致性要求不高的業務場景。
關鍵配置
proxy_cache_use_stale
:當用戶無法從原始請求中獲取響應或者上游服務器宕機時使用,將陳舊的緩存內容返回給前端
proxy_cache_use_stale error | timeout | invalid_header |
updating | http_500 | http_502 | http_503 | http_504 |
http_403 | http_404 | http_429 | off ...;
默認值: proxy_cache_use_stale off;
上下文: http, server, location可選參數內容含義1. error:與上游建立連接、發送請求、讀取響應頭出錯2. timeout:與商友建立連接、發送請求、讀取響應頭超時3. invalid_header:無效頭部4. updating:緩存過期,正在更新時5. http_500:返回狀態碼5006. http_502:返回狀態碼5007. http_503:返回狀態碼5008. http_504:返回狀態碼500.......
proxy_cache_backgroud_update
:新的緩存更新操作在后臺運行
語法:proxy_cache_backgroud_update on | off;
默認值:proxy_cache_backgroud_update off;
上下文: http、server、location
配置示例
配置實例如下所示,讀者可參考注釋閱讀。
server {listen 80;server_name localhost;#charset koi8-r;#access_log logs/host.access.log main;location / {root html;index index.html index.htm;# 緩存更新在后臺完成proxy_cache_background_update on;# http響應超時 錯誤 緩存更新時返回陳舊緩存proxy_cache_use_stale error timeout updating;}}
第三方清除緩存模塊
我們在上面往緩存中添加了一堆緩存,有時我們希望能夠將其刪除,我們就可以使用第三方模塊進行緩存刪除
首先我們需要下載第三方緩存清除模塊
wget http://labs.frickle.com/files/ngx_cache_purge-2.3.tar.gz
進入nginx安裝文件目錄重新編譯文件,然后再make、make install
./configure --add-module=ngx_cache_purge-2.3 ;make;make install
修改配置文件,如下所示,我們使用clear/需要被清除的文件的資源名
配置如下,例如我們的請求將index.html緩存(proxy_cache_key的配置會將這個緩存結果以host+uri作為key將資源緩存起來)
,那么我們就可以使用/clear/inedx.html
將其清除。
注意配置完成后需要將緩存目錄清楚,再reload
一下。
http {include mime.types;default_type application/octet-stream;proxy_cache_path /usr/local/nginx/cache_temp levels=2:2 keys_zone=cache_zone:30m max_size=32m inactive=60m use_temp_path=off;upstream cache_server {server 192.168.12.128:1010;server 192.168.12.128:1011;}sendfile on;keepalive_timeout 65;server {listen 80;server_name localhost;# 如果是txt text文件就加個cookir的變量if ($request_uri ~ \.(txt|text)$ ) {set $cookie_name "no cahe";}location ~/clear(/.*){# 清楚host+映射變量的緩存proxy_cache_purge cache_zone $host$1;}location / {# 引用上文的緩存配置proxy_cache cache_zone;# 緩存值的keyproxy_cache_key $host$uri;# 如果有cookie_name這個變量就不換緩存proxy_no_cache $cookie_name;# 僅對響應200的有效proxy_cache_valid 200 5m;# http請求頭記錄緩存狀態add_header Nginx-Cache-Status "$upstream_cache_status";# 開啟lockproxy_cache_lock on;# 設置持有鎖的超時時間proxy_cache_lock_timeout 5s;# 超時后多久再嘗試proxy_cache_lock_age 5s;proxy_pass http://cache_server;}error_page 500 502 503 504 /50x.html;location = /50x.html {root html;}}}
完成配置之后,我們不妨重載一下配置進行測試,鍵入如下命令進行第一次請求:
curl 127.0.0.1:80/index.html -I
可以看到第一次結果為MISS
HTTP/1.1 200 OK
Server: nginx/1.10.2
Date: Wed, 20 Jul 2022 13:36:52 GMT
Content-Type: text/html
Content-Length: 5
Connection: keep-alive
Last-Modified: Tue, 19 Jul 2022 15:24:44 GMT
ETag: "62d6ccbc-5"
Nginx-Cache-Status: MISS
Accept-Ranges: bytes
再次請求,HIT
命中緩存
HTTP/1.1 200 OK
Server: nginx/1.10.2
Date: Wed, 20 Jul 2022 13:36:54 GMT
Content-Type: text/html
Content-Length: 5
Connection: keep-alive
Last-Modified: Tue, 19 Jul 2022 15:24:44 GMT
ETag: "62d6ccbc-5"
Nginx-Cache-Status: HIT
Accept-Ranges: bytes
然后我們使用緩存清除地址將其清除
curl 127.0.0.1:80/clear/index.html -I
HTTP/1.1 200 OK
Server: nginx/1.10.2
Date: Wed, 20 Jul 2022 13:36:57 GMT
Content-Type: text/html
Content-Length: 287
Connection: keep-alive
再次發起請求發現,又變成MISS
狀態了。
HTTP/1.1 200 OK
Server: nginx/1.10.2
Date: Wed, 20 Jul 2022 13:37:02 GMT
Content-Type: text/html
Content-Length: 5
Connection: keep-alive
Last-Modified: Tue, 19 Jul 2022 15:23:53 GMT
ETag: "62d6cc89-5"
Nginx-Cache-Status: MISS
Accept-Ranges: bytes
基于nginx配置https請求
簡介
關于https可以看到筆者這篇文章,做了非常詳細的介紹,總的來說https就是客戶端和服務端通過非對稱密鑰協商出一個對稱密鑰來保證數據安全,進而保證后續數據交互安全又高效。
http知識總結
csr/crt/key/pem的區別
- csr全稱是
certificate signing request
,是向CA去申請證書的請求文件的后綴,其中包含了服務器的公鑰和一些基本信息。 - crt是certificate的簡寫,就是最后拿到的證書文件的后綴。
- key是密鑰的后綴,不同工具有不同編碼方式,pem后綴的文件也有可能是證書或者密鑰。
配置示例
由于我們沒有ca,所以我們這里就自己在自己的服務器生成的key文件,模擬ca的私鑰。
openssl genrsa -out ca.key 1024
然后在生成一個向ca申請證書的文件csr
openssl req -new -key ca.key -out ca.csr
使用key文件配置csr文件生成一個crt文件(模擬ca為服務器簽發證書)
openssl x509 -req -days 365 -in ca.csr -signkey ca.key -out ca.crt
nginx配置,注意剛剛的crt文件和key文件都需要放到nginx的conf文件夾
server {listen 443 ssl;server_name localhost;ssl_certificate ca.crt;ssl_certificate_key ca.key;ssl_session_cache shared:SSL:1m;ssl_session_timeout 5m;ssl_ciphers HIGH:!aNULL:!MD5;ssl_prefer_server_ciphers on;location / {root html;index index.html index.htm;}}
測試
完成配置后,重載一下配置進入測試,可以發現HTTPS雖然不受信任,但是可以使用了。
參考文獻
【Django 030】部署到Nginx之配置https:https://blog.csdn.net/Victor2code/article/details/106485814)