Home | Mirror | Search

21. Cache

21.1. CDN (Content Delivery Network) 與反向代理

與CDN有關的開發工作

21.1.1. CDN介面API

CDN 內容更新,一般廠商會提供一個SOAP介面,你可以通過介面刷新你的內容。但介面有限制,不能隨意使用,一般是多少秒可以刷新一次,或者一天可以刷新幾次

21.1.2. 方向代理頁面過期處理

方向代理一般都支持PURGE協議,Squid,Varnish等等向管理連接埠發送 PURGE 即可是使用頁面刷新

PURGE http://netkiller.github.net/index.html
				

有些方向代理如:Varnish 可以使用正則表達式

同時這些代理伺服器都承受管理命令

squid: squidclient

varnish: varnishadm

21.1.3. 內容版本化

例如這樣的URL

http://images.example.com/logo.gif
http://images.example.com/product.jpg
				

我們可以通過Rewrite或PATHINFO等技術做為靜態化。例如首次版本

http://images.example.com/logo.1.gif		=> logo.gif
http://images.example.com/product.1.jpg		=> product.jpg
				

原圖發生變化後,版本遞增

http://images.example.com/logo.2.gif		=> logo.gif
http://images.example.com/product.2.jpg		=> product.jpg
				

就的URL將丟棄

http://images.example.com/logo.1.gif
http://images.example.com/product.1.jpg
				

CDN 就回源去下面的URL,並且取到的是新圖

http://images.example.com/logo.2.gif
http://images.example.com/product.2.jpg
				

21.2. HTTP Cache

Cache-Control

max-age
max-age 格式寫為:max-age=n,n是以秒為單位, 這個值是告知客戶端GMT + N 後頁面過期,緩存伺服器在s-maxage值為空的時候也會使用這個參數的值。

s-maxage
s-maxage的格式跟max-age一樣,只不過他是給緩存伺服器使用的。

must-revalidate
這個參數用來告知客戶端和緩存伺服器,在GET請求的時候必須與源伺服器驗證實體是否為最新版本。

Cache-Control:max-age=1200,s-maxage=3600
			
Last-Modified
這個參數提供了實體最近一次被修改的時間。這個名字起得不錯,當實體被修改了之後,這個參數也就會被修改.
			

ETag

ETag
ETag是根據內容生成的一段hash字元串,採用信息摘要算法,保證每一個頁面有一個唯一字串。
			

expires

expires 是HTTP 1.0 中定義的,已經不能滿足用戶的需要在 HTTP 1.1 加入了max-age,建議使用 max-age替代expires

指令					含義
public				可以在任何地方緩存
private				只能被瀏覽器緩存
no-cache			不能在任何地方緩存
must-revalidate		緩存必須檢查更新版本
proxy-revalidate	代理緩存必須檢查更新版本
max-age				內容能夠被緩存的時期,以秒錶示
s-maxage			覆蓋共享緩存的max-age設置
			

在Squid, Varnish, Apache, Lighttpd, Nginx 中都可是實現HTTP Cache-Control推送,每次修改都需要重新加載,不太靈活。

ExpiresActive On
ExpiresByType image/gif "access plus 1 month"
ExpiresByType image/png "access plus 1 month"
ExpiresByType image/jpeg "access plus 1 month"
ExpiresByType text/css "access plus 1 month"
ExpiresByType text/javascript "access plus 1 month"
ExpiresByType application/x-javascript "access plus 1 month"
ExpiresByType application/x-shockwave-flash "access plus 1 month"


server.modules = (
...
"mod_expire",
...
)

$HTTP["url"] =~ "^/images/" {
expire.url = ( "" => "access 30 days" )
}
			

我喜歡自己控制TTL時間,且每個頁面單獨設置,可以隨時調整設置。

21.2.1. 在程序中靈活操作 Cache-Control

在MVC框架中每個控製器下的方法都可以單獨操作Cache

Class blog extend Controller{
	blog(){
		header('Cache-Control: max-age=28800');
	}
	list(){
		header('Cache-Control: max-age=3600');
	}
	details(){
		header('Cache-Control: max-age=160');
	}
}
				

你還可以封裝到Controller中

Class blog extend Controller{
	blog(){
		this->cache('28800');
	}
	list(){
		this->cache('3600');
	}
	details(){
		this->cache('160');
	}
}
				

21.2.2. 非程序檔案緩存處理

首先做一個Rewrite讓程序接管所有圖片請求

url.rewrite = ( "^/(.+)" => "/index.php/$1" )
				

然後程序通過PATHINFO取出圖片URL

http://images.example.com/your/dir/test.jpg => http://images.example.com/index.php/your/dir/test.jpg
				

程序取出 /your/dir/test.jpg 設置 Content-type 並輸出二進制流

詳細參考

				
<?php
    // Test image.
    $images = '/test/foo.png';

    $headers = apache_request_headers();

    if (isset($headers['If-Modified-Since']) && (strtotime($headers['If-Modified-Since']) == filemtime($images))) {
        header('Last-Modified: '.gmdate('D, d M Y H:i:s', filemtime($images)).' GMT', true, 304);
    } else {
        header('Content-Type: image/png');
        print file_get_contents($fn);
		if (file_exists($images)) {
			header('Last-Modified: '.gmdate('D, d M Y H:i:s', filemtime($images)).' GMT', true, 200);
			header("Cache-Control: max-age=3600, must-revalidate");
			header('Content-Length: '.filesize($images));
			header('Content-type: ' .mime_content_type($images));
			flush();
			readfile($images);
			exit;
		}
    }
				
				

javascript 檔案也可以使用類似方法處理

				
	private function js($file){
		if (file_exists($file)) {
			header("Cache-Control: max-age=3600, must-revalidate");
			header('Content-type: text/javascript');
			flush();
			readfile($file);
			exit;
		}
	}
				
				

21.3. Cache 生存時間

你不必一開始加費勁心機去考慮這個值,當網站運行一段時間後,利用玩站流量數據作為參考,一步一地嘗試調整。

comments powered by Disqus