網站靜態內容出版解決方案

http://netkiller.github.io/journal/static.html

Mr. Neo Chen (陳景峯), netkiller, BG7NYT


中國廣東省深圳市龍華新區民治街道溪山美地
518131
+86 13113668890


版權聲明

轉載請與作者聯繫,轉載時請務必標明文章原始出處和作者信息及本聲明。

文檔出處:
http://netkiller.github.io
http://netkiller.sourceforge.net

微信掃瞄二維碼進入 Netkiller 微信訂閲號

QQ群:128659835 請註明“讀者”

2017-06-16: 2012-08-24 19:38:17 +0800 (Fri, 24 Aug 2012)

摘要


目錄

1. 架構總覽

www 負責靜態檔案瀏覽, 台數不定, 可以採用零成本的DNS輪詢, 或者4層LVS, 或者7層HAProxy, 還可以用F5, Array 等負載均衡設備.

cms 負責靜態檔案生成. 生成後的檔案要同步到www中, 或者採用網絡共享, 再者使用分散式檔案系統, 總之將生成的檔案交給www伺服器, 根據你壓力橫向擴展即可

img 負責圖片檔案瀏覽. 通過給圖片加版本號, 結局圖片更新問題, 這樣更新網站不用頻繁刷新 CDN

這裡不談論負載均衡, 以及存儲方案, 有情緒可以延伸閲讀: http://netkiller.github.com/architect/index.html

你掌握了這個方案, 你可以很容易實現 向"京東商城", "VANCL凡客誠品", "走秀網" 這樣的網站

這些網站的特點是: 瀏覽量大, 數據存儲主要是圖片, 登錄/註冊與購物車,用戶中心 訪問量只占到 5% 使用負責均衡很容易解決.

靜態化網站可不避免的使用ajax做局部更新, ajax請求也要考慮緩存問題

首次訪問伺服器

  1. 訪問www伺服器

  2. nginx 判斷檔案是否存在,如果存在將檔案顯示出來

  3. 如果檔案不存在,去cms伺服器上查找, 如果存在便返回給www伺服器,並顯示出來

  4. 如果cms上檔案不存在,cms伺服器便使用rewrite生成該檔案, 同時將內容返回給www伺服器,www將內容緩存在自己的伺服器上,並將內容顯示出來

第二次訪問

  1. 訪問www伺服器

  2. nginx 判斷檔案是否存在,如果存在將檔案顯示出來

  3. 如果檔案不存在,去cms伺服器上查找, 如果存在便返回給www伺服器,並顯示出來

  4. 如果cms上檔案不存在,cms伺服器便使用rewrite生成該檔案, 同時將內容返回給www伺服器,www將內容緩存在自己的伺服器上,並將內容顯示出來

2. cdn

如何使用 cdn 來緩存你的網站內容

讓你的網頁緩存在 cdn 節點上的方式有下面幾種

  1. 讓cdn的客服幫你配置緩存的規則, 他們很喜歡一刀切, 例如所有html都緩存2小時

  2. 在他們管理後台自行使用正則配置緩存的時間, 這個他們一般不會提供, 某些公司的CDN會提供這個功能. 非常方便.

  3. 通過HTTP頭自行控制緩存時間, 一般是使用 max-age / s-maxage / Last-Modified 判斷緩存時間

我比較喜歡最後一種, 通常我們使用max-age 與 s-maxage 同時使用, 這樣我可以按照我的意向來決定檔案的緩存時間這裡有更詳細的解釋說明.

3. www 伺服器

下面給出一個精簡後的配置例子

如果檔案不存在就會連接後端cms伺服器生成檔案,並且顯示出來,同時加上緩存. 生成的檔案會從cms中同步到www伺服器上.

你可以採用
  1. rsync同步方案

  2. nfs/samba/gluster 共享方案

  3. iscsi 共享存儲方案

  4. 分散式檔案系統方案

參考閲讀: 分散式檔案系統, Netkiller Linux Storage 手札

		
upstream  cms.mydomain.com  {
  server   192.168.2.11		weight=5	max_fails=3  fail_timeout=30s;
  server   192.168.2.21     weight=5	max_fails=3  fail_timeout=30s;
  server   192.168.2.23 backup;
  server   192.168.2.23 down;
}

server {
    listen       80;
    server_name  www.mydomain.com;

    charset utf-8;
    access_log  /var/log/nginx/www.mydomain.com.access.log  main;

    location / {
        root   /www/mydomain.com/www.mydomain.com;
        index  index.html index.htm;

		if ($request_uri ~* "\.(ico|css|js|gif|jpe?g|png|html)$") {
            expires 1d;
        }
        if ($request_uri ~* "\.(xml|json)$") {
            expires 1m;
        }

		valid_referers none blocked *.mydomain.com;
		if ($invalid_referer) {
			#rewrite ^(.*)$  http://www.mydomain.com/cn/$1;
			return 403;
		}

        proxy_intercept_errors  on;
        if (!-f $request_filename) {
          proxy_pass http://cms.mydomain.com;
          break;
        }
    }

    #error_page  404              /404.html;

    # redirect server error pages to the static page /50x.html
    #
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }

    # deny access to .htaccess files, if Apache's document root
    # concurs with nginx's one
    #
    #location ~ /\.ht {
    #    deny  all;
    #}
}
		
		

4. cms 伺服器

CMS 內容管理系統的主要功能
  1. 內容分類管理

  2. 內容模板管理

  3. 內容編輯與發佈

  4. 內容生成

服務應該實現
  1. 當發現目錄中檔案不存, 通過rewrite生成html, 這樣可能根據需要生成html頁面

  2. 當頁面更新的時候,應該通過api 刷新cdn的緩存, 圖片的版本好應該加一

  3. 將頁面分成多個模組, 通過SSI拼裝頁面, 避免有重大改版時, 整站生成HTML.

  4. 避免使用seesion技術, 這樣在負載均衡的時候可以使用最小連接數算法

例如:

rewrite ^/product/(phone|notebook)/(\d+).html /product/$1.php?id=$2 last;
		

URL 唯一, url設計要考慮唯一性, 不要出現同一個url處理兩個任務, 例如下面的例子, 每個用戶的profile一個URL, 當被訪問的時候便可以緩存在CDN或者用戶瀏覽器上.

		
http://www.mydomain.com/profile/neo.html
http://www.mydomain.com/profile/jam.html
		
		
		
server {
    listen       80;
    server_name  www.mydomain.com;

    #charset koi8-r;
    access_log  /var/log/nginx/www.mydomain.com.access.log  main;

    location / {
        root   /www/mydomain.com/www.mydomain.com;
        index  index.html;
    }
}

server {
    listen       80;
    server_name  cms.mydomain.com;

    charset utf-8;
    access_log  /var/log/nginx/cms.mydomain.com.access.log  main;

    location / {
        root   /www/mydomain.com/cms.mydomain.com;
        index  index.html index.php;

    }

    location ~ ^/(cn|tw)/(comment|affiche)/.*\.html {
		root /www/mydomain.com/www.mydomain.com;
		if (!-f $request_filename) {
			rewrite ^/(cn|tw)/(comment|affiche)/(\d+).html /publish/$2.php?id=$3&lang=$1 last;
		}
    }
    location /xml/ {
		root /www/mydomain.com/www.mydomain.com/xml;
    }
    location ~ ^/(config|include|crontab)/ {
		deny all;
		break;
    }

    #error_page  404              /404.html;

    # redirect server error pages to the static page /50x.html
    #
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }

    # proxy the PHP scripts to Apache listening on 127.0.0.1:80
    #
    #location ~ \.php$ {
    #    proxy_pass   http://127.0.0.1;
    #}

    # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
    #
    location ~ \.php$ {
	root		/www/mydomain.com/cms.mydomain.com;
        fastcgi_pass   127.0.0.1:9000;
        fastcgi_index  index.php;
        fastcgi_param  SCRIPT_FILENAME  /www/mydomain.com/cms.mydomain.com$fastcgi_script_name;
        include        fastcgi_params;
		fastcgi_param  DOCUMENT_ROOT /www/mydomain.com/cms.mydomain.com;
		fastcgi_param  HOSTNAME cms.mydomain.com;
    }

    # deny access to .htaccess files, if Apache's document root
    # concurs with nginx's one
    #
    location ~ /\.ht {
        deny  all;
    }
}
		
		

5. img

img.mydomain.com

		
server {
    listen       80;
    server_name  img.mydomain.com;

    charset utf-8;
    access_log  /var/log/nginx/img.mydomain.com.access.log  main;

    location ~ .*\.(gif|jpg|jpeg|png|bmp|swf|ico)$
    {
		expires      7d;
    }
    location ~ .*\.(js|css)$
    {
		expires      1d;
    }
    location ~ .*\.(html|htm)$
    {
		expires      15m;
    }

    location / {
        root   /img/mydomain.com/img.mydomain.com;
        index  index.html;

        rewrite  "/theme/([0-9] {4})([0-9] {2})([0-9] {2})/(.+)\.(.+)\.(.+)" /theme/$1/$2/$3/$4.$6;
        rewrite  "/news/([0-9] {4})([0-9] {2})([0-9] {2})/(.+)\.(.+)\.(.+)" /news/$1/$2/$3/$4.$6;
        rewrite  "/product/([0-9] {4})([0-9] {2})([0-9] {2})/(.+)\.(.+)\.(.+)" /product/$1/$2/$3/$4.$6;
    }

}
		
		

/theme/2012/08/15/images.1.jpg 實際上就是 /theme/2012/08/15/images.jpg 檔案

/theme/2012/08/15/images.2.jpg 也是 /theme/2012/08/15/images.jpg

/theme/2012/08/15/images.3.jpg 也是 /theme/2012/08/15/images.jpg

但CDN與你的瀏覽器會每次下載新的檔案, 這樣只要更新CDN中的html頁面即可, 不用去理睬圖片, 你的瀏覽器會用新的地址下載圖片. 這樣就解決了煩瑣的刷新工作.

6. Ajax 局部更新與緩存

例如我的新聞評論頁面,需要使用ajax技術, 將用戶回覆的品論顯示來, ajax 載入json數據然後局部更新, 我對他做了1分鐘的緩存

if ($request_uri ~* "\.(xml|json)$") {
	expires 1m;
}
		

如果有新的提交我們可以為json增加版本是控制例如: http://api.mydomain.com/news.json?1.0