A. 從HTTP響應頭看各家CDN緩存技術
從HTTP響應頭看各家CDN緩存技術
從HTTP響應頭看各家CDN緩存技術
由於國內各家電信運營商互聯互通的壁壘,CDN作為互聯網用戶加速的最後一公里,扮演了很重要的角色。
在各家公司大談的異地多活容災上也承擔了用戶分流的重任,看看各家用的東西,結合一些網上的公開資料,也能管中窺豹。
傳統的國內CDN廠家有檔橘:帝聯,網宿,藍汛,快網等
新興的互聯網公司有自家產品對外輸出型和創業公司細分型:BAT都有此產品,還有七牛,又拍,微軟azure等
美國龍頭:Akamai,美國市場大哥,Apple用的也是這個,但Apple的在線服務這么爛,真懷疑是不是Apple把Akamai帶坑裡了。
本文只展示響應頭,有興趣自己深挖。
淘寶
server:Tenginestatus:200timing-allow-origin:*via:cache15.l2et15-1[0,200-0,H],cache35.l2et15-1[0,0],cache3.cn286[0,200-0,H],cache8.cn286[11,0]x-cache:HITTCP_MEM_HITdirn:20:727080716x-swift-cachetime:31535998x-swift-savetime:Fri, 19Aug2016 02:55:13GMT
不用說,淘寶用的是自家阿里CDN, 走Tengine, 返回的響應很友好,甚至告訴你是從內存命中的。
x-swift指明了使用了的具體熱點緩存技術。
關於阿里雲CDN,有很多公開介紹,例如:
文章一: 阿里雲CDN技術演進之路 http://www.slideshare.net/jos...
文章二: 研究下淘寶的swift熱點緩存遷移的事
via:cache46.l2et2[0,200-0,H],cache60.l2et2[0,0],cache7.cn286[0,200-0,H],cache8.cn286[3,0]x-cache:HITTCP_HITdirn:11:60349972x-swift-cachetime:31535950x-swift-savetime:Tue, 28Jun2016 04:04:29GMT
根據 阿里雲官網 解釋:
若:X-Cache:HIT TCP_MEM_HIT 表示命中緩存
若:X-Cache:MISS TCP_MISS 則表示未命中緩存
微信
騰攔拆訊CDN節點:
Server:Qnginx/1.1.1X-Cache-Lookup:HitFromDisktankX-NWS-LOG-UUID:406395d0-7cb8-4630-99cf-8208d04e7750
很明顯,這里告訴大家CDN命中了磁碟緩存上的數據。
一些網上資料查到的解釋:
X-Cache-Lookup:Hit From MemCache 表示命中CDN節點的內存
X-Cache-Lookup:Hit From Disktank 表示命中CDN節點的磁碟
X-Cache-Lookup:Hit From Upstream 表示沒有命中CDN
騰訊CDN起步可能會晚一點,Qcon上一個公開資料:
CDN架構技術之道 http://www.infoq.com/cn/prese...
騰訊還與小米合作,在硬碟版小米路由上推出了一個插件,叫騰訊會員兌換,本質上就是利用小米路由用戶上的硬碟存儲一部分內容,上傳給需要用的用戶,由騰訊計算收益,盤活了家裡閑時的網路資源。
網易雲音樂
Server:nginxX-Via:1.1ngdianxin90:9(CdnCacheServerV2.0)
網易太低調,最近也開始搞網易雲產品了,行衡團但基本查不到什麼公開資料,從響應頭看似乎就是直接用的nginx。
新浪微博
Content-Type:image/gifSINA-LB:==SINA-TS:ZGFkYzk4Y2UgMCAwIDAgOCAwCg==Via:http/1.1 ctc.ningbo.ha2ts4.70 (ApacheTrafficServer/4.2.1.1[cRs f ])X-Via-CDN:f=Edge,s=ctc.ningbo.ha2ts4.70,c=115.231.82.33Age:1X-Via:1.1zjjhdx33:3(Cdn Cache Server V2.0),1.1tzhoudxin37:5(Cdn Cache Server V2.0)Connection:keep-alive
這個返回了Cdn Cache Server V2.0,有多家公司都返回了這個,不知道這是個啥玩意,是不是個開源通用產品呢?Squid Varnish Nginx?
segmantfault:
命中
via:T.101203.R.1, M.ctn-zj-lna-204x-cache:HIT(R) from ctn-zj-lna-204x-request-id:-source:U/200, G/200
緩存MISS
via:T.101195.N.1,T.101163.R.1,V.mix-hz-fdi-163,M.ctn-zj-lna-200x-cache:MISS(S)fromctn-zj-lna-200x-request-id:
在ctn-zj-lna上緩存沒有命中,這個ctn-zj是個CDN集群么?
七牛
訪問該圖片: http://7xt44n.com2.z0.glb.qin...
Response header返回:
X-Log:mc.g;IO:1/304X-Qiniu-Zone:0X-Reqid:90oAABxCoNMaw2wUX-Via:1.1dxxz44:2(Cdn Cache Server V2.0),1.1ngdianxin42:6(Cdn Cache Server V2.0)
用的就是自家產品。
唯品會
Server:vipshop/VbibTransfer-Encoding:chunkedVip-Cache:HITx-amz-delete-marker:falseX-Via:1.1xxxz53:0(CdnCacheServerV2.0),1.1zhdx34:6(CdnCacheServerV2.0)
看Server的響應頭,似乎也應該是自家搭建的CDN,顯示了命中與否。
B. 請問Nginx緩存不起作用的原因,感謝大家。
200:伺服器已成功處理了請求,這表示伺服器提供了請求的內容。=== 如果不想讓代理或瀏覽器緩存,加no-cache參數 add_header Cache-Control no-cache;這樣瀏覽器F5...
C. 求助各位,nginx緩存問題
通過設置nginx的client_max_body_size解決nginx+php上傳大文件的問題局冊:簡毀 用nginx來做webserver的時,上傳大文件時需要攔臘備特別注意client_max_body_size這個參數,否則會中斷在nginx的請求中,在php中是無法記錄到訪問的. 一般上傳大文件流程: 首先修...
D. 關於nginx緩存的原理,求大神解答
打個形象的比喻:
你經營一家購物網站,倉庫在北京局鏈正桐悔。你發一件貨到廣東的話,至少要2-3天。你發一件貨到新疆的話,至少要4-5天。
於是你在廣東建立一個倉庫,常買的貨放在這里一份,這樣做,廣東客戶的發貨都在這里,客戶一天就能收到以貨。再在新疆建立一個倉庫,新疆客戶都在這里發貨,客戶一天就也能收到貨。
如果分倉庫缺貨了,就向北京總喚山倉庫調貨。北京總倉庫也不至於那麼忙,專心發貨到分倉庫就可以了。
E. 如何利用Nginx的緩沖,緩存優化提升性能
使用緩沖釋放後端伺服器
反向代理的一個問題是代理大量用戶時會增加伺服器進程的性能沖擊影響。在大多數情況下,可以很大程度上能通過利用Nginx的緩沖和緩存功能減輕。
當代理到另一台伺服器,兩個不同的連接速度會影響客戶的體驗:
從客戶機到Nginx代理的連接。
從Nginx代理到後端伺服器的連接。
Nginx具有優化這些連接調整其行為的能力。
如果沒有緩沖,數據從代理的伺服器發送並立即開始被發送到客戶。如果假定客戶端很快,緩沖可以關閉而盡快使數據到客戶端,有了緩沖,Nginx 代理將暫時存儲後端的響應,然後按需供給數據給客戶端。如果客戶端是緩慢的,允許Nginx伺服器關閉到後端的連接。然後,它可以處理數據分配到客戶端, 以任何可能的速度。
Nginx默認有緩沖設計,因為客戶端往往有很大的不同的連接速度。我們可以用以下指令調節緩沖行為。可以在HTTP,server或 location位置來設置。重要的是要記住,大小size指令是針對每個請求配置的,所以增加超出你需求會影響你的性能,如果這時有許多客戶端請求:
proxy_buffering:該指令控制緩沖是否啟用。默認情況下,它的值是「on」。
proxy_buffers:該指令控制代理響應緩沖區的數量(第一個參數)和大小(第二個參數)。默認配置是8個緩沖區大小等於一個內存頁(4K或者8K)。增加緩沖區的數目可以讓你緩沖更多信息。
proxy_buffer_size:從後端伺服器的響應頭緩沖區大小,它包含headers,和其他部分響應是分開的。該指令設置響應部分的緩沖區大小。默認情況下,它和proxy_buffers是相同的尺寸,但因為這是用於頭信息,這通常可以設置為一個較低的值。
proxy_busy_buffers_size:此指令設置標注「client-ready」緩沖區的最大尺寸。而客戶端可以一次讀取來自一個緩沖區的數據,緩沖被放置在隊列中,批量發送到客戶端。此指令控制允許是在這種狀態下的緩沖空間的大小。
proxy_max_temp_file_size:這是每個請求能用磁碟上臨時文件最大大小。這些當上游響應太大不能裝配到緩沖區時被創建。
proxy_temp_file_write_size:這是當被代理伺服器的響應過大時Nginx一次性寫入臨時文件的數據量。
proxy_temp_path:當上游伺服器的響應過大不能存儲到配置的緩沖區域時,Nginx存儲臨時文件硬碟路徑。
正如你所看到的,Nginx提供了相當多的不同的指令來調整緩沖行為。大多數時候,你不必擔心太多,但它對於調整一些值可能是有用的。可能最有用的調整是proxy_buffers和proxy_buffer_size指令。
一個例子:、
proxy_busy_buffers_size 8k;
proxy_max_temp_file_size 2048m;
proxy_temp_file_write_size 32k;
proxy_pass http://example.com;
配置代理服務緩存來減少響應時間
盡管緩沖可以幫助釋放後端伺服器以處理更多的請求,Nginx還提供了一種方法來緩存從後端伺服器的內容,對於許多請求無需連接到上游。
配置代理緩存
要設置緩存用於代理內容,我們可以使用proxy_cache_path指令。這將創建區域保存來自被代理伺服器返回的數據。該proxy_cache_path指令必須在HTTP上下文部分進行設置。
在下面的例子中,我們將配置一些相關的指令來建立我們的緩存系統。
# http context
proxy_cache_path /var/lib/nginx/cache levels=1:2 keys_zone=backcache:8m max_size=50m;
proxy_cache_key "$scheme$request_method$host$request_uri$is_args$args";
proxy_cache_valid 200 302 10m;
proxy_cache_valid 404 1m;
用proxy_cache_path指令,我們首先應該已經定義在文件系統中希望存儲緩存的目錄。在這個例子中,我們選擇在/var/lib/nginx/cache目錄。如果該目錄不存在,你可以用正確的許可權和所有權創建它:
sudo mkdir -p /var/lib/nginx/cache
sudo chown www-data /var/lib/nginx/cache
sudo chmod 700 /var/lib/nginx/cache
levels=參數指定緩存將如何組織。 Nginx將通過散列鍵(下方配置)的值來創建一個緩存鍵。我們選擇了上述的levels決定了單個字元目錄(這是散列值的最後一個字元)配有兩個字元的 子目錄(下兩個字元取自散列值的末尾)將被創建。你通常不必對這個細節關注,但它可以幫助Nginx快速找到相關的值。
keys_zone=參數定義緩存區域的名字,我們稱之為backcache。這也是我們定義多少元數據存儲的地方。在這個例子里,我們是存儲8 MB的key。對於每兆位元組,Nginx可存儲8000左右的條目。MAX_SIZE參數設置實際緩存數據的最大尺寸。
我們使用上面的另一個指令是proxy_cache_key。這個設置將設置用於存儲緩存值的鍵。此鍵用於檢查是否一個請求可以從高速緩存提供服務。我們將它設置成方案(http或https),HTTP請求方法,以及被請求的主機和URI的組合。
proxy_cache_valid指令可以被指定多次。它依賴於狀態代碼值使我們能夠配置多長時間存儲。在我們的例子中,我們對於後端返回200和302存儲10分鍾,404響應的一分鍾過期。
現在,我們已經配置了緩存區,但我們仍然需要告訴Nginx什麼時候使用緩存。
在我們代理到後端的location位置,我們可以配置使用這個緩存:
# server context
location /proxy-me {
proxy_cache backcache;
proxy_cache_bypass $http_cache_control;
add_header X-Proxy-Cache $upstream_cache_status;
proxy_pass http://backend;
}
使用proxy_cache指令,就可以指定該backcache緩存區被用於這個位置。 Nginx會在這里檢查傳遞給後端有效的條目。
上述proxy_cache_bypass指令被設置為$ http_cache_control變數。這將包含一個指示器,用以指示該客戶端是否被明確地請求一個最新的,非緩存版本。設置此指令允許Nginx正確處理這些類型的客戶端請求。無需進行進一步的配置。
我們還增加了被稱為X-Proxy-Cache的額外頭。我們設置這個頭部為$ upstream_cache_status變數的值。這個設置頭,使我們能夠看到,如果請求導致高速緩存命中,高速緩存未命中,或者高速緩存被明確旁 路。這是對於調試特別有價值,也對客戶端是有用的信息。
關於緩存結果的注意事項
高速緩存能夠極大地提高代理伺服器的性能。不過,也需要明確的考慮配置緩存時候,要記住。
首先,任何用戶相關的數據不應被高速緩存。這可能導致一個用戶的數據被呈現給其他用戶。如果你的網站是完全靜態的,這可能不是一個問題。
如果你的網站有一些動態元素,你將不得不考慮到這一點。你如何處理要看是什麼應用程序或伺服器處理的後端處理。對於私人的內容,你應該設置Cache-Control頭為「no-cache」,「no-sotre」,或者「private」依賴於數據的性質:
no-cache:
請求: 告知緩存者,必須原原本本的轉發原始請求,並告知任何緩存者,需要去轉發請求,並驗證緩存(如果有的話).對應名詞:端對端重載.
響應: 允許緩存者緩存副本.那麼其實際價值是,總是強制緩存者,校驗緩存的新鮮度.一旦確認新鮮,則可以使用緩存副本作為響應. no-cache,還可以指定某個包含欄位,比如一個典型應用,no-cache=Set-Cookie. 這樣做的結果,就是告知緩存者,對於Set-Cookie欄位,你不要使用緩存內容.而是使用新滴.其他內容則可以使用緩存
no-store:表示在任何時候收到的數據不被緩存。這對於私人數據是最安全,因為它意味著,該數據必須從伺服器每次進行檢索。
private:這表明共享的緩存空間不能緩存此數據。這可以用於指示用戶的瀏覽器高速緩存數據,但代理伺服器不應當考慮隨後的請求數據有效。
public:這表明該響應是可在連接的任何點被高速緩存的公共數據。
一個相關的可以控制此行為報頭是max-age頭,其指示,任何資源應該緩存的秒數。
根據內容的敏感性,正確設置這些頭,會幫助你利用緩存優勢,同時保持你的私人數據安全,並使您的動態數據最新。
如果你的後端也使用Nginx,你可以設置使用過期指令,設置max-age來實現Cache-Control:
location / {
expires 60m;
}
location /check-me {
expires -1;
}
在上面的例子中,第一個塊允許緩存一個小時的內容。第二塊設置Cache-Control頭為「無緩存」。要設置其他值,可以使用add_header指令,就像這樣:
location /private {
expires -1;
add_header Cache-Control "no-store";
}
F. Nginx緩存設置教程
| 這篇文章主要介紹了Nginx緩存設置案例詳解,本篇文章通過簡要的案例,講解了該項技術的了解與使用,以下就是詳細內容,需要的朋友可以參考下 |
在開發調試web的時候,經常會碰到因瀏覽器緩存(cache)而經常要去清空緩存或者強制刷新來測試的煩惱,提供下apache不緩存配置和nginx不緩存配置的設置。在常用的緩存設置裡面有兩種方式,都是使用add_header來設置:分別為Cache-Control和Pragma。
對於站點中不經常修改的靜態內容(如圖片,JS,CSS),可以在伺服器中設置expires過期時間,控制瀏覽器緩存,達到有效減小帶寬流量,降低伺服器壓力的目的。
以Nginx伺服器為例:
【背景】:Expires是Web伺服器響應消息頭欄位,在響應http請求時告訴瀏覽器在過期時間前瀏覽器可以直接從瀏覽器緩存取數據,而無需再次請求。
【相關資料】
1、Cache-control策略
Cache-Control與Expires的作用一致,都是指明當前資源的有效期,控制瀏覽器是否直接從瀏覽器緩存取數據還是重新發請求到伺服器取數據。只不過Cache-Control的選擇更多,設置更細致,如果同時設置的話,其優先順序高於Expires。
http協議頭Cache-Control :
值可以是public、private、no-cache、no- store、no-transform、must-revalidate、proxy-revalidate、max-age
各個消息中的指令含義如下:
Last-Modified/If-Modified-Since
其最終達到的就是等效於設置這三類html緩存技術:
G. nginx緩存(proxy_cache模塊)
緩存的基本思想是利用客戶端訪問的時間局限性,將客戶端訪問過的內容做一個副本,在一定時間內存放到本地,當改數據下次被訪問時,不必連接到後端伺服器反復去查詢數據,而是由本地保存的副本響應數據。
保存在本地的這些副本具有一個過期時間,超過該時間將會更新。判斷一個副本數據是否為過期數據的辦法有很多,可以使用保留時間來判斷,也可以使用數據完整度來判斷。
許多Web伺服器還具有校驗功能,就是當某些副本數據過期以後,先向後端伺服器發送校驗請求,後端伺服器對這些數據進行校驗,如果發現原數據和副本沒有差別,則將過期副本重新置為可用副本。
以上nginx配置結合使用:
proxy_params文件的配置如下:
訪問一次頁面,並向 http://www.blogs-s.com:8080/api/ 發起一個介面數據請求,查看/cache/nginx目錄下的緩存結果:
ngx_cache_purge是nginx的第三方模塊,能夠幫助我清除nginx中的緩存。
在之前的nginx編譯安裝中我們是沒有把緩存的清除模塊ngx_cache_purge編譯進去的,如果啟動了緩存,沒有安裝這個模塊,在之後的調試中我們嘗試去清除緩存時,將會出現異常:
這個異常是在指示我們,找不到該指令的驅動,需要按照相關模塊。
ngx_cache_purge只是nginx的第三方模塊,並不是某個特殊的軟體,所以我們需要對nginx重新進行編譯,操作如下:
配置nginx:
再一次啟動nginx成功;
接下來進行緩存清除測試,訪問: http://blogs.com/clear_cache/api/index.php , 訪問這個連接將會清除介面: http://blogs.com/api/index.php 的緩存數據。
結果如下:
在項目開發中,不可能出現什麼都需要緩存的數據,緩存僅僅適合去緩存查詢頻繁,但是不需要實時更新的數據,這個是它適合的場景,而我們上面的配置,只要是訪問api介面目錄就會緩存介面的數據,這樣對於一些需要實時更新的介面數據來說是不合理的,需要控制好nginx的緩存去緩存什麼以及不緩存什麼
set 指令為變數設置,proxy_no_cache參數中的值可以設置多個,但是多個值中,只要有一個是不為0的,就會通過緩存響應數據。
該指令用於配置一塊公用的內存區域的名稱,該區域可以存放緩存的索引數據。這些數據在Nginx伺服器啟動時由緩存索引重建進程負責建立,在Nginx伺服器的整個運行過程中由緩存管理進程負責定時檢測過期數據,檢索等管理工作。
該指令用於配置Nginx伺服器向客戶端發送響應數據時,不從緩存中獲取的條件。這些條件支持使用Nginx 配置的常用變數。
看一個例子:
其中,Scookie_nocache、Sarg_nocache、Sarg_comment、Shttp_pragma 和Shttp_authorization 都是Nginx配置文件的變數,
該指令用於設置Nginx伺服器在內存中為緩存數據建立索引時使用的關鍵字
如果我們希望緩存數據包含伺服器主機名稱等關鍵字,則可以將該指令設置為:
該指令用於設置是否開啟緩存的鎖功能。在緩存中,某些數據項可以同時被多個請求返回的響應數據填充。開啟該功能後,Nginx伺服器同時只能有一個請求填充緩存中的某一數據項,這相當於給該數據項上鎖,不允許其他請求操作。其他的請求如果也想填充該項,必須等待該數據項的鎖被釋放。這個等待時間由 proxy_cache_lock_timeout 指令配置。
該指令用於設置緩存的鎖功能開啟以後鎖的超時時間。具體細節參見proxy_cache_lock 指令的相關內容
其中,time為設置的時間,默認為5s。
該指令用於設置客戶端請求發送的次數,當客戶端向被代理伺服器發送相同請求達到該指令設定的次數後,Nginx伺服器才對該請求的響應數據做緩存。合理設置該值可以有效地降低硬碟上緩存數據的數量,並提高緩存的命中率。
其中,number為設置的次數。默認設置為1。
該指令用於設置Nginx伺服器存儲緩存數據的路徑以及和緩存索引相關的內容
該指令設置比較復雜,一般需要設置前面三個指令的情形比較多,後面的幾個變數與Nginx伺服器緩存索引重建進程及管理進程的性能相關,一般情況下保持默認設置就可以了。我們來看幾個簡單的配置實例:
如果Nginx在訪問被代理伺服器過程中出現被代理的伺服器無法訪問或者訪問錯誤等現象時,Nginx伺服器可以使用歷史緩存響應客戶端的請求,這些數據不一定和被代理伺服器上最新的數據相一致,但對於更新頻率不高的後端伺服器來說,Nginx伺服器的該功能在一定程度上能夠為客戶端提供不間斷訪問。該指令用來設置一些狀態,當後端被代理的伺服器處於這些狀態時,Nginx伺服器啟用該功能。
該指令可以支持的狀態如語法結構中所示。
該指令可以針對不同的HTTP響應狀態設置不同的緩存時間,
該指令同於配置在什麼情況下不使用cache功能
該指令配置是否在本地磁碟緩存來自被代理伺服器的響應數據。這是Nginx伺服器提供的另一種緩存數據的方法,但是該功能相對 Proxy Cache簡單一些,它不提供緩存過期更新、內存索引建立等功能,不佔用內存空間,對靜態數據的效果比較好。
Proxy Store方法多使用在被代理伺服器端發生錯誤的情況下,用來緩存被代理伺服器的響應數據。
該指令用於設置用戶或用戶組對Proxy Store緩存的數據的訪問許可權,
有關Proxy Store方法的使用,我們通過官方給出的實例加深理解,在該實例中筆者通過注釋對配置做了說明:
H. nginx 緩存機制
Nginx緩存的基本思路
基本思想是利用客戶訪問的時間局部性原理,對客戶已經訪問過的內容在Nginx伺服器本地建立副本,這樣在一段時間內再次訪問該數據,就不需要通過Nginx伺服器再次向後端伺服器發出請求,所以能夠減少Nginx伺服器與後端伺服器之間的網路流量,減輕網路擁塞,同時還能減小數據傳輸延遲,提高用戶訪問速度。同時,當後端伺服器宕機時,Nginx伺服器上的副本資源還能夠回應相關的用戶請求,這樣能夠提高後端伺服器的魯棒性。
對於緩存,我們大概會有以下問題:
(1)緩存文件放在哪兒?
(2)緩存的空間大小是否可以限定?
(3)如何指定哪些請求被緩存?
(4)緩存的有效期是多久?
(5)對於某些請求,是否可以不走緩存?
解決這些問題後,nginx的緩存也就基本配置完成了,下面看詳細配置過程
開啟緩存
要使用緩存,首先要使用 proxy_cache_path 這個指令(必須放在 http 上下文的頂層位置),然後在目標上下文中使用 proxy_cache 指令
配置示例
proxy_cache_path 有兩個必填參數,第一個參數為 緩存目錄,第二個參數keys_zone指定緩存名稱和佔用內存空間的大小(註:示例中的10m是對內存中緩存內容元數據信息大小的限制,如果想限制緩存總量大小,需要用 max_size 參數)
proxy_cache 的參數為之前指定的緩存名稱
緩存管理的相關進程
在緩存工作中有兩個附加進程:
(1)緩存管理器
定期檢查緩存狀態,看緩存總量是否超出限制,如果超出,就移除其中最少使用的部分
(2)緩存載入器
載入器只在nginx啟動後運行一次,把緩存內容的元數據信息載入到內存空間,如果一次性載入全部緩存信息,會大量消耗資源,使nginx在啟動後的幾分鍾里變慢,為避免此問題,有3種載入策略:
loader_threshold – 指定每次載入執行的時間
loader_files – 每次最多載入的數量
loader_sleeps – 每次載入的延時
例如:
proxy_cache_path /data/nginx/cache keys_zone=one:10m loader_threshold=300 loader_files=200;
指定緩存哪些請求
nginx默認會緩存所有 get 和 head 方法的請求結果,緩存的key默認使用請求字元串
(1)自定義key
例如 proxy_cache_key " request_uri cookie_nocache arg_comment;
如果任何一個參數值不為空,或者不等於0,nginx就不會查找緩存,直接進行代理轉發
綜合示例
nginx 緩存機制
三分鍾看懂Nginx伺服器的緩存原理和機制
I. 如何統計nginx前端緩存的命中率
location / {
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_connect_timeout 180;
proxy_send_timeout 180;
proxy_read_timeout 180;
proxy_buffer_size 128k;
proxy_buffers 4 128k;
proxy_busy_buffers_size 128k;
proxy_temp_file_write_size 128k;
proxy_cache cache;
proxy_cache_valid 200 304 1h;
proxy_cache_valid 404 1m;
proxy_cache_key $uri$is_args$args;
add_header Nginx-Cache "$upstream_cache_status";
proxy_pass http://backend;
J. 何時部署要啟動lua nginx
Lua是一個可以嵌入到Nginx配置文件中的動態腳本語言,從而可以在Nginx請求處理的任何階段執行各種Lua代碼。剛開始我們只是用Lua 把請求路由到後端伺服器,但是它對我們架構的作用超出了我們的預期。下面就講講我們所做的工作。
強制搜索引擎只索引mixlr.com
Google把子域名當作完全獨立的網站,我們不希望爬蟲抓取子域名的頁面,降低我們的Page rank
location /robots.txt {
rewrite_by_lua '
if ngx.var.http_host ~= "mixlr.com" then
return ngx.exec("/robots_disallow.txt");
end
';
}
如果對robots.txt的請求不是mixlr.com域名的話,則內部重寫到robots_diallow.txt,雖然標準的重寫指令也可以實現這個需求,但是 Lua的實現更容易理解和維護。
根據程序邏輯設置響應頭
Lua提供了比Nginx默認配置規則更加靈活的設置方式。 在下面的例子中,我們要保證正確設置響應頭,這樣瀏覽器如果發送了指定請求頭後,就可以 無限期緩存靜態文件,是的用戶只需下載一次即可。
這個重寫規則使得任何靜態文件,如果請求參數中包含時間戳值,那麼就設置相應的Expires和Cache-Control響應頭。
location / {
header_filter_by_lua '
if ngx.var.query_string and ngx.re.match( ngx.var.query_string, "^([0-9]{10})$" ) then
ngx.header["Expires"] = ngx.http_time( ngx.time() + 31536000 );
ngx.header["Cache-Control"] = "max-age=31536000";
end
';
try_files $uri @dynamic;}
刪除jQuery JSONP請求的時間戳參數
很多外部客戶端請求JSONP介面時,都會包含一個時間戳類似的參數,從而導致Nginx proxy緩存無法命中(因為無法忽略指定的HTTP參數)。下面的 規則刪除了時間戳參數,使得Nginx可以緩存upstream server的響應內容,減輕後端伺服器的負載。
location / {
rewrite_by_lua '
if ngx.var.args ~= nil then
-- /some_request?_=1346491660 becomes /some_request
local fixed_args, count = ngx.re.sub( ngx.var.args, "&?_=[0-9]+", "" );
if count > 0 then
return ngx.exec(ngx.var.uri, fixed_args);
end
end
';}
把後端的慢請求日誌記錄到Nginx的錯誤日誌
如果後端請求響應很慢,可以把它記錄到Nginx的錯誤日誌,以備後續追查。
location / {
log_by_lua '
if tonumber(ngx.var.upstream_response_time) >= 1 then
ngx.log(ngx.WARN, "[SLOW] Ngx upstream response time: " .. ngx.var.upstream_response_time .. "s from " .. ngx.var.upstream_addr);
end
';}
基於Redis的實時IP封禁
某些情況下,需要阻止流氓爬蟲的抓取,這可以通過專門的封禁設備去做,但是通過Lua,也可以實現簡單版本的封禁。
lua_shared_dict banned_ips 1m;
location / {
access_by_lua '
local banned_ips = ngx.shared.banned_ips;
local updated_at = banned_ips:get("updated_at");
-- only update banned_ips from Redis once every ten seconds:
if updated_at == nil or updated_at < ( ngx.now() - 10 ) then
local redis = require "resty.redis";
local red = redis:new();
red:set_timeout(200);
local ok, err = red:connect("your-redis-hostname", 6379);
if not ok then
ngx.log(ngx.WARN, "Redis connection error retrieving banned_ips: " .. err);
else
local updated_banned_ips, err = red:smembers("banned_ips");
if err then
ngx.log(ngx.WARN, "Redis read error retrieving banned_ips: " .. err);
else
-- replace the locally stored banned_ips with the updated values:
banned_ips:flush_all();
for index, banned_ip in ipairs(updated_banned_ips) do
banned_ips:set(banned_ip, true);
end
banned_ips:set("updated_at", ngx.now());
end
end
end
if banned_ips:get(ngx.var.remote_addr) then
ngx.log(ngx.WARN, "Banned IP detected and refused access: " .. ngx.var.remote_addr);
return ngx.exit(ngx.HTTP_FORBIDDEN);
end
';}
現在就可以阻止特定IP的訪問:
1
ruby> $redis.sadd("banned_ips", "200.1.35.4")
Nginx進程每隔10秒從Redis獲取一次最新的禁止IP名單。需要注意的是,如果架構中使用了Haproxy這樣類似的負載均衡伺服器時, 需要把$remote_addr設置為正確的遠端IP地址。
這個方法還可以用於HTTP User-Agent欄位的檢查,要求滿足指定條件。
使用Nginx輸出CSRF(form_authenticity_token)
Mixlr大量使用頁面緩存,由此引入的一個問題是如何給每個頁面輸出會話級別的CSRF token。我們通過Nginx的子請求,從upstream web server 獲取token,然後利用Nginx的SSI(server-side include)功能輸出到頁面中。這樣既解決了CSRF攻擊問題,也保證了cache能被正常利用。
location /csrf_token_endpoint {
internal;
include /opt/nginx/conf/proxy.conf;
proxy_pass "http://upstream";}
location @dynamic {
ssi on;
set $csrf_token '';
rewrite_by_lua '
-- Using a subrequest, we our upstream servers for the CSRF token for this session:
local csrf_capture = ngx.location.capture("/csrf_token_endpoint");
if csrf_capture.status == 200 then
ngx.var.csrf_token = csrf_capture.body;
-- if this is a new session, ensure it sticks by passing through the new session_id
-- to both the subsequent upstream request, and the response:
if not ngx.var.cookie_session then
local match = ngx.re.match(csrf_capture.header["Set-Cookie"], "session=([a-zA-Z0-9_+=/+]+);");
if match then
ngx.req.set_header("Cookie", "session=" .. match[1]);
ngx.header["Set-Cookie"] = csrf_capture.header["Set-Cookie"];
end
end
else
ngx.log(ngx.WARN, "No CSRF token returned from upstream, ignoring.");
end
';
try_files /maintenance.html /rails_cache$uri @thin;}
CSRF token生成 app/metal/csrf_token_endpoint.rb:
class CsrfTokenEndpoint
def self.call(env)
if env["PATH_INFO"] =~ /^\/csrf_token_endpoint/
session = env["rack.session"] || {}
token = session[:_csrf_token]
if token.nil?
token = SecureRandom.base64(32)
session[:_csrf_token] = token
end
[ 200, { "Content-Type" => "text/plain" }, [ token ] ]
else
[404, {"Content-Type" => "text/html"}, ["Not Found"]]
end
endend
我們的模版文件示例:
<meta name="csrf-param" value="authenticity_token"/>
<meta name="csrf-token" value="<!--# echo var="csrf_token" default="" encoding="none" -->"/>
Again you could make use of lua_shared_dict to store in memory the CSRF token for a particular session. This minimises the number of trips made to /csrf_token_endpoint.