-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathstatic.xml
298 lines (267 loc) · 11.8 KB
/
static.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
<?xml version="1.0" encoding="UTF-8"?>
<!-- $Id$ -->
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V5.0//EN"
"/usr/share/xml/docbook/schema/dtd/4.5/docbookx.dtd" [
<!ENTITY article.author.xml SYSTEM "../common/article.author.xml">
<!ENTITY book.info.legalnotice.xml SYSTEM "../common/book.info.legalnotice.xml">
<!ENTITY book.info.abstract.xml SYSTEM "../common/book.info.abstract.xml">
]>
<article xml:base="http://netkiller.sourceforge.net/article/"
xmlns="http://docbook.org/ns/docbook" xml:lang="zh-cn">
<articleinfo>
<title>网站静态内容出版解决方案</title>
<subtitle>http://netkiller.github.io/journal/static.html</subtitle>
&article.author.xml;
&book.info.legalnotice.xml;
<abstract>
<para></para>
</abstract>
&book.info.abstract.xml;
<keywordset>
<keyword>cms</keyword>
<keyword>cdn</keyword>
<keyword>nginx</keyword>
</keywordset>
<pubdate>$Date: 2012-08-24 19:38:17 +0800 (Fri, 24 Aug 2012) $</pubdate>
<releasewww>$Id$</releasewww>
</articleinfo>
<section>
<title>架构总览</title>
<para>www 负责静态文件浏览, 台数不定, 可以采用零成本的DNS轮询, 或者4层LVS, 或者7层HAProxy, 还可以用F5, Array 等负载均衡设备.</para>
<para>cms 负责静态文件生成. 生成后的文件要同步到www中, 或者采用网络共享, 再者使用分布式文件系统, 总之将生成的文件交给www服务器, 根据你压力横向扩展即可</para>
<para>img 负责图片文件浏览. 通过给图片加版本号, 结局图片更新问题, 这样更新网站不用频繁刷新 CDN</para>
<para>这里不谈论负载均衡, 以及存储方案, 有情绪可以延伸阅读: <ulink url="http://netkiller.github.com/architect/index.html" /> </para>
<para>你掌握了这个方案, 你可以很容易实现 向"京东商城", "VANCL凡客诚品", "走秀网" 这样的网站</para>
<para>这些网站的特点是: 浏览量大, 数据存储主要是图片, 登录/注册与购物车,用户中心 访问量只占到 5% 使用负责均衡很容易解决.</para>
<para>静态化网站可不避免的使用ajax做局部更新, ajax请求也要考虑缓存问题</para>
<para>首次访问服务器</para>
<orderedlist>
<listitem><para>访问www服务器</para></listitem>
<listitem><para>nginx 判断文件是否存在,如果存在将文件显示出来</para></listitem>
<listitem><para>如果文件不存在,去cms服务器上查找, 如果存在便返回给www服务器,并显示出来</para></listitem>
<listitem><para>如果cms上文件不存在,cms服务器便使用rewrite生成该文件, 同时将内容返回给www服务器,www将内容缓存在自己的服务器上,并将内容显示出来</para></listitem>
</orderedlist>
<para>第二次访问</para>
<orderedlist>
<listitem><para>访问www服务器</para></listitem>
<listitem><para>nginx 判断文件是否存在,如果存在将文件显示出来</para></listitem>
<listitem><para>如果文件不存在,去cms服务器上查找, 如果存在便返回给www服务器,并显示出来</para></listitem>
<listitem><para>如果cms上文件不存在,cms服务器便使用rewrite生成该文件, 同时将内容返回给www服务器,www将内容缓存在自己的服务器上,并将内容显示出来</para></listitem>
</orderedlist>
</section>
<section>
<title>cdn</title>
<para>如何使用 cdn 来缓存你的网站内容</para>
<para>让你的网页缓存在 cdn 节点上的方式有下面几种</para>
<orderedlist>
<listitem><para>让cdn的客服帮你配置缓存的规则, 他们很喜欢一刀切, 例如所有html都缓存2小时</para></listitem>
<listitem><para>在他们管理后台自行使用正则配置缓存的时间, 这个他们一般不会提供, 某些公司的CDN会提供这个功能. 非常方便.</para></listitem>
<listitem><para>通过HTTP头自行控制缓存时间, 一般是使用 max-age / s-maxage / Last-Modified 判断缓存时间</para></listitem>
</orderedlist>
<para>我比较喜欢最后一种, 通常我们使用max-age 与 s-maxage 同时使用, 这样我可以按照我的意向来决定文件的缓存时间<ulink url="http://netkiller.github.com/architect/architecture/cache.html">这里有更详细的解释说明.</ulink></para>
</section>
<section>
<title>www 服务器</title>
<para>下面给出一个精简后的配置例子</para>
<para>如果文件不存在就会连接后端cms服务器生成文件,并且显示出来,同时加上缓存. 生成的文件会从cms中同步到www服务器上. </para>
<orderedlist>
<title>你可以采用</title>
<listitem><para>rsync同步方案</para></listitem>
<listitem><para>nfs/samba/gluster 共享方案</para></listitem>
<listitem><para>iscsi 共享存储方案</para></listitem>
<listitem><para>分布式文件系统方案</para></listitem>
</orderedlist>
<para>参考阅读: <ulink url="http://netkiller.github.com/architect/architecture/dfs.html">分布式文件系统</ulink>, <ulink url="http://netkiller.github.com/storage/index.html">Netkiller Linux Storage 手札</ulink> </para>
<screen>
<![CDATA[
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;
#}
}
]]>
</screen>
</section>
<section>
<title>cms 服务器</title>
<orderedlist>
<title>CMS 内容管理系统的主要功能</title>
<listitem><para>内容分类管理</para></listitem>
<listitem><para>内容模板管理</para></listitem>
<listitem><para>内容编辑与发布</para></listitem>
<listitem><para>内容生成</para></listitem>
</orderedlist>
<orderedlist>
<title>服务应该实现</title>
<listitem><para>当发现目录中文件不存, 通过rewrite生成html, 这样可能根据需要生成html页面</para></listitem>
<listitem><para>当页面更新的时候,应该通过api 刷新cdn的缓存, 图片的版本好应该加一</para></listitem>
<listitem><para>将页面分成多个模块, 通过SSI拼装页面, 避免有重大改版时, 整站生成HTML.</para></listitem>
<listitem><para>避免使用seesion技术, 这样在负载均衡的时候可以使用最小连接数算法</para></listitem>
</orderedlist>
<para>例如:</para>
<screen>
rewrite ^/product/(phone|notebook)/(\d+).html /product/$1.php?id=$2 last;
</screen>
<para>URL 唯一, url设计要考虑唯一性, 不要出现同一个url处理两个任务, 例如下面的例子, 每个用户的profile一个URL, 当被访问的时候便可以缓存在CDN或者用户浏览器上.</para>
<screen>
<![CDATA[
http://www.mydomain.com/profile/neo.html
http://www.mydomain.com/profile/jam.html
]]>
</screen>
<screen>
<![CDATA[
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;
}
}
]]>
</screen>
</section>
<section>
<title>img</title>
<para>img.mydomain.com</para>
<para></para>
<screen>
<![CDATA[
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;
}
}
]]>
</screen>
<para>/theme/2012/08/15/images.1.jpg 实际上就是 /theme/2012/08/15/images.jpg 文件</para>
<para>/theme/2012/08/15/images.2.jpg 也是 /theme/2012/08/15/images.jpg</para>
<para>/theme/2012/08/15/images.3.jpg 也是 /theme/2012/08/15/images.jpg</para>
<para>但CDN与你的浏览器会每次下载新的文件, 这样只要更新CDN中的html页面即可, 不用去理睬图片, 你的浏览器会用新的地址下载图片. 这样就解决了烦琐的刷新工作.</para>
</section>
<section>
<title>Ajax 局部更新与缓存</title>
<para>例如我的新闻评论页面,需要使用ajax技术, 将用户回复的品论显示来, ajax 载入json数据然后局部更新, 我对他做了1分钟的缓存</para>
<screen>
if ($request_uri ~* "\.(xml|json)$") {
expires 1m;
}
</screen>
<para>如果有新的提交我们可以为json增加版本是控制例如: http://api.mydomain.com/news.json?1.0</para>
</section>
</article>