版权声明:可以任意转载,转载时请务必以超链接形式标明文章原始出处和作者信息及本声明
http://www.chedong.com/tech/cms.html
关键词:"content manage system" cms path_info cgi php cache squid 内容管理系统 缓存 Cacheable "Search engine friendly"
内容摘要:
你完全不必耐心的看到最后,本文主要说明的是在设计CMS时以下2点注意事项:
- 搜索引擎友好(Search engine Friendly):基于PATH_INFO的参数解析使得动态网页在链接(URI)形式上更像静态的目录结构,大大方便网站内容被搜索引擎收录;
- 可缓存性(Cache Friendly):CMS本身不要过多考虑“效率”问题,只要页面输出设计的比较Cacheable,效率问题可以通过更前端专业的缓存服务器解决。
后面附有一个简单的利用PATH_INFO机制 + SquidWEB加速模式实现PHP动态网页的静态发布的例子,这种轻量级的动态缓存解决方案只需对原有的动态发布系统做少量的修改,从而大大提高原有内容发布系统的重用度。
网站内容静态发布的重要性:Cacheable / Search Engine Friendly
由于一个动态页面的速度往往会比静态页面慢2-10倍,因此对于一个访问量逐步向百万级发展的网站来说,访问速度很快成为一个瓶颈。除了优化内容发布系统的应用本身外,如果能把更新频率比较低的动态页面转存成静态网页来发布,速度上的提升效果将是显著的,而静态网页如果能被缓存在内存里,访问速度更会比原有动态网页有2-3个数量级的提高。
在国外内容管理系统(CMS)已经是一个非常成熟的行业,能够真正支撑大访问的系统中静态页面输出和缓存系统几乎是必须的。
此外随着互联网上的内容以惊人速度的增长也越来越突出了搜索引擎的重要性,如果网站想更好地被搜索引擎收录,网站设计除了面向用户友好(User Friendly)外,面向搜索引擎友好的设计也是非常重要的。链接地址相对固定的静态网页比较适合搜索引擎索引,动态网页后面跟的参数灵活度很大,因此很多搜索引擎都往往会忽略动态页面,比如:对于news.php?day=22&month=03&year=2003,很多搜索引擎可能只索引news.php这个页面一次,更多其他参数的页面可能都会当成相似内容滤掉;我个人一直怀疑在搜索引擎中:即使是同样内容,静态页面往往也比动态网页的PageRank高。
因此,将动态页面转换成静态页面,无论从效率上还是面向搜索引擎友好上,都是一个门户级内容发布系统必须面对的问题。
静态缓存和动态缓存的比较
静态页面的缓存可能有2种形式:
- 静态缓存:是在新内容发布的同时就立刻生成相应内容的静态页面,比如:2003年3月22日,管理员通过后台内容管理界面录入一篇新闻后,就立刻生成http://www.chedong.com/tech/2003/03/22/001.html这个静态页面,并同步更新http://www.chedong.com/tech/index.html这个静态页面上的相关链接。
- 动态缓存:是在新内容发布以后,并不预先生成相应的静态页面,直到对相应内容发出请求时,如果前台缓存服务器找不到相应缓存,就向后台内容管理服务器发出请求,后台系统会生成相应内容的静态页面,用户第一次访问页面时可能会慢一点,但是以后就是直接访问缓存了。
如果去ZDNet等国外网站会发现他们使用的基于Vignette内容管理系统都有这样的页面名称:0,22342566,300458.html。其实这里的0,22342566,300458就是用逗号分割开的多个参数:
第一次访问找不到页面后,相当于会在服务器端产生一个doc_type=0&doc_id=22342566&doc_template=300458的查询,
而查询结果会生成的缓存的静态页面:0,22342566,300458.html
静态缓存的缺点:
- 复杂的触发更新机制:这两种机制在内容管理系统比较简单的时候都是非常适用的。但对于一个关系比较复杂的网站来说,页面之间的逻辑引用关系就成为一个非常非常复杂的问题。最典型的例子就是一条新闻要同时出现在新闻首页和相关的3个新闻专题中,在静态缓存模式中,每发一篇新文章,除了这篇新闻内容本身的页面外,还需要系统通过触发器生成多个新的相关静态页面,这些相关逻辑的触发也往往就会成为内容管理系统中最复杂的部分之一。
- 旧内容的批量更新: 通过静态缓存发布的内容,对于以前生成的静态页面的内容很难修改,这样用户访问旧页面时,新的模板根本无法生效。
在动态缓存模式中,内容管理系统只需要关心各个页面自身,而相关的其他页面链接能自动更新,从而大大减少了设计触发器设计的需要。
VIGNETTE的动态缓存虽然很好,但是一个系统如果设计得太全面其实也是有很大危险的:如果一个频道下文章很多:比如达到十万时,如果生成的静态页面都在一个目录下,对系统文件系统是一个极大的危害,因为一个目录下文件个数超过3000效率就会非常差,甚至连rm *时都会出现too many arguments错误。简单的说,一个好的内容管理系统应该包括:
- 输入:方便的内容录入,所见即所得的编辑界面,权限控制等……
- 输出:方便的模板管理,缓存发布等……
以前做应用的时候也用过一些方式:应用首次访问以后将生成的内容存成一个缓存文件,下次请求时从缓存目录中读取缓存文件,内容更新时,应用把内容从缓存目录中删掉,从而减少对数据库的访问。虽然这样做也能承载比较大的负载,但这样的内容管理和缓存一体的系统是很难分离的。
如果换一个思路:通过一定的分工现内容管理和缓存机制2者的分离,你会发现无论哪一方面可选的余地都是非常大的。甚至有可能利用目前的已经是“功能”比较全面的内容管理系统,而让所有“效率”问题都由前台更专业,而且是很容易分布的缓存服务器解决:可以是通过开放源代码的SQUID做反相代理的WEB加速,可以是专门的缓存硬件设备,甚至是专业的缓存服务商。
动态缓存必须有一个基于静态链接本身的参数解析过程,很多专业内容管理系统系统都是将参数解析机制做成了WEB服务器的模块实现的。
最近看到很多关于面向搜索引擎URL设计优化(URI Pretty)的文章,提到了一种利用PATH_INFO机制将动态网页参数变成像静态网页的形式:
比如可以将: http://www.chedong.com/phpMan.php?mode=man¶meter=ls
变成: http://www.chedong.com/phpMan.php/man/ls
基于PATH_INFO的参数传递:把URI地址用作参数传递
什么是PATH_INFO:
PATH_INFO是一个CGI 1.1的标准,所有直接跟在CGI或动态页面app.cgi后面的"/value_1/value_2"就是PATH_INFO参数:
比如http://www.chedong.com/phpMan.php/man/ls,中:$PATH_INFO = "/man/ls"
这样,我们就可以把以前的HTTP/GET方式的?key=value改为用/value方式来传递,从而实现了动态页面的静态页面形式。而缓存只需要在前端加上一层CACHE服务器,比如:Squid。网站动态内容的动态缓存发布就实现了。
按照这个机制实现的发布系统很好地体现了应用系统的分工:把复杂地内容管理系统分解成:内容输入和缓存这2个相对简单的系统实现。而中间的内容发布通过PATH_INFO解决动态页面的参数传递。
- 后台内容管理系统:专心的将内容发布做好,比如:复杂的工作流管理,复杂的模板规则等……
- 前台页面的缓存管理则可以使用缓存软件(比如前台80端口使用SQUID对后台8080的内容发布管理系统进行缓存),缓存硬件,甚至交给缓存服务商。
______________________ ___________________PATH_INFO是CGI标准,因此PHP Servlet等都有比较好的支持。比如Servlet中就有request.getPathInfo()方法。
|Squid Software cache| |F5 Hardware cache|
---------------------- -------------------
/ /
/ ________________ /
|ASP |JSP |PHP |
PATH_INFO Based Content Manage System
----------------
注意:/myapp/servlet/Hello/foo的getPathInfo()返回的是/foo,而/myapp/dir/hello.jsp/foo的getPathInfo()将返回的/hello.jsp,从这里你也可以知道jsp其实就是一个Servlet的PATH_INFO参数。
PHP中基于PATH_INFO的参数解析的例子如下:
//注意:第一个参数是空的,参数按"/"分割
if ( isset($_SERVER["PATH_INFO"]) ) {
list(day, _SERVER["PATH_INFO"]);
}
如何隐蔽应用:例如.php,的扩展名:
在APACHE中这样配置
<FilesMatch "^app_name$">
ForceType application/x-httpd-php
</FilesMatch>
如何更像静态页面:app_name/my/app.html
解析的PATH_INFO参数的时候,把最后一个参数的最后5个字符“.html”截断即可。
虽然通过修改设置SQUID也可以对带?的动态页面进行缓存,但为了方便搜索引擎索引,还是将参数改成PATH_INFO比较好。
OK,这样以后看见类似于http://www.example.com/article/234这样的网页你就知道其实是article这个php程序生成的动态网页,很多站点表面看上去可能有很多静态目录,其实很有可能都是使用1,2个程序实现的内容发布。比如很多WIKIWIKI系统都使用了这个机制:整个系统就一个简单的wiki程序,而看上去的目录其实都是这个应用拿后面的地址作为参数的查询结果。
利用基于PATH_INFO + CACHE服务器的解决方案对原有的动态发布系统进行改造,可以大大降低旧有系统升级到新的内容管理系统的成本。
动态页面的缓存设计
为了让页面能够比较好的被缓存服务器缓存,最好在HTTP返回的HEADER中加入一些声明,以允许前端服务器缓存。对于Squid缓存服务器:- 页面必须包含Last-Modified: 标记,一般纯静态页面都会有Last-Modified信息,动态页面需要加上
- 如果服务器端有基于HTTP的认证,必须有Cache-Control: public标记
- 最好有Expires或Cache-Control: max-age标记设置页面的过期时间,对于动态页面,通过Expires可以设置各种页面的缓存周期,比如对于新闻首页可以是20分钟,而对于具体的一条新闻页面可能是1天后过期。
- 大访问量的网站应尽可能将动态网页生成静态页面作为缓存发布,甚至对于搜索引擎这样的动态应用来说,缓存机制也是非常非常重要的。
- 利用PATH_INFO机制进行解析参数,实现动态网页链接的美化,方便搜索引擎的索引;
- 在动态页面中利用HTTP Header定义缓存更新策略。
参考资料:
CMS行业观察
http://www.cmswatch.com
CMS讨论邮件列表
http://www.cms-list.org
一个基于PATH_INFO的开源内容管理系统
http://typo3.com/
商业的和开源CMS项目列表:
http://directory.google.com/Top/Computers/Software/Internet/Site_Management/Content_Management/
搜索引擎友好的URL设计
http://www.sitepoint.com/article/485
说不定这个URL原来就是articel.php?id=485
HTTP代理缓存
http://vancouver-webpages.com/proxy.html
可缓存的页面设计
http://linux.oreillynet.com/pub/a/linux/2002/02/28/cachefriendly.html
相关RFC文档:
- RFC 2616:
- section 13 (Caching)
- section 14.9 (Cache-Control header)
- section 14.21 (Expires header)
- section 14.32 (Pragma: no-cache) is important if you are interacting with HTTP/1.0 caches
- section 14.29 (Last-Modified) is the most common validation method
- section 3.11 (Entity Tags) covers the extra validation method
原文出处:<a href="http://www.chedong.com/tech/cms.html">http://www.chedong.com/tech/cms.html</a>