Home | 简体中文 | 繁体中文 | 杂文 | 知乎专栏 | 视频教程 | bilibili | Github | OSChina 博客 | 云社区 | 云栖社区 | Facebook | Linkedin | 打赏(Donations) | About
知乎专栏多维度架构 | 微信号 netkiller-ebook | 51CTO:视频教程

2.4. 网站静态内容出版

2.4.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请求也要考虑缓存问题

静态化另一个目的是改善SEO

首次访问服务器

  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.4.2. 静态化实现手段有哪些?

静态化方法包括:

  1. 生成方式

  2. 抓取方式

  3. 伪静态化

  4. 混合方式

2.4.2.1. 生成方式

主要由程序实现

例如

			
content = "<html><title>my static</title><body>hello world</body></html>"
file = open( your static file)
file.write(content)
file.close()
			
			

2.4.2.2. 抓取方式

主要由程序实现

程序中抓取

			
content = get_url('http://netkiller.8800.org/index.php')
file = open( index.html)
file.write(content)
file.close()
			
			

使用软件抓取,不仅限于wget。

			
wget http://netkiller.8800.org/index.php -O index.html
			
			

这时只给出简单例子,使用复杂参数实现更复杂的拾取,然后将脚本加入crontab中可。

2.4.2.3. 伪静态化

伪静态化是主要是通过在URL上做一些手脚,使你看去是静态的,实质上它是动态脚本。

伪静态化实现主要包括两种方法:

  1. Rewrite rule

  2. path_info

下面是一个PATH_INFO例子

http://netkiller.8800.org/zh-cn/photography/browse/2009.html

根本就不存在这个目录'zh-cn/photography/browse/'和文件'2009.html'

下面是一个Rewrite例子

http://example.org/bbs/thread-1003872-1-1.html

2.4.2.4. 混合方式

其实目前网站使用的基本上都是上面几种方法混合方式。

例如首先将动态url(example.org/news.php?cid=1&id=1) 通过rewrite转换为 (example.org/new_1_1.html)

接下来就比较容易解决了,一种方法是使用wget example.org/new_1_1.html,另一种方法你无需静态化,直接使用squid规则配置让他永不过期

2.4.2.5. 静态化中的动态内容

在静态化页面中有一些内容是无法实现静态的。像登录信息,用户评论等等

我们用三种方法实现静态中嵌入动态内容:

  1. iframe - 灵活性差

  2. SSI - 消耗web服务器资源

  3. Ajax - 依赖浏览器,稳定性差

2.4.3. cdn

如何使用 cdn 来缓存你的网站内容

让你的网页缓存在 cdn 节点上的方式有下面几种

  1. 让cdn的客服帮你配置缓存的规则, 他们很喜欢一刀切, 例如所有html都缓存2小时

  2. 在他们管理后台自行使用正则配置缓存的时间, 这个他们一般不会提供, 某些公司的CDN会提供这个功能. 非常方便.

  3. 通过HTTP头自行控制缓存时间, 一般是使用 max-age / s-maxage / Last-Modified 判断缓存时间

我比较喜欢最后一种, 通常我们使用max-age 与 s-maxage 同时使用, 这样我可以按照我的意向来决定文件的缓存时间 这里有更详细的解释说明.

2.4.4. 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;
    #}
}
		
		

2.4.5. 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;
    }
}
		
		

2.4.6. 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页面即可, 不用去理睬图片, 你的浏览器会用新的地址下载图片. 这样就解决了烦琐的刷新工作.

2.4.7. Ajax 局部更新与缓存

例如我的新闻评论页面,需要使用ajax技术, 将用户回复的品论显示来, ajax 载入json数据然后局部更新, 我对他做了1分钟的缓存

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

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

网站:http://www.netkiller.cn/ | 知乎:netkiller | 51CTO:视频教程 | Bilibili:netkiller | Github:netkiller