﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-jinfeng_wang-随笔分类-website</title><link>http://www.blogjava.net/jinfeng_wang/category/44697.html</link><description>G-G-S,D-D-U!</description><language>zh-cn</language><lastBuildDate>Fri, 16 Apr 2010 07:16:22 GMT</lastBuildDate><pubDate>Fri, 16 Apr 2010 07:16:22 GMT</pubDate><ttl>60</ttl><item><title>谈谈网站静态化 zz</title><link>http://www.blogjava.net/jinfeng_wang/archive/2010/04/16/318519.html</link><dc:creator>jinfeng_wang</dc:creator><author>jinfeng_wang</author><pubDate>Fri, 16 Apr 2010 06:34:00 GMT</pubDate><guid>http://www.blogjava.net/jinfeng_wang/archive/2010/04/16/318519.html</guid><wfw:comment>http://www.blogjava.net/jinfeng_wang/comments/318519.html</wfw:comment><comments>http://www.blogjava.net/jinfeng_wang/archive/2010/04/16/318519.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jinfeng_wang/comments/commentRss/318519.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jinfeng_wang/services/trackbacks/318519.html</trackback:ping><description><![CDATA[<h2 style="margin: 13pt 0cm"><span style="font-family: 黑体"><font style="font-size: 18pt" color="#000000">写在前头</font></span></h2>
<p style="margin: 0cm 0cm 0pt"><font size="3"><font color="#000000"><span style="font-family: 宋体">静态化是解决减轻网站压力</span>,<span style="font-family: 宋体">提高网站访问速度的常用方案</span>,<span style="font-family: 宋体">但在强调交互的</span>We2.0 <span style="font-family: 宋体">时代</span>,<span style="font-family: 宋体">对静态化提出了更高的要求</span>,<span style="font-family: 宋体">静态不仅要能静</span>,<span style="font-family: 宋体">还要能动</span>,<span style="font-family: 宋体">下面我通过一个项目</span>,<span style="font-family: 宋体">谈谈网站静态化后的架构设计方案</span>,<span style="font-family: 宋体">同时和大家探讨一下</span>,<span style="font-family: 宋体">在开源产品大行其道</span>,<span style="font-family: 宋体">言架构必称</span>MemberCache, Nginx,<span style="font-family: 宋体">的时代</span>,<span style="font-family: 宋体">微软技术在网站架构设计中的运用</span>.</font></font></p>
<h2 style="margin: 13pt 0cm"><span style="font-family: 黑体"><font style="font-size: 18pt" color="#000000">静态化的设计原则和步骤</font></span></h2>
<p style="margin: 0cm 0cm 0pt"><font size="3"><font color="#000000"><span style="font-family: 宋体">静态化是解决减轻网站压力</span>,<span style="font-family: 宋体">但是静态化也会带来一系列的问题</span>,<span style="font-family: 宋体">包括开发上复杂度的增加</span>,<span style="font-family: 宋体">维护难度的增加</span>,<span style="font-family: 宋体">运用不的当</span>,<span style="font-family: 宋体">更可能适得其反</span>,<span style="font-family: 宋体">而许多替代方案</span>,<span style="font-family: 宋体">比如页面缓存</span>,<span style="font-family: 宋体">如果运用得当</span>,<span style="font-family: 宋体">也能起到很好的效果</span>,<span style="font-family: 宋体">所以在开始之前</span>,<span style="font-family: 宋体">必须进行详细的考察</span>,<span style="font-family: 宋体">确定是否适合静态化</span>,<span style="font-family: 宋体">并制定适合的静态化方式</span>,<span style="font-family: 宋体">下面先介绍一下</span></font></font></p>
<p style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt"><font color="#000000"><span style="font-family: Wingdings"><font size="3">l</font><span style="font: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal; x-system-font: none">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><strong><span style="font-family: 宋体"><font size="3">考查读写比</font></span></strong><font size="3">:</font></font></p>
<p style="margin: 0cm 0cm 0pt 21pt"><font size="3"><font color="#000000"><span style="font-family: 宋体">读写比</span>,<span style="font-family: 宋体">准确的说是读写负荷比</span>,<span style="font-family: 宋体">是否值得静态化的最终考虑</span>,<span style="font-family: 宋体">由于一般写入的压力明显大于读出的压力</span>,<span style="font-family: 宋体">如果写入太频繁</span>,<span style="font-family: 宋体">或者每次写入消耗的资源太多</span>,<span style="font-family: 宋体">都不能达到效果</span>,<span style="font-family: 宋体">我觉得读写比例</span>10:1<span style="font-family: 宋体">应该是个上限</span>.<span style="font-family: 宋体">具体情况需要根据自己的业务逻辑判断</span></font></font></p>
<p style="margin: 0cm 0cm 0pt"><font color="#000000" size="3">&nbsp;</font></p>
<p style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt"><font color="#000000"><span style="font-family: Wingdings"><font size="3">l</font><span style="font: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal; x-system-font: none">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><strong><span style="font-family: 宋体"><font size="3">确定页面呈现的内容是否适合静态化</font></span></strong><font size="3">:</font></font></p>
<p style="margin: 0cm 0cm 0pt 21pt"><font size="3"><font color="#000000"><span style="font-family: 宋体">在设计方案时</span>,<span style="font-family: 宋体">必须详细考虑每个原型页面</span>,<span style="font-family: 宋体">找到页面上展示的信息</span>,<span style="font-family: 宋体">和他的更新方式</span>,<span style="font-family: 宋体">更新时机</span>,<span style="font-family: 宋体">更新频率</span>,<span style="font-family: 宋体">一定要注意那些不起眼的信息</span>,<span style="font-family: 宋体">他们可能左右你的设计</span>,</font></font></p>
<p style="margin: 0cm 0cm 0pt; text-indent: 21pt"><font size="3"><font color="#000000"><span style="font-family: 宋体">比如</span>:<span style="font-family: 宋体">我们以</span>CSDN<span style="font-family: 宋体">的论坛的任意一篇帖子为例</span>,<span style="font-family: 宋体">进行分析</span></font></font></p>
<p style="margin: 0cm 0cm 0pt; text-indent: 21pt"><font size="3"><font color="#000000"><span style="font-family: 宋体"><span style="font-family: 黑体"><font color="#000000"><img style="width: 361px; height: 385px" height="466" alt="" src="http://p.blog.csdn.net/images/p_blog_csdn_net/yizhu2000/EntryImages/20080901/topic.JPG" width="512" /></font></span></span></font></font></p>
<p style="margin: 0cm 0cm 0pt; text-indent: 21pt"><font size="3"><font color="#000000"><span style="font-family: 宋体">上面的帖子中呈现的内容主要是这样几块</span>,<span style="font-family: 宋体">帖子内容</span>,<span style="font-family: 宋体">回复内容</span>,<span style="font-family: 宋体">发帖人回复人的用户信息</span></font></font></p>
<p style="margin: 0cm 0cm 0pt 42pt; text-indent: -21pt"><font color="#000000"><span style="font-family: Wingdings"><font size="3">n</font><span style="font: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal; x-system-font: none">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="font-family: 宋体"><font size="3">帖子内容和回复内容在发帖时更新</font></span><font size="3">,</font><span style="font-family: 宋体"><font size="3">发帖后用户可以修改其内容</font></span><font size="3">,</font><span style="font-family: 宋体"><font size="3">更新频率高</font></span></font></p>
<p style="margin: 0cm 0cm 0pt 42pt; text-indent: -21pt"><font color="#000000"><span style="font-family: Wingdings"><font size="3">n</font><span style="font: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal; x-system-font: none">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="font-family: 宋体"><font size="3">用户信息</font></span><font size="3">,</font><span style="font-family: 宋体"><font size="3">用户修改个人信息时可能会发生更改</font></span><font size="3">,</font><span style="font-family: 宋体"><font size="3">用户等级增加时也可能发生更改</font></span><font size="3">,</font><span style="font-family: 宋体"><font size="3">比如加星</font></span><font size="3">,</font><span style="font-family: 宋体"><font size="3">更新频率低</font></span></font></p>
<p style="margin: 0cm 0cm 0pt 42pt; text-indent: -21pt"><font color="#000000"><span style="font-family: Wingdings"><font size="3">n</font><span style="font: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal; x-system-font: none">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="font-family: 宋体"><font size="3">回复数将每次回复后都要更改</font></span><font size="3">,</font><span style="font-family: 宋体"><font size="3">更新频率高</font></span></font></p>
<p style="margin: 0cm 0cm 0pt 42pt; text-indent: -21pt"><font color="#000000"><span style="font-family: Wingdings"><font size="3">n</font><span style="font: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal; x-system-font: none">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="font-family: 宋体"><font size="3">设计时要注意细节</font></span><font size="3">,</font><span style="font-family: 宋体"><font size="3">如上图中圈出来的部分</font></span><font size="3">,</font><span style="font-family: 宋体"><font size="3">这些部分是怎么修改的</font></span><font size="3">,</font><span style="font-family: 宋体"><font size="3">频率有多大</font></span><font size="3">,</font><span style="font-family: 宋体"><font size="3">一个都不能放过</font></span><font size="3">.</font></font></p>
<p style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt"><font color="#000000"><span style="font-family: Wingdings"><font size="3">l</font><span style="font: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal; x-system-font: none">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><strong><font size="3"><span style="font-family: 宋体">确定生成方式</span>:</font></strong></font></p>
<p style="margin: 0cm 0cm 0pt 21pt"><font size="3"><font color="#000000"><span style="font-family: 宋体">在上面帖子一例中</span>.<span style="font-family: 宋体">每次更改都重新生成页面是不可取的</span>,<span style="font-family: 宋体">一篇比回复数多的帖子</span>,<span style="font-family: 宋体">需要的数据量是巨大的</span>(<span style="font-family: 宋体">每层楼的用户信息</span>,<span style="font-family: 宋体">回复内容</span>),<span style="font-family: 宋体">任何修改</span>,<span style="font-family: 宋体">都需要重新取出数据进行生成是不能允许的</span>.<span style="font-family: 宋体">一般除非你的页面基本不用更新</span>,<span style="font-family: 宋体">或者更新开销极小</span>,(<span style="font-family: 宋体">比如一段嵌入的广告代码</span>)<span style="font-family: 宋体">才能采用整体更新的方式</span>,<span style="font-family: 宋体">不然就需要我们找到合适的更新页面局部区域的方法</span>:</font></font></p>
<p style="margin: 0cm 0cm 0pt 21pt"><font size="3"><font color="#000000"><span style="font-family: 宋体">一般有下面两个方法</span>:</font></font></p>
<p style="margin: 0cm 0cm 0pt 39pt; text-indent: -18pt"><font color="#000000"><strong><font size="3">1)</font><span style="font: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal; x-system-font: none">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></strong><strong><font size="3"><span style="font-family: 宋体">正则修改法</span>:</font></strong></font></p>
<pre><font size="3"><font color="#000000"><font face="宋体">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 比如,如果帖子中的回复数,html代码是这样</font></font></font></pre>
<pre><font size="3"><font color="#000000"><font face="宋体">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;label&gt;回复数&lt;var id="replyCount"&gt;34&lt;/var&gt;&lt;/label&gt;</font></font></font></pre>
<pre><font size="3"><font color="#000000"><font face="宋体">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 我们可以通过用下面正则来查找并替换计数</font></font></font></pre>
<pre><font size="3"><font color="#000000"><font face="宋体">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  (?&lt;=id="replyCount"&gt;)"d{1,}</font></font></font></pre>
<p style="margin: 0cm 0cm 0pt 39pt; text-indent: -18pt"><font color="#000000"><strong><font size="3">2)</font><span style="font: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal; x-system-font: none">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></strong><strong><font size="3"><span style="font-family: 宋体">页面区域分块</span>:</font></strong></font></p>
<p style="margin: 0cm 0cm 0pt 21pt"><font size="3"><font color="#000000"><span style="font-family: 宋体">把页面分成很多小块</span>,<span style="font-family: 宋体">在显示时组装起来</span>,<span style="font-family: 宋体">比如</span>DotText<span style="font-family: 宋体">就采用这个方法</span></font></font></p>
<p style="margin: 0cm 0cm 0pt 21pt"><font size="3"><font color="#000000"><span style="font-family: 宋体"><span style="font-family: 宋体"><img height="441" alt="" src="http://p.blog.csdn.net/images/p_blog_csdn_net/yizhu2000/EntryImages/20080901/blog.JPG" width="379" /></span></span></font></font></p>
<p style="margin: 0cm 0cm 0pt 21pt"><font size="3"><font color="#000000"><span style="font-family: 宋体">这是一篇典型的</span>Dottext blog<span style="font-family: 宋体">页面</span>,<span style="font-family: 宋体">其中红色标定部分是一个独立的文件</span>,<span style="font-family: 宋体">而黄色框内的是脚本动态加载</span>,<span style="font-family: 宋体">这些部分在最终显示的时候组合起来</span>,<span style="font-family: 宋体">最终构成了一篇</span>Blog,<span style="font-family: 宋体">具体的组合方法也有多种</span>,<span style="font-family: 宋体">可以使用</span>Include,<span style="font-family: 宋体">也可以自己来实现</span>.DotText<span style="font-family: 宋体">就自己实现了一套加载机制</span></font></font></p>
<p style="margin: 0cm 0cm 0pt 21pt"><font color="#000000" size="3">&nbsp;</font></p>
<p style="margin: 0cm 0cm 0pt 21pt"><font size="3"><font color="#000000"><span style="font-family: 宋体">上面的两种方法并不孤立</span>,<span style="font-family: 宋体">并可以根据需要</span>,<span style="font-family: 宋体">配合使用</span></font></font></p>
<p style="margin: 0cm 0cm 0pt 21pt"><font color="#000000" size="3">&nbsp;</font></p>
<p style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt"><font color="#000000"><span style="font-family: Wingdings"><font size="3">l</font><span style="font: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal; x-system-font: none">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><strong><font size="3"><span style="font-family: 宋体">确定需要动态加载的信息</span>:</font></strong></font></p>
<p style="margin: 0cm 0cm 0pt 21pt"><font size="3"><font color="#000000"><span style="font-family: 宋体">页面上总有一些内容看起来不太适合静态化</span>,<span style="font-family: 宋体">最典型的是一些统计结果</span>,<span style="font-family: 宋体">比如如果你在做一个图书介绍页面</span>,<span style="font-family: 宋体">可能就会需要展示图书的当天综合评分</span>,<span style="font-family: 宋体">或者书籍排名</span>,<span style="font-family: 宋体">这些内容需要用脚本进行动态加载</span></font></font></p>
<p style="margin: 0cm 0cm 0pt 21pt"><font size="3"><font color="#000000"><span style="font-family: 宋体">既然做了静态化</span>,<span style="font-family: 宋体">就是希望减少服务器负载</span>,<span style="font-family: 宋体">动态加载的数据总是不得已而为之</span>,<span style="font-family: 宋体">有的时候在需求允许的情况下</span>,<span style="font-family: 宋体">我们在数据在实时性和性能方面做一些妥协</span>,<span style="font-family: 宋体">比如上面帖子中的用户星级和昵称</span>,<span style="font-family: 宋体">从数据实时性上说</span>,<span style="font-family: 宋体">当用户的星级增长</span>,<span style="font-family: 宋体">他发言的所有帖子都应该发生变化</span>,<span style="font-family: 宋体">所以应该用动态加载</span>.<span style="font-family: 宋体">然而其实上这些信息如果不发生变化</span>,<span style="font-family: 宋体">也无伤大雅</span>,<span style="font-family: 宋体">用户反而能够看到自己在多年前发帖时的级别和昵称</span>.</font></font></p>
<h2 style="margin: 13pt 0cm"><span style="font-family: 黑体"><font style="font-size: 18pt" color="#000000">现实中的项目</font></span></h2>
<p style="margin: 0cm 0cm 0pt; text-indent: 21.75pt"><font size="3"><font color="#000000">X<span style="font-family: 宋体">网站是大型的电影资讯</span>,<span style="font-family: 宋体">电影社区</span>,<span style="font-family: 宋体">向外提供电影相关信息服务</span>,<span style="font-family: 宋体">以及用户社区</span>,<span style="font-family: 宋体">其中信息服务部分</span>, <span style="font-family: 宋体">其中大部分页面属于信息呈现页</span>,<span style="font-family: 宋体">读取量比较大</span>,<span style="font-family: 宋体">百万级别</span>pv,<span style="font-family: 宋体">信息主要由编辑在后台发布</span>,<span style="font-family: 宋体">更新较少</span>,<span style="font-family: 宋体">但其页面上有大量的交互性的内容</span>,<span style="font-family: 宋体">比如评论</span>,<span style="font-family: 宋体">收藏列表</span>,<span style="font-family: 宋体">同时许多内容允许用户创造</span>,<span style="font-family: 宋体">比如上传图片</span>,<span style="font-family: 宋体">添加注释</span>.<span style="font-family: 宋体">交互内容的数量和交互的频繁程度</span>,<span style="font-family: 宋体">都超过了普通的咨询页面</span>,<span style="font-family: 宋体">这次调整</span>,<span style="font-family: 宋体">准备将其中访问量最大的几块</span>:<span style="font-family: 宋体">电影资料页</span>,<span style="font-family: 宋体">影人资料页</span>,<span style="font-family: 宋体">进行静态化</span>,<span style="font-family: 宋体">如果成功</span>,<span style="font-family: 宋体">还将运用到更多的频道</span>,<span style="font-family: 宋体">基本实现全站静态化</span></font></font></p>
<p style="margin: 0cm 0cm 0pt; text-indent: 21.75pt"><font color="#000000" size="3">&nbsp;</font></p>
<p style="margin: 0cm 0cm 0pt"><font size="3"><font color="#000000"><span style="font-family: 宋体">通过对页面设计和前一版本的分析</span>,<span style="font-family: 宋体">下面是具有挑战性的地方</span>.<span style="font-family: 宋体">这些特点基本使用于大多数</span>web2.0<span style="font-family: 宋体">的站点</span>,<span style="font-family: 宋体">很具有典型意义</span></font></font></p>
<p style="margin: 0cm 0cm 0pt"><font color="#000000" size="3">&nbsp;</font></p>
<p style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt"><font color="#000000"><span style="font-family: Wingdings"><font size="3">l</font><span style="font: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal; x-system-font: none">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><strong><font size="3"><span style="font-family: 宋体">页面生成的触发条件复杂</span></font></strong></font></p>
<p style="margin: 0cm 0cm 0pt"><font size="3"><font color="#000000"><span style="font-family: 宋体">一般论坛中的帖子或者</span>blog,<span style="font-family: 宋体">更新方式比较单一</span>:<span style="font-family: 宋体">主要是由回复进行触发还有少数的修改动作</span>,<span style="font-family: 宋体">然而该网站一个页面上需要根据不同触发条件就有</span>20<span style="font-family: 宋体">多个</span>, <span style="font-family: 宋体">比如光二级菜单</span>:<span style="font-family: 宋体">用户发布图片</span>,<span style="font-family: 宋体">删除图片</span>,<span style="font-family: 宋体">发布或者删除影片信息</span>,<span style="font-family: 宋体">发布或者修改视频</span>,<span style="font-family: 宋体">后台修改电影信息</span>,<span style="font-family: 宋体">都有可能触发</span></font></font></p>
<p style="margin: 0cm 0cm 0pt"><font color="#000000" size="3">&nbsp;</font></p>
<p style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt"><font color="#000000"><span style="font-family: Wingdings"><font size="3">l</font><span style="font: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal; x-system-font: none">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><strong><font size="3"><span style="font-family: 宋体">一个动作触发生成的页面可能很多而且相互交叠</span></font></strong></font></p>
<p style="margin: 0cm 0cm 0pt"><font size="3"><font color="#000000"><span style="font-family: 宋体">每一个动作都会触发一系列的生成</span>,<span style="font-family: 宋体">并且不同动作可能都会涉及同一个页面或者区域的生成</span>.</font></font></p>
<p style="margin: 0cm 0cm 0pt"><font size="3"><font color="#000000"><span style="font-family: 宋体">比如</span>:<span style="font-family: 宋体">用户给一步电影评分</span>,<span style="font-family: 宋体">需要生成评分更多页</span>,<span style="font-family: 宋体">评分统计更多页</span>,<span style="font-family: 宋体">首页右侧谁还关注此影片小区域</span>,<span style="font-family: 宋体">等等</span>.<span style="font-family: 宋体">用户收藏一个影片</span>,<span style="font-family: 宋体">也需要更新首页右侧谁还关注此影片小区域</span></font></font></p>
<p style="margin: 0cm 0cm 0pt"><font color="#000000" size="3">&nbsp;</font></p>
<p style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt"><font color="#000000"><span style="font-family: Wingdings"><font size="3">l</font><span style="font: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal; x-system-font: none">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><strong><font size="3"><span style="font-family: 宋体">触发频繁</span>:</font></strong></font></p>
<p style="margin: 0cm 0cm 0pt"><font size="3"><font color="#000000"><span style="font-family: 宋体">虽然不及某些更大规模的网站</span>,<span style="font-family: 宋体">但是由于涉及众多用户参与的内容</span>,<span style="font-family: 宋体">评论</span>,<span style="font-family: 宋体">收藏等等</span>,<span style="font-family: 宋体">触发点多</span>,<span style="font-family: 宋体">发生频度相当频繁</span></font></font></p>
<p style="margin: 0cm 0cm 0pt"><font color="#000000" size="3">&nbsp;</font></p>
<p style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt"><font color="#000000"><span style="font-family: Wingdings"><font size="3">l</font><span style="font: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal; x-system-font: none">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><strong><font size="3"><span style="font-family: 宋体">页面多</span>,</font></strong><strong><font size="3"><span style="font-family: 宋体">结构复杂</span>,</font></strong><strong><font size="3"><span style="font-family: 宋体">空间占用大</span>:</font></strong></font></p>
<p style="margin: 0cm 0cm 0pt"><font size="3"><font color="#000000"><span style="font-family: 宋体">通常</span>,<span style="font-family: 宋体">需要生成的页面规模是这样粗略估算的</span>,Rn*P,Rn<span style="font-family: 宋体">为资源数</span>,P<span style="font-family: 宋体">为每个资源的页面数</span>,<span style="font-family: 宋体">所谓资源</span>,<span style="font-family: 宋体">可以看做一个生成单位</span>,<span style="font-family: 宋体">其页面数可以简单看做发布一个资源</span>,<span style="font-family: 宋体">就需要生成其所有相关页面数量</span>,<span style="font-family: 宋体">比如</span>:<span style="font-family: 宋体">发布一个</span>blog,<span style="font-family: 宋体">就需要生成一个</span>Blog<span style="font-family: 宋体">页</span>,<span style="font-family: 宋体">同时还需要生成或者更新个人主页的</span>blog<span style="font-family: 宋体">列表</span>,<span style="font-family: 宋体">算上个人主页右侧的分类文章数的小块</span>,<span style="font-family: 宋体">也就是最多</span>10<span style="font-family: 宋体">来个页面或者区域</span>,<span style="font-family: 宋体">但是发布一个电影</span>,<span style="font-family: 宋体">其相关的页面至少有</span>50<span style="font-family: 宋体">个以上</span>,<span style="font-family: 宋体">而且有的页面还带有分页</span>,<span style="font-family: 宋体">一个信息比较丰富的电影</span>,<span style="font-family: 宋体">其页面竟可以达到千个以上</span>,<span style="font-family: 宋体">空间</span>10~20M,<span style="font-family: 宋体">而且资源总数也不少</span>,<span style="font-family: 宋体">电影</span>80000<span style="font-family: 宋体">左右</span>,<span style="font-family: 宋体">电影人虽然</span>P<span style="font-family: 宋体">值较少</span>,<span style="font-family: 宋体">但是总量确有几十万之巨</span>,<span style="font-family: 宋体">估计静态页面磁盘占用量几百个</span>G</font></font></p>
<p style="margin: 0cm 0cm 0pt"><font color="#000000" size="3">&nbsp;</font></p>
<p style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt"><font color="#000000"><span style="font-family: Wingdings"><font size="3">l</font><span style="font: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal; x-system-font: none">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><strong><font size="3"><span style="font-family: 宋体">向下兼容</span></font></strong></font></p>
<p style="margin: 0cm 0cm 0pt"><font size="3"><font color="#000000"><span style="font-family: 宋体">这是一个已有系统</span>,<span style="font-family: 宋体">旧系统的框框需要突破</span>,<span style="font-family: 宋体">但又没有时间</span>,<span style="font-family: 宋体">或者不能完全突破</span>,<span style="font-family: 宋体">比如</span>Url,<span style="font-family: 宋体">已经被收录到搜索引擎</span>,<span style="font-family: 宋体">就不能随便调整</span>,<span style="font-family: 宋体">还有一些地方</span>,<span style="font-family: 宋体">原本没有为静态生成考虑</span>,<span style="font-family: 宋体">另一些地方又需要兼容旧的设计</span>. </font></font></p>
<p style="margin: 0cm 0cm 0pt"><font color="#000000" size="3">&nbsp;</font></p>
<p style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt"><font color="#000000"><span style="font-family: Wingdings"><font size="3">l</font><span style="font: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal; x-system-font: none">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><strong><font size="3"><span style="font-family: 宋体">多台前端</span>Web</font></strong></font></p>
<p style="margin: 0cm 0cm 0pt"><font size="3"><font color="#000000"><span style="font-family: 宋体">这种结构要求生成的文件可能需要分布到多个服务器</span>(<span style="font-family: 宋体">另一个方案是放在几台专用的机器上</span>,<span style="font-family: 宋体">等前端来取</span>)</font></font></p>
<p style="margin: 0cm 0cm 0pt"><font color="#000000" size="3">&nbsp;</font></p>
<p style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt"><font color="#000000"><span style="font-family: Wingdings"><font size="3">l</font><span style="font: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal; x-system-font: none">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><strong><font size="3"><span style="font-family: 宋体">任务紧迫</span></font></strong></font></p>
<p style="margin: 0cm 0cm 0pt"><font size="3"><font color="#000000"><span style="font-family: 宋体">架构讨论结束仪式六月初</span>,<span style="font-family: 宋体">离奥运开幕上线只有两月</span>,<span style="font-family: 宋体">也就是说所有底层框架实现</span>,<span style="font-family: 宋体">页面模板开发</span>,<span style="font-family: 宋体">调试测试</span>,<span style="font-family: 宋体">动作的整理</span>,<span style="font-family: 宋体">必须在</span>7<span style="font-family: 宋体">月底全部完成</span>,<span style="font-family: 宋体">按我原来估计</span>,<span style="font-family: 宋体">光实现这几块的上百个页面模板和填充方法</span>,<span style="font-family: 宋体">也需要那么长的时间</span></font></font></p>
<p style="margin: 0cm 0cm 0pt"><font color="#000000" size="3">&nbsp;</font></p>
<p style="margin: 0cm 0cm 0pt"><font size="3"><font color="#000000"><span style="font-family: 宋体">综合考虑上述因素</span>,<span style="font-family: 宋体">架构必须要有以下几个方面的特点</span></font></font></p>
<p style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt"><font color="#000000"><span style="font-family: Wingdings"><font size="3">l</font><span style="font: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal; x-system-font: none">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="font-family: 宋体"><font size="3">动作可以灵活扩展配置</font></span><font size="3">,</font><span style="font-family: 宋体"><font size="3">某个动作对应哪些生成</font></span><font size="3">,</font><span style="font-family: 宋体"><font size="3">应该可以配置</font></span><font size="3">,</font><span style="font-family: 宋体"><font size="3">并且可以分组</font></span></font></p>
<p style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt"><font color="#000000"><span style="font-family: Wingdings"><font size="3">l</font><span style="font: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal; x-system-font: none">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="font-family: 宋体"><font size="3">文件必须有分发机制</font></span></font></p>
<p style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt"><font color="#000000"><span style="font-family: Wingdings"><font size="3">l</font><span style="font: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal; x-system-font: none">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="font-family: 宋体"><font size="3">分发和生成必须独立出来</font></span><font size="3">,</font><span style="font-family: 宋体"><font size="3">并且支持分布式</font></span></font></p>
<p style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt"><font color="#000000"><span style="font-family: Wingdings"><font size="3">l</font><span style="font: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal; x-system-font: none">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="font-family: 宋体"><font size="3">各种的动作</font></span><font size="3">,</font><span style="font-family: 宋体"><font size="3">必须转化为消息</font></span><font size="3">,</font><span style="font-family: 宋体"><font size="3">发送到生成和分发服务器进行处理</font></span></font></p>
<p style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt"><font color="#000000"><span style="font-family: Wingdings"><font size="3">l</font><span style="font: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal; x-system-font: none">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="font-family: 宋体"><font size="3">针对同意资源频繁动作</font></span><font size="3">,</font><span style="font-family: 宋体"><font size="3">在变量相同的情况下能够具有合并的能力</font></span></font></p>
<p style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt"><font color="#000000"><span style="font-family: Wingdings"><font size="3">l</font><span style="font: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal; x-system-font: none">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="font-family: 宋体"><font size="3">动作必须有记录</font></span></font></p>
<p style="margin: 0cm 0cm 0pt 21pt; text-indent: -21pt"><font color="#000000"><span style="font-family: Wingdings"><font size="3">l</font><span style="font: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal; x-system-font: none">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="font-family: 宋体"><font size="3">尽量考虑使用已有成熟技术</font></span><font size="3">,</font><span style="font-family: 宋体"><font size="3">节省开发时间</font></span></font></p>
<h2 style="margin: 13pt 0cm"><span style="font-family: 黑体"><font style="font-size: 18pt" color="#000000">下面是设计的第一个架构</font></span></h2>
<h2 style="margin: 13pt 0cm"><span style="font-family: 黑体"><span style="font-family: 宋体"><font color="#000000" size="3"><img alt="" src="http://p.blog.csdn.net/images/p_blog_csdn_net/yizhu2000/EntryImages/20080901/first.JPG" /></font></span></span></h2>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: 宋体"><font color="#000000" size="3">用户的动作经过</font></span><font color="#000000" size="3">MSMQ</font><a title="" href="http://blog.csdn.net/PostEditPlain.aspx#_edn1" name="_ednref1"><span style="font-size: 10.5pt; font-family: 'Times New Roman'"><u><font color="#0000ff">[1]</font></u></a></span><font size="3"><font color="#000000"><span style="font-family: 宋体">传入到生成分发中心</span>(<span style="font-family: 宋体">途中绿色箭头</span>)<span style="font-family: 宋体">进行处理</span>,,<span style="font-family: 宋体">处理中心接受到消息后</span>,<span style="font-family: 宋体">负责生成对应的页面或者页面区域</span>,<span style="font-family: 宋体">并将页面分发到各个服务器</span>,<span style="font-family: 宋体">负载均衡沿用以前的架构</span>,<span style="font-family: 宋体">采用微软的</span></font></font><font color="#000000" size="3">NLB</font><a title="" href="http://blog.csdn.net/PostEditPlain.aspx#_edn2" name="_ednref2"><span style="font-size: 10.5pt; font-family: 'Times New Roman'"><u><font color="#0000ff">[2]</font></u></a></span></p>
<p style="margin: 0cm 0cm 0pt"><font color="#000000" size="3">&nbsp;</font></p>
<p style="margin: 0cm 0cm 0pt"><font size="3"><font color="#000000"><span style="font-family: 宋体">之所以用</span>MSMQ,<span style="font-family: 宋体">就是看上了他提供的完整的消息存储恢复机制</span>,<span style="font-family: 宋体">这样我们能确保即使服务器</span>down<span style="font-family: 宋体">掉重启后</span>,<span style="font-family: 宋体">消息依然能正常处理</span>,<span style="font-family: 宋体">碰巧我们</span>cms<span style="font-family: 宋体">组的同事</span>MSMQ<span style="font-family: 宋体">非常熟悉</span>,<span style="font-family: 宋体">并且真准备在另外一个项目中使用类似的架构</span>—<span style="font-family: 宋体">于是一拍即合</span></font></font></p>
<p style="margin: 0cm 0cm 0pt"><font color="#000000" size="3">&nbsp;</font></p>
<p style="margin: 0cm 0cm 0pt"><font size="3"><font color="#000000"><span style="font-family: 宋体">页面采用分块存储</span>,<span style="font-family: 宋体">这样能保证生成时目标小</span>,<span style="font-family: 宋体">开销小</span>,<span style="font-family: 宋体">也能重用性</span>,<span style="font-family: 宋体">然后再藉由</span></font></font><font color="#000000" size="3">SSI</font><a title="" href="http://blog.csdn.net/PostEditPlain.aspx#_edn3" name="_ednref3"><span style="font-size: 10.5pt; font-family: 'Times New Roman'"><u><font color="#0000ff">[3]</font></u></a><font color="#000000" size="3">(shtml include)</font></span><font size="3"><font color="#000000"><span style="font-family: 宋体">进行整合</span>,<span style="font-family: 宋体">之所以采取这样的方案</span>,<span style="font-family: 宋体">而不采用</span>Dottext<span style="font-family: 宋体">的整合方式</span>,<span style="font-family: 宋体">是因为如果采用</span>Dottext<span style="font-family: 宋体">的方式</span>,<span style="font-family: 宋体">就必须走</span>IIS<span style="font-family: 宋体">和</span>.Net<span style="font-family: 宋体">的管道</span></font></font><a title="" href="http://blog.csdn.net/PostEditPlain.aspx#_edn4" name="_ednref4"><span style="font-size: 10.5pt; font-family: 'Times New Roman'"><u><font color="#0000ff">[4]</font></u></span></a><font size="3"><font color="#000000">,<span style="font-family: 宋体">而据测试</span>,<span style="font-family: 宋体">经过管道和直接返回</span>html<span style="font-family: 宋体">性能有非常大的差异</span>,<span style="font-family: 宋体">而使用</span>ssi,<span style="font-family: 宋体">在性能上是一个折中</span>,<span style="font-family: 宋体">并且可以</span>Light HTTPd<span style="font-family: 宋体">等高性能</span>web<span style="font-family: 宋体">服务器</span></font></font></p>
<p style="margin: 0cm 0cm 0pt"><font color="#000000" size="3">&nbsp;</font></p>
<p style="margin: 0cm 0cm 0pt"><font size="3"><font color="#000000"><span style="font-family: 宋体">模板生成方式</span>,<span style="font-family: 宋体">采用了</span>XSLT<span style="font-family: 宋体">和另外一种自定义的模板</span>(<span style="font-family: 宋体">我的同事开发的机制</span>,<span style="font-family: 宋体">很有趣</span>, <span style="font-family: 宋体">理论上能把传统模板替换的性能开销全部消除</span>),<span style="font-family: 宋体">生成的最终产物是</span>shtml,<span style="font-family: 宋体">之所以生成</span>shtml<span style="font-family: 宋体">是为了使用其</span>ssi(Server Side Include)<span style="font-family: 宋体">的特性</span>,<span style="font-family: 宋体">保证一定的灵活性</span>,<span style="font-family: 宋体">并实现热点数据的分离</span>:<span style="font-family: 宋体">某些页面上的部分可能会频繁更新和生成</span>,<span style="font-family: 宋体">而其它地方不变</span>,<span style="font-family: 宋体">或者某个部分是所有页面通用的</span>(<span style="font-family: 宋体">比如页头和页脚</span>),<span style="font-family: 宋体">较之</span>php<span style="font-family: 宋体">下常常使用</span>smarty,<span style="font-family: 宋体">生成</span>php<span style="font-family: 宋体">文件</span>,<span style="font-family: 宋体">虽然灵活性不如</span>php,<span style="font-family: 宋体">但是性能上不相上下</span>,<span style="font-family: 宋体">还略高</span>.</font></font></p>
<p style="margin: 0cm 0cm 0pt"><font color="#000000" size="3">&nbsp;</font></p>
<p style="margin: 0cm 0cm 0pt"><font size="3"><font color="#000000"><span style="font-family: 宋体">但是这个设计的问题是动态内容和静态内容没有分开</span>,<span style="font-family: 宋体">生成的</span>html<span style="font-family: 宋体">页面</span>,<span style="font-family: 宋体">和动态页面都放在前端服务器上</span>,<span style="font-family: 宋体">通过负载均衡访问</span>,<span style="font-family: 宋体">也造成了分发服务器需要分发到多台服务器</span>,<span style="font-family: 宋体">网络</span>IO<span style="font-family: 宋体">效率较低</span>,<span style="font-family: 宋体">而且静态内容需要的磁盘空间很大</span>,<span style="font-family: 宋体">且小文件非常多</span>,<span style="font-family: 宋体">和动态页面混在一起不便于优化</span>,<span style="font-family: 宋体">所以第二个方案对生成的静态内容与动态内容使用不同的服务器</span></font></font></p>
<p style="margin: 0cm 0cm 0pt"><font color="#000000" size="3">&nbsp;</font></p>
<h2 style="margin: 13pt 0cm"><font style="font-size: 18pt" color="#000000"><span style="font-family: 黑体">方案二</span><font face="Arial">:</font></font></h2>
<h2 style="margin: 13pt 0cm"><font color="#000000"><span style="font-family: 宋体"><img alt="" src="http://p.blog.csdn.net/images/p_blog_csdn_net/yizhu2000/EntryImages/20080901/second.JPG" /></span></font></h2>
<p style="margin: 0cm 0cm 0pt"><font size="3"><font color="#000000"><span style="font-family: 宋体">我们把生成的静态文件单独放置</span>,<span style="font-family: 宋体">可以看到</span>,<span style="font-family: 宋体">前端增加</span>Nginx,<span style="font-family: 宋体">作为跳转</span>,<span style="font-family: 宋体">把电影</span>,<span style="font-family: 宋体">影人资料库的页面转向静态服务器</span>,<span style="font-family: 宋体">其他的调用转向动态服务器</span>,<span style="font-family: 宋体">这样我们就可以单独为静态服务器进行优化</span>,<span style="font-family: 宋体">比如采用更高效的服务器等等</span>.</font></font></p>
<p style="margin: 0cm 0cm 0pt"><font color="#000000" size="3">&nbsp;</font></p>
<p style="margin: 0cm 0cm 0pt"><font size="3"><font color="#000000"><span style="font-family: 宋体">同时减少了文件分发的次数</span>(<span style="font-family: 宋体">甚至可以只分发到本机</span>),<span style="font-family: 宋体">提高生成分发的处理能力</span></font></font></p>
<p style="margin: 0cm 0cm 0pt"><font color="#000000" size="3">&nbsp;</font></p>
<p style="margin: 0cm 0cm 0pt"><font size="3"><font color="#000000"><span style="font-family: 宋体">更进一步</span>,<span style="font-family: 宋体">可以把图片服务分到另外一组机器上</span>,<span style="font-family: 宋体">使用独立的域名</span>,<span style="font-family: 宋体">比如</span>img.xxx.com,<span style="font-family: 宋体">这样可以有效的减少带宽</span></font></font></p>
<p style="margin: 0cm 0cm 0pt"><font color="#000000" size="3">&nbsp;</font></p>
<h2 style="margin: 13pt 0cm"><font style="font-size: 18pt" color="#000000"><span style="font-size: 18pt"><span style="font-family: 黑体">最终完整架构</span>:</span></font></h2>
<p style="margin: 0cm 0cm 0pt"><font color="#000000" size="3">&nbsp;</font></p>
<p style="margin: 0cm 0cm 0pt"><font color="#000000" size="3"><img height="458" alt="" src="http://p.blog.csdn.net/images/p_blog_csdn_net/yizhu2000/EntryImages/20080901/final.JPG" width="554" />&nbsp;</font></p>
<h2 style="margin: 13pt 0cm"><span style="font-family: 黑体"><font color="#000000"><span style="font-size: 18pt"><span style="font-family: 黑体"><font color="#000000"><span style="font-size: 18pt"><span style="font-family: 黑体"><font color="#000000"><span style="font-family: 黑体"><font color="#000000">文件生成分发中心</font></span></font></span></span></font></span></span></font></span></h2>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: 宋体"><font color="#000000" size="3">下图是文件生成分发中心的工作流程图</font></span></p>
<p style="margin: 0cm 0cm 0pt"><span style="font-family: 宋体"><img height="293" alt="" src="http://p.blog.csdn.net/images/p_blog_csdn_net/yizhu2000/EntryImages/20080901/generator.JPG" width="526" /><br />
</span><font size="3"><font color="#000000"><span style="font-family: 宋体">生成服务对外只有一个输入</span>,<span style="font-family: 宋体">就是消息</span>,<span style="font-family: 宋体">一个输出</span>:<span style="font-family: 宋体">静态文件</span>,<span style="font-family: 宋体">内部根据消息</span>,<span style="font-family: 宋体">从配置文件中找到对应的生成方法</span>,<span style="font-family: 宋体">取出相应的模板</span>,<span style="font-family: 宋体">进行数据填充</span></font></font></p>
<p style="margin: 0cm 0cm 0pt"><font color="#000000" size="3">&nbsp;</font></p>
<p style="margin: 0cm 0cm 0pt"><font size="3"><font color="#000000"><span style="font-family: 宋体">分发服务主要吧生成服务产生的文件进行分发</span>,<span style="font-family: 宋体">分发到前端的</span>N<span style="font-family: 宋体">台服务器上</span>,<span style="font-family: 宋体">开始考虑得比较复杂</span>,<span style="font-family: 宋体">希望分发服务可以跨越协议</span>(<span style="font-family: 宋体">本地文件系统</span>,<span style="font-family: 宋体">局域网</span>,http<span style="font-family: 宋体">协议</span>),<span style="font-family: 宋体">跨越多种存储介质</span>(<span style="font-family: 宋体">文件系统</span>,<span style="font-family: 宋体">数据库</span>),<span style="font-family: 宋体">实际最后定下来基本是本地文件系统或者局域网传输</span></font></font></p>
<p style="margin: 0cm 0cm 0pt"><font color="#000000" size="3">&nbsp;</font></p>
<p style="margin: 0cm 0cm 0pt"><font color="#000000"><strong><span style="font-size: 9pt; font-family: 宋体">注</span></strong><strong><span style="font-size: 9pt">:</span></strong><strong><span style="font-size: 9pt; font-family: 宋体">上图中文件分发的部分也可以通过定制</span></strong><strong><span style="font-size: 9pt">MogileFS,</span></strong><strong><span style="font-size: 9pt; font-family: 宋体">来实现分布式文件系统</span></strong></font></p>
<p style="margin: 0cm 0cm 0pt"><font color="#000000" size="3">&nbsp;</font></p>
<h2 style="margin: 13pt 0cm"><font style="font-size: 18pt" color="#000000"><span style="font-family: 黑体">马后炮</span><font face="Arial">:</font></font></h2>
<p style="margin: 0cm 0cm 0pt"><font size="3"><font color="#000000"><span style="font-family: 宋体">总结起来</span>,<span style="font-family: 宋体">静态化除了对架构方面的影响</span>,<span style="font-family: 宋体">对开发和测试流程也有影响</span></font></font></p>
<p style="margin: 0cm 0cm 0pt"><strong><font size="3"><font color="#000000"><span style="font-family: 宋体">对测试提出更高的要求</span>:</font></font></strong></p>
<p style="margin: 0cm 0cm 0pt"><font size="3"><font color="#000000"><span style="font-family: 宋体">因为一旦上线后</span>,<span style="font-family: 宋体">某个页面发现问题</span>,<span style="font-family: 宋体">即使是文字的修改</span>,<span style="font-family: 宋体">也需要重新生成许多页面</span>,<span style="font-family: 宋体">所以测试人员必须非常仔细</span>,<span style="font-family: 宋体">测试周期也需要延长</span></font></font></p>
<p style="margin: 0cm 0cm 0pt"><font color="#000000" size="3">&nbsp;</font></p>
<p style="margin: 0cm 0cm 0pt"><strong><font size="3"><font color="#000000"><span style="font-family: 宋体">开发人员需要掌握模板语言</span></font></font></strong></p>
<p style="margin: 0cm 0cm 0pt"><font size="3"><font color="#000000"><span style="font-family: 宋体">需要掌握一种模板预言</span>,<span style="font-family: 宋体">无论是</span>Xslt<span style="font-family: 宋体">还是自己开发的模板语言</span>,<span style="font-family: 宋体">都需要花一定的时间掌握</span></font></font></p>
<p style="margin: 0cm 0cm 0pt"><font color="#000000" size="3">&nbsp;</font></p>
<p style="margin: 0cm 0cm 0pt"><strong><font size="3"><font color="#000000"><span style="font-family: 宋体">需要给第一次生成腾出足够时间</span>:</font></font></strong></p>
<p style="margin: 0cm 0cm 0pt"><font size="3"><font color="#000000"><span style="font-family: 宋体">如果不是新系统</span>,<span style="font-family: 宋体">那么数据迁移和生成的过程就比较痛苦</span>,<span style="font-family: 宋体">由于页面众多</span>,<span style="font-family: 宋体">第一次生成的过程可能需要以天来计算</span>,<span style="font-family: 宋体">在制定上线方案是就需要考虑到这个方面</span></font></font></p>
<p style="margin: 0cm 0cm 0pt"><font color="#000000" size="3">&nbsp;</font></p>
<p style="margin: 0cm 0cm 0pt"><font color="#000000" size="3">Nginx</font><font size="3"><font color="#000000"><span style="font-family: 宋体">作为前端的跳转</span>,<span style="font-family: 宋体">根据其他网站的经验</span>,<span style="font-family: 宋体">应该可以达到</span>2-3<span style="font-family: 宋体">万并发连接</span>,<span style="font-family: 宋体">但是使用之后</span>,<span style="font-family: 宋体">常常有卡壳的情况发生</span>,<span style="font-family: 宋体">具体症状为在浏览器中访问页面时</span>,<span style="font-family: 宋体">连接超时</span>,<span style="font-family: 宋体">或者一直不响应</span>,<span style="font-family: 宋体">此时</span>Nginx<span style="font-family: 宋体">连接数并不高</span>,<span style="font-family: 宋体">好在还有第一套方案可以备用</span>,<span style="font-family: 宋体">让我们有时间去解决这个问题</span>,<span style="font-family: 宋体">如果大家对这个问题有什么心得</span>,<span style="font-family: 宋体">欢迎交流</span></font></font></p>
 <img src ="http://www.blogjava.net/jinfeng_wang/aggbug/318519.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jinfeng_wang/" target="_blank">jinfeng_wang</a> 2010-04-16 14:34 <a href="http://www.blogjava.net/jinfeng_wang/archive/2010/04/16/318519.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>多站点整合—单点登录简单方案 zz</title><link>http://www.blogjava.net/jinfeng_wang/archive/2010/04/16/318517.html</link><dc:creator>jinfeng_wang</dc:creator><author>jinfeng_wang</author><pubDate>Fri, 16 Apr 2010 06:31:00 GMT</pubDate><guid>http://www.blogjava.net/jinfeng_wang/archive/2010/04/16/318517.html</guid><wfw:comment>http://www.blogjava.net/jinfeng_wang/comments/318517.html</wfw:comment><comments>http://www.blogjava.net/jinfeng_wang/archive/2010/04/16/318517.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jinfeng_wang/comments/commentRss/318517.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jinfeng_wang/services/trackbacks/318517.html</trackback:ping><description><![CDATA[<span class="content" id="fontzoom"><strong>http://www.yaosansi.com/post/1218.html</strong><br />
<br />
<br />
问题描述：在一个比较复杂的网站环境下。有多个产品向外提供服务。每个产品下都有自己的用户登录界面。现在需要设计一个统一的登录界面。当用户在这个界面登录后就可以自由的使用各个产品和服务。同时意味着用户用一个帐号可以在不同服务里登录，另一方面就是在一个服务里面登录后可以无障碍的漫游到其他服务里面去。<br />
<br />
实际应用：Sohu的Passport将focus.cn，17173.com，sogou.com，chinaren.com这四个域名下的产品全部整合在一起了。用户在这四个站点中任何一个地方都可以登录。当用户登录后可以自由的使用其他域名下的服务。现在很多网站上都有bbs blog album服务。这些服务一般也是自己维护自己的用户信息。当发展到一定时候，也需要一个Passport机制整合所有服务，使用户可以单点登录。<br />
<br />
<strong><font color="#ff0000">Sohu的实现方案</font></strong><br />
在<a href="http://passport.sohu.com/" target="_blank">http://passport.sohu.com/</a> 登录后 fiddler可以拦截到如下的返回信息：<br />
<br />
<a href="http://zhangsichu.com/attachments/month_200710/23_220611_tqixsso1.gif" target="_blank"><img alt="Click to Open in New Window" src="http://zhangsichu.com/attachments/month_200710/23_220611_tqixsso1.gif" onload="javascript:if(this.width />screen.width-300)this.width=screen.width-300" border=0></a><br />
<br />
由于passport.sohu.com的登录界面使用了iframe隐藏提交。所以页面没有看到刷新。隐藏的iframe把用户名和加密的password和其他信息发送给了passport.sohu.com。passport.sohu.com在Response中设置了成功登录的cookie。这个cookie可以证实这个用户成功登录了passport.sohu.com。<br />
<br />
<a href="http://zhangsichu.com/attachments/month_200710/23_220615_if8lsso2.gif" target="_blank"><img alt="Click to Open in New Window" src="http://zhangsichu.com/attachments/month_200710/23_220615_if8lsso2.gif" onload="javascript:if(this.width />screen.width-300)this.width=screen.width-300" border=0></a><br />
<br />
当用户在Passport成功登录后。客户端的Javascript根据成功登录的标志，操作iframe请求<a href="http://passport.sohu.com/sso/crossdomain_all.jsp?action=login" target="_blank">http://passport.sohu.com/sso/crossdomain_all.jsp?action=login</a> 因为在同一个域名下，没有跨域，在这次请求中，上次成功登陆的cookie会被一并带着回去。服务器端检查到成功登录的cookie后会Render回一段同时登录多个站点的html。 <br />
<br />
<a href="http://zhangsichu.com/attachments/month_200710/23_220619_74vasso3.gif" target="_blank"><img alt="Click to Open in New Window" src="http://zhangsichu.com/attachments/month_200710/23_220619_74vasso3.gif" onload="javascript:if(this.width />screen.width-300)this.width=screen.width-300" border=0></a><br />
<br />
这段html 要向4个地址发送请求。截至到现在都是在相同的Domain(passport.sohu.com)请求和返回，为真正的跨站点登录做准备，真正的跨站点登录还没有开始。下面passport.sohu.com通过sso/crossdomain.jsp 在服务器端进行Redirect 设置http head 为302进行跳转。跳转后在这个跳转后的域名下设置登录成功的cookie。这就是sohu实现跨站点登录的核心过程。下面是passport.sohu.com登录17173.com的过程。<br />
1.&nbsp;&nbsp;通过<a href="http://passport.sohu.com/sso/crossdomain_all.jsp?action=login" target="_blank">http://passport.sohu.com/sso/crossdomain_all.jsp?action=login</a> Render回来的script &lt;script type="text/javascript" src="<a href='http://passport.sohu.com/sso/crossdomain.jsp?action=login&amp;domain=17173.com"></script>
' target=_blank href_cetemp='http://passport.sohu.com/sso/crossdomain.jsp?action=login&amp;domain=17173.com"></script>
'>http://passport.sohu.com/sso/crossdomain.jsp?action=login&amp;domain=17173.com"&gt;&lt;/script&gt;</a> 请求同域下的<a href="http://passport.sohu.com/sso/crossdomain.jsp?action=login&amp;domain=17173.com" target="_blank">http://passport.sohu.com/sso/crossdomain.jsp?action=login&amp;domain=17173.com</a> 这时passport.sohu.com下成功登录的cookie会被带回去。 <br />
<br />
<a href="http://zhangsichu.com/attachments/month_200710/23_220622_c02fsso4.gif" target="_blank"><img alt="Click to Open in New Window" src="http://zhangsichu.com/attachments/month_200710/23_220622_c02fsso4.gif" onload="javascript:if(this.width />screen.width-300)this.width=screen.width-300" border=0></a><br />
<br />
2.&nbsp;&nbsp;服务器看到成功登录的Cookie后。在服务器端计算出一个加密后的17173.com的登录Url，并Redirect到这个Url。 <br />
<br />
<a href="http://zhangsichu.com/attachments/month_200710/23_220626_liapsso5.gif" target="_blank"><img alt="Click to Open in New Window" src="http://zhangsichu.com/attachments/month_200710/23_220626_liapsso5.gif" onload="javascript:if(this.width />screen.width-300)this.width=screen.width-300" border=0></a><br />
<br />
3.&nbsp;&nbsp;17173.com从url的QueryString中取得信息。并在Response中设置Cookie。这个Cookie终于写到了17173.com下。而不是passport.sohu.com下。从而使得用户在17173.com下登录。其实用户在17173.com下手动登录也是写上同样的Cookie。以后用户再访问17173.com的页面时这个Cookie会被带回去。这就表示用户在17173.com下成功登录过了。 <br />
<br />
<a href="http://zhangsichu.com/attachments/month_200710/23_220629_96xbsso6.gif" target="_blank"><img alt="Click to Open in New Window" src="http://zhangsichu.com/attachments/month_200710/23_220629_96xbsso6.gif" onload="javascript:if(this.width />screen.width-300)this.width=screen.width-300" border=0></a><br />
<br />
经过上面的步骤。用户在passport.sohu.com下登录的同时也在其他站点登录了。<br />
<br />
<strong><font color="#ff0000">在上面的过程中，最核心的技巧就是在指定的域下写入想要的Cookie：</font></strong><br />
<br />
<strong>1.&nbsp;&nbsp;Sohu使用了在同一个域名登录后通过再次请求这个域名下某个链接后，得到要登录站点的请求Url，通过javascript使隐藏的iframe请求要登录站点的Url，服务器端接到请求Redirect到要登录站点，然后通过Response写入Cookie，完成跨域名写Cookie的操作。这种写Cookie的方式，需要在跳转时对请求的QueryString进行加密。接受方需要对QueryString进行解密。</strong><br />
<br />
<strong>2.&nbsp;&nbsp;这种做法在服务器端不需要特别的处理。只要写好相应Post操作 WriteCookie操作 Redirect操作 就可以了。在FireFox下就可以正常工作了。但是在IE下写Cookie的操作还不行，总是写不进去Cookie。需要在Response中加入一段特别的Header. P3P: CP="CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR" </strong><br />
<br />
<strong>这个Http Header 是P3P安全的要求。P3P的详解 <a href="http://www.oreilly.com.cn/book.php?bn=7-302-07170-5" target="_blank">http://www.oreilly.com.cn/book.php?bn=7-302-07170-5</a> </strong><br />
<strong>微软对这个的解释：<a href="http://support.microsoft.com/default.aspx?scid=KB;EN-US;Q323752" target="_blank">http://support.microsoft.com/default.aspx?scid=KB;EN-US;Q323752</a> </strong><br />
<br />
<strong><font color="#ff0000">一个更加轻量级的方案</font></strong><br />
<br />
Sohu的通行证方案已经可以轻松的将各个域名下的用户都同步登录了。但是在实现上Sohu会让客户端的浏览器请求两次passport.sohu.com。在第二次得到一个登录多个站点的地址列表。在第三次请求时通过本域下的cookie进行身份验证，最后在服务器端跳转到一个含有加密Key的其它域名的Url地址，最终写入登录成功的Cookie。除去最开始的登录，要求用户在登录后再进行两次请求。并且服务器端要再做一次跳转。Sohu的做法可能由于Sohu服务器环境和数据存储的结构所决定。<br />
<br />
其实总共只需一次登录请求，和每个域名下一次请求就可以完成多站点登录了，同时也不需要服务器端的跳转。<br />
<br />
<a href="http://zhangsichu.com/attachments/month_200710/24_174933_fc5isso7.gif" target="_blank"><img alt="Click to Open in New Window" src="http://zhangsichu.com/attachments/month_200710/24_174933_fc5isso7.gif" onload="javascript:if(this.width />screen.width-300)this.width=screen.width-300" border=0></a><br />
<br />
跨站点的请求由script的src发出。各个域名下的ssologin处理QueryString中的key，解密key，验证Key的合法性。在Response中写入登录成功的Cookie。完成跨站点Cookie的写入。<br />
<br />
<strong><font color="#ff0000">两种方案的比较</font></strong><br />
<br />
<strong>1. Sohu使用的登录方式，请求次数多，但是每次请求都有对应的验证过程，在服务端跳转时，重要的跳转Url地址在HttpHeader中，使得跳转地址更加安全，使得用户在跨域登录时非常安全可靠。</strong><br />
<br />
<strong>2. 轻量级方案的登录方式，请求次数少，没有服务器端的跳转，对服务器压力小。但是需要对Key进行加密解密。跳转的Url会在Response的Http Body中Render给用户。在使用轻量级方案的时候，最好在Key中加上时间戳，过期时间设置为3分钟。Key过期认为这个Key是非法Key，不在Response中写入登录成功的Cookie。</strong></span>
 <img src ="http://www.blogjava.net/jinfeng_wang/aggbug/318517.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jinfeng_wang/" target="_blank">jinfeng_wang</a> 2010-04-16 14:31 <a href="http://www.blogjava.net/jinfeng_wang/archive/2010/04/16/318517.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>亿万用户网站MySpace的成功秘密 zz</title><link>http://www.blogjava.net/jinfeng_wang/archive/2010/04/16/318514.html</link><dc:creator>jinfeng_wang</dc:creator><author>jinfeng_wang</author><pubDate>Fri, 16 Apr 2010 06:22:00 GMT</pubDate><guid>http://www.blogjava.net/jinfeng_wang/archive/2010/04/16/318514.html</guid><wfw:comment>http://www.blogjava.net/jinfeng_wang/comments/318514.html</wfw:comment><comments>http://www.blogjava.net/jinfeng_wang/archive/2010/04/16/318514.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jinfeng_wang/comments/commentRss/318514.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jinfeng_wang/services/trackbacks/318514.html</trackback:ping><description><![CDATA[http://www.yaosansi.com/post/1130.html<br />
<br />
<br />
高速增长的访问量给社区网络的技术体系带来了巨大挑战。MySpace的开发者多年来不断重构站点软件、数据库和存储系统，以期与自身的成长同步——目前，该站点月访问量已达400亿。绝大多数网站需要应对的流量都不及MySpace的一小部分，但那些指望迈入庞大在线市场的人，可以从MySpace的成长过程学到知识。<br />
<br />
<span style="font-weight: bold">用户的烦恼</span><br />
Drew，是个来自达拉斯的17岁小伙子，在他的MySpace个人资料页上，可以看到他的袒胸照，看样子是自己够着手拍的。他的好友栏全是漂亮姑娘和靓车的链接，另外还说自己参加了学校田径队，爱好吉他，开一辆蓝色福特野马。<br />
不过在用户反映问题的论坛里，似乎他的火气很大。&#8220;赶紧弄好这该死的收件箱！&#8221;他大写了所有单词。使用MySpace的用户个人消息系统可以收发信息，但当他要查看一条消息时，页面却出现提示：&#8220;非常抱歉&#8230;&#8230;消息错误&#8221;。<br />
<br />
Drew的抱怨说明1.4亿用户非常重视在线交流系统，这对MySpace来说是个好消息。但也恰是这点让MySpace成了全世界最繁忙的站点之一。<br />
11月，MySpace的美国国内互联网用户访问流量首次超过Yahoo。comScore Media Metrix公司提供的资料显示，MySpace当月访问量为387亿，而Yahoo是380.5亿。<br />
显然，MySpace的成长太快了——从2003年11月正式上线到现在不过三年。这使它很早就要面对只有极少数公司才会遇到的高可扩展性问题的严峻挑战。<br />
事实上，MySpace的Web服务器和数据库经常性超负荷，其用户频繁遭遇&#8220;意外错误&#8221;和&#8220;站点离线维护&#8221;等告示。包括Drew在内的MySpace用户经常无法收发消息、更新个人资料或处理其他日常事务，他们不得不在论坛抱怨不停。<br />
<br />
尤其是最近，MySpace可能经常性超负荷。因为Keynote Systems公司性能监测服务机构负责人Shawn White说，&#8220;难以想象，在有些时候，我们发现20%的错误日志都来自MySpace，有时候甚至达到30%以至40%&#8230;&#8230;而Yahoo、Salesforce.com和其他提供商用服务的站点，从来不会出现这样的数字。&#8221;他告诉我们，其他大型站点的日错误率一般就1%多点。<br />
<br />
顺便提及，MySpace在2006年7月24号晚上开始了长达12小时的瘫痪，期间只有一个可访问页面——该页面解释说位于洛杉矶的主数据中心发生故障。为了让大家耐心等待服务恢复，该页面提供了用Flash开发的派克人（Pac-Man）游戏。Web站点跟踪服务研究公司总经理Bill Tancer说，尤其有趣的是，MySpace瘫痪期间，访问量不降反升，&#8220;这说明了人们对MySpace的痴迷——所有人都拥在它的门口等着放行&#8221;。<br />
现Nielsen Norman Group 咨询公司负责人、原Sun Microsystems公司工程师，因在Web站点方面的评论而闻名的Jakob Nielsen说，MySpace的系统构建方法显然与Yahoo、eBay以及Google都不相同。和很多观察家一样，他相信MySpace对其成长速度始料未及。&#8220;虽然我不认为他们必须在计算机科学领域全面创新，但他们面对的的确是一个巨大的科学难题。&#8221;他说。<br />
<br />
MySpace开发人员已经多次重构站点软件、数据库和存储系统，以满足爆炸性的成长需要，但此工作永不会停息。&#8220;就像粉刷金门大桥，工作完成之时，就是重新来过之日。&#8221;（译者注：意指工人从桥头开始粉刷，当到达桥尾时，桥头涂料已经剥落，必须重新开始）MySpace技术副总裁Jim Benedetto说。<br />
既然如此，MySpace的技术还有何可学之处？因为MySpace事实上已经解决了很多系统扩展性问题，才能走到今天。<br />
<br />
Benedetto说他的项目组有很多教训必须总结，他们仍在学习，路漫漫而修远。他们当前需要改进的工作包括实现更灵活的数据缓存系统，以及为避免再次出现类似7月瘫痪事件的地理上分布式架构。<br />
<br style="font-weight: bold" />
<span style="font-weight: bold">背景知识</span><br />
MySpace目前的努力方向是解决扩展性问题，但其领导人最初关注的是系统性能。<br />
3年多前，一家叫做Intermix Media（早先叫eUniverse。这家公司从事各类电子邮件营销和网上商务）的公司推出了MySpace。而其创建人是Chris DeWolfe和Tom Anderson，他们原来也有一家叫做ResponseBase的电子邮件营销公司，后于2002年出售给Intermix。据Brad Greenspan（Intermix前CEO）运作的一个网站披露，ResponseBase团队为此获得2百万美金外加分红。Intermix是一家颇具侵略性的互联网商务公司——部分做法可能有点过头。2005年，纽约总检察长Eliot Spitzer——现在是纽约州长——起诉Intermix使用恶意广告软件推广业务，Intermix最后以790万美元的代价达成和解。<br />
<br />
2003年，美国国会通过《反垃圾邮件法》（CAN-SPAM Act），意在控制滥发邮件的营销行为。Intermix领导人DeWolfe和Anderson意识到新法案将严重打击公司的电子邮件营销业务，&#8220;因此必须寻找新的方向。&#8221;受聘于Intermix负责重写公司邮件营销软件的Duc Chau说。<br />
当时有个叫Friendster的交友网站，Anderson和DeWolfe很早就是它的会员。于是他们决定创建自己的网上社区。他们去除了Friendster在用户自我表述方面的诸多限制，并重点突出音乐（尤其是重金属乐），希望以此吸引用户。Chau使用Perl开发了最初的MySpace版本，运行于Apache Web服务器，后台使用MySQL数据库。但它没有通过终审，因为Intermix的多数开发人员对ColdFusion（一个Web应用程序环境，最初由Allaire开发，现为Adobe所有）更为熟悉。因此，最后发布的产品采用ColdFusion开发，运行在Windows上，并使用MS SQL Server作为数据库服务器。<br />
Chau就在那时离开了公司，将开发工作交给其他人，包括Aber Whitcomb（Intermix的技术专家，现在是MySpace技术总监）和Benedetto（MySpace现技术副总裁，大概于MySpace上线一个月后加入）。<br />
<br />
MySpace上线的2003年，恰恰是Friendster在满足日益增长的用户需求问题上遭遇麻烦的时期。在财富杂志最近的一次采访中，Friendster总裁Kent Lindstrom承认他们的服务出现问题选错了时候。那时，Friendster传输一个页面需要20到30秒，而MySpace只需2到3秒。<br />
<br />
结果，Friendster用户开始转投MySpace，他们认为后者更为可靠。<br />
今天，MySpace无疑已是社区网站之王。社区网站是指那些帮助用户彼此保持联系、通过介绍或搜索、基于共同爱好或教育经历交友的Web站点。在这个领域比较有名的还有最初面向大学生的Facebook、侧重职业交流的LinkedIn，当然还少不了Friendster。MySpace宣称自己是&#8220;下一代门户&#8221;，强调内容的丰富多彩（如音乐、趣事和视频等）。其运作方式颇似一个虚拟的夜总会——为未成年人在边上安排一个果汁吧，而显著位置则是以性为目的的约会，和寻找刺激派对气氛的年轻人的搜索服务。<br />
<br />
用户注册时，需要提供个人基本信息，主要包括籍贯、性取向和婚姻状况。虽然MySpace屡遭批评，指其为网上性犯罪提供了温床，但对于未成年人，有些功能还是不予提供的。<br />
MySpace的个人资料页上表述自己的方式很多，如文本式&#8220;关于本人&#8221;栏、选择加载入MySpace音乐播放器的歌曲，以及视频、交友要求等。它还允许用户使用CSS（一种Web标准格式语言，用户以此可设置页面元素的字体、颜色和页面背景图像）自由设计个人页面，这也提升了人气。不过结果是五花八门——很多用户的页面布局粗野、颜色迷乱，进去后找不到东南西北，不忍卒读；而有些人则使用了专业设计的模版（可阅读《Too Much of a Good Thing?》第49页），页面效果很好。<br />
在网站上线8个月后，开始有大量用户邀请朋友注册MySpace，因此用户量大增。&#8220;这就是网络的力量，这种趋势一直没有停止。&#8221;Chau说。<br />
<br />
拥有Fox电视网络和20th Century Fox影业公司的媒体帝国——新闻集团，看到了他们在互联网用户中的机会，于是在2005年斥资5.8亿美元收购了MySpace。新闻集团董事局主席Rupert Murdoch最近向一个投资团透露，他认为MySpace目前是世界主要Web门户之一，如果现在出售MySpace，那么可获60亿美元——这比2005年收购价格的10倍还多！新闻集团还惊人地宣称，MySpace在2006年7月结束的财政年度里总收入约2亿美元，而且预期在2007年度，Fox Interactive公司总收入将达到5亿美元，其中4亿来自MySpace。<br />
然而MySpace还在继续成长。12月份，它的注册账户达到1.4亿，而2005年11月时不过4千万。当然，这个数字并不等于真实的用户个体数，因为有些人可能有多个帐号，而且个人资料也表明有些是乐队，或者是虚构的名字，如波拉特（译者注：喜剧电影《Borat》主角），还有像Burger King（译者注：美国最大的汉堡连锁集团）这样的品牌名。<br />
<br />
当然，这么多的用户不停发布消息、撰写评论或者更新个人资料，甚至一些人整天都泡在Space上，必然给MySpace的技术工作带来前所未有的挑战。而传统新闻站点的绝大多数内容都是由编辑团队整理后主动提供给用户消费，它们的内容数据库通常可以优化为只读模式，因为用户评论等引起的增加和更新操作很少。而MySpace是由用户提供内容，数据库很大比例的操作都是插入和更新，而非读取。<br />
浏览MySpace上的任何个人资料时，系统都必须先查询数据库，然后动态创建页面。当然，通过数据缓存，可以减轻数据库的压力，但这种方案必须解决原始数据被用户频繁更新带来的同步问题。<br />
<br />
MySpace的站点架构已经历了5个版本——每次都是用户数达到一个里程碑后，必须做大量的调整和优化。Benedetto说，&#8220;但我们始终跟不上形势的发展速度。我们重构重构再重构，一步步挪到今天&#8221;。<br />
尽管MySpace拒绝了正式采访，但Benedetto在参加11月于拉斯维加斯召开的SQL Server Connections会议时还是回答了Baseline的问题。本文的不少技术信息还来源于另一次重要会议——Benedetto和他的老板——技术总监Whitcomb今年3月出席的Microsoft MIX Web开发者大会。<br />
据他们讲，MySpace很多大的架构变动都发生在2004和2005年早期——用户数在当时从几十万迅速攀升到了几百万。<br />
<br />
在每个里程碑，站点负担都会超过底层系统部分组件的最大载荷，特别是数据库和存储系统。接着，功能出现问题，用户失声尖叫。最后，技术团队必须为此修订系统策略。<br />
虽然自2005年早期，站点账户数超过7百万后，系统架构到目前为止保持了相对稳定，但MySpace仍然在为SQL Server支持的同时连接数等方面继续攻坚，Benedetto说，&#8220;我们已经尽可能把事情做到最好&#8221;。<br />
<br style="font-weight: bold" />
<span style="font-weight: bold">里程碑一：50万账户</span><br />
按Benedetto 的说法，MySpace最初的系统很小，只有两台Web服务器和一个数据库服务器。那时使用的是Dell双CPU、4G内存的系统。<br />
单个数据库就意味着所有数据都存储在一个地方，再由两台Web服务器分担处理用户请求的工作量。但就像MySpace后来的几次底层系统修订时的情况一样，三服务器架构很快不堪重负。此后一个时期内，MySpace基本是通过添置更多Web服务器来对付用户暴增问题的。<br />
但到在2004年早期，MySpace用户数增长到50万后，数据库服务器也已开始汗流浃背。<br />
但和Web服务器不同，增加数据库可没那么简单。如果一个站点由多个数据库支持，设计者必须考虑的是，如何在保证数据一致性的前提下，让多个数据库分担压力。<br />
在第二代架构中，MySpace运行在3个SQL Server数据库服务器上——一个为主，所有的新数据都向它提交，然后由它复制到其他两个；另两个全力向用户供给数据，用以在博客和个人资料栏显示。这种方式在一段时间内效果很好——只要增加数据库服务器，加大硬盘，就可以应对用户数和访问量的增加。<br />
<br />
<span style="font-weight: bold">里程碑二：1-2百万账户</span><br />
MySpace注册数到达1百万至2百万区间后，数据库服务器开始受制于I/O容量——即它们存取数据的速度。而当时才是2004年中，距离上次数据库系统调整不过数月。用户的提交请求被阻塞，就像千人乐迷要挤进只能容纳几百人的夜总会，站点开始遭遇&#8220;主要矛盾&#8221;，Benedetto说，这意味着MySpace永远都会轻度落后于用户需求。<br />
&#8220;有人花5分钟都无法完成留言，因此用户总是抱怨说网站已经完蛋了。&#8221;他补充道。<br />
这一次的数据库架构按照垂直分割模式设计，不同的数据库服务于站点的不同功能，如登录、用户资料和博客。于是，站点的扩展性问题看似又可以告一段落了，可以歇一阵子。<br />
垂直分割策略利于多个数据库分担访问压力，当用户要求增加新功能时，MySpace将投入新的数据库予以支持它。账户到达2百万后，MySpace还从存储设备与数据库服务器直接交互的方式切换到SAN（Storage Area Network，存储区域网络）——用高带宽、专门设计的网络将大量磁盘存储设备连接在一起，而数据库连接到SAN。这项措施极大提升了系统性能、正常运行时间和可靠性，Benedetto说。<br />
<br />
<span style="font-weight: bold">里程碑三：3百万账户</span><br />
当用户继续增加到3百万后，垂直分割策略也开始难以为继。尽管站点的各个应用被设计得高度独立，但有些信息必须共享。在这个架构里，每个数据库必须有各自的用户表副本——MySpace授权用户的电子花名册。这就意味着一个用户注册时，该条账户记录必须在9个不同数据库上分别创建。但在个别情况下，如果其中某台数据库服务器临时不可到达，对应事务就会失败，从而造成账户非完全创建，最终导致此用户的该项服务无效。<br />
另外一个问题是，个别应用如博客增长太快，那么专门为它服务的数据库就有巨大压力。<br />
2004年中，MySpace面临Web开发者称之为&#8220;向上扩展&#8221;对&#8220;向外扩展&#8221;（译者注：Scale Up和Scale Out，也称硬件扩展和软件扩展）的抉择——要么扩展到更大更强、也更昂贵的服务器上，要么部署大量相对便宜的服务器来分担数据库压力。一般来说，大型站点倾向于向外扩展，因为这将让它们得以保留通过增加服务器以提升系统能力的后路。<br />
但成功地向外扩展架构必须解决复杂的分布式计算问题，大型站点如Google、Yahoo和Amazon.com，都必须自行研发大量相关技术。以Google为例，它构建了自己的分布式文件系统。<br />
另外，向外扩展策略还需要大量重写原来软件，以保证系统能在分布式服务器上运行。&#8220;搞不好，开发人员的所有工作都将白费&#8221;，Benedetto说。<br />
因此，MySpace首先将重点放在了向上扩展上，花费了大约1个半月时间研究升级到32CPU服务器以管理更大数据库的问题。Benedetto说，&#8220;那时候，这个方案看似可能解决一切问题。&#8221;如稳定性，更棒的是对现有软件几乎没有改动要求。<br />
糟糕的是，高端服务器极其昂贵，是购置同样处理能力和内存速度的多台服务器总和的很多倍。而且，站点架构师预测，从长期来看，即便是巨型数据库，最后也会不堪重负，Benedetto说，&#8220;换句话讲，只要增长趋势存在，我们最后无论如何都要走上向外扩展的道路。&#8221;<br />
因此，MySpace最终将目光移到分布式计算架构——它在物理上分布的众多服务器，整体必须逻辑上等同于单台机器。拿数据库来说，就不能再像过去那样将应用拆分，再以不同数据库分别支持，而必须将整个站点看作一个应用。现在，数据库模型里只有一个用户表，支持博客、个人资料和其他核心功能的数据都存储在相同数据库。<br />
既然所有的核心数据逻辑上都组织到一个数据库，那么MySpace必须找到新的办法以分担负荷——显然，运行在普通硬件上的单个数据库服务器是无能为力的。这次，不再按站点功能和应用分割数据库，MySpace开始将它的用户按每百万一组分割，然后将各组的全部数据分别存入独立的SQL Server实例。目前，MySpace的每台数据库服务器实际运行两个SQL Server实例，也就是说每台服务器服务大约2百万用户。Benedetto指出，以后还可以按照这种模式以更小粒度划分架构，从而优化负荷分担。<br />
当然，还是有一个特殊数据库保存了所有账户的名称和密码。用户登录后，保存了他们其他数据的数据库再接管服务。特殊数据库的用户表虽然庞大，但它只负责用户登录，功能单一，所以负荷还是比较容易控制的。<br />
<br />
<span style="font-weight: bold">里程碑四：9百万到1千7百万账户</span><br />
2005年早期，账户达到9百万后，MySpace开始用Microsoft的C#编写ASP.NET程序。C#是C语言的最新派生语言，吸收了C++和Java的优点，依托于Microsoft .NET框架（Microsoft为软件组件化和分布式计算而设计的模型架构）。ASP.NET则由编写Web站点脚本的ASP技术演化而来，是Microsoft目前主推的Web站点编程环境。<br />
可以说是立竿见影，MySpace马上就发现ASP.NET程序运行更有效率，与ColdFusion相比，完成同样任务需消耗的处理器能力更小。据技术总监Whitcomb说，新代码需要150台服务器完成的工作，如果用ColdFusion则需要246台。Benedetto还指出，性能上升的另一个原因可能是在变换软件平台，并用新语言重写代码的过程中，程序员复审并优化了一些功能流程。<br />
<br />
最终，MySpace开始大规模迁移到ASP.NET。即便剩余的少部分ColdFusion代码，也从Cold-Fusion服务器搬到了ASP.NET，因为他们得到了BlueDragon.NET（乔治亚州阿尔法利塔New Atlanta Communications公司的产品，它能将ColdFusion代码自动重新编译到Microsoft平台）的帮助。<br />
账户达到1千万时，MySpace再次遭遇存储瓶颈问题。SAN的引入解决了早期一些性能问题，但站点目前的要求已经开始周期性超越SAN的I/O容量——即它从磁盘存储系统读写数据的极限速度。<br />
原因之一是每数据库1百万账户的分割策略，通常情况下的确可以将压力均分到各台服务器，但现实并非一成不变。比如第七台账户数据库上线后，仅仅7天就被塞满了，主要原因是佛罗里达一个乐队的歌迷疯狂注册。<br />
某个数据库可能因为任何原因，在任何时候遭遇主要负荷，这时，SAN中绑定到该数据库的磁盘存储设备簇就可能过载。&#8220;SAN让磁盘I/O能力大幅提升了，但将它们绑定到特定数据库的做法是错误的。&#8221;Benedetto说。<br />
最初，MySpace通过定期重新分配SAN中数据，以让其更为均衡的方法基本解决了这个问题，但这是一个人工过程，&#8220;大概需要两个人全职工作。&#8221;Benedetto说。<br />
长期解决方案是迁移到虚拟存储体系上，这样，整个SAN被当作一个巨型存储池，不再要求每个磁盘为特定应用服务。MySpace目前采用了一种新型SAN设备——来自加利福尼亚州弗里蒙特的3PARdata。<br />
在3PAR的系统里，仍能在逻辑上按容量划分数据存储，但它不再被绑定到特定磁盘或磁盘簇，而是散布于大量磁盘。这就使均分数据访问负荷成为可能。当数据库需要写入一组数据时，任何空闲磁盘都可以马上完成这项工作，而不再像以前那样阻塞在可能已经过载的磁盘阵列处。而且，因为多个磁盘都有数据副本，读取数据时，也不会使SAN的任何组件过载。<br />
当2005年春天账户数达到1千7百万时，MySpace又启用了新的策略以减轻存储系统压力，即增加数据缓存层——位于Web服务器和数据库服务器之间，其唯一职能是在内存中建立被频繁请求数据对象的副本，如此一来，不访问数据库也可以向Web应用供给数据。换句话说，100个用户请求同一份资料，以前需要查询数据库100次，而现在只需1次，其余都可从缓存数据中获得。当然如果页面变化，缓存的数据必须从内存擦除，然后重新从数据库获取——但在此之前，数据库的压力已经大大减轻，整个站点的性能得到提升。<br />
缓存区还为那些不需要记入数据库的数据提供了驿站，比如为跟踪用户会话而创建的临时文件——Benedetto坦言他需要在这方面补课，&#8220;我是数据库存储狂热分子，因此我总是想着将万事万物都存到数据库。&#8221;但将像会话跟踪这类的数据也存到数据库，站点将陷入泥沼。<br />
增加缓存服务器是&#8220;一开始就应该做的事情，但我们成长太快，以致于没有时间坐下来好好研究这件事情。&#8221;Benedetto补充道。<br />
<br />
<span style="font-weight: bold">里程碑五：2千6百万账户</span><br />
2005年中期，服务账户数达到2千6百万时，MySpace切换到了还处于beta测试的SQL Server 2005。转换何太急？主流看法是2005版支持64位处理器。但Benedetto说，&#8220;这不是主要原因，尽管这也很重要；主要还是因为我们对内存的渴求。&#8221;支持64位的数据库可以管理更多内存。<br />
更多内存就意味着更高的性能和更大的容量。原来运行32位版本的SQL Server服务器，能同时使用的内存最多只有4G。切换到64位，就好像加粗了输水管的直径。升级到SQL Server 2005和64位Windows Server 2003后，MySpace每台服务器配备了32G内存，后于2006年再次将配置标准提升到64G。<br />
<br />
<span style="font-weight: bold">意外错误</span><br />
如果没有对系统架构的历次修改与升级，MySpace根本不可能走到今天。但是，为什么系统还经常吃撑着了？很多用户抱怨的&#8220;意外错误&#8221;是怎么引起的呢？<br />
原因之一是MySpace对Microsoft的Web技术的应用已经进入连Microsoft自己也才刚刚开始探索的领域。比如11月，超出SQL Server最大同时连接数，MySpace系统崩溃。Benedetto说，这类可能引发系统崩溃的情况大概三天才会出现一次，但仍然过于频繁了，以致惹人恼怒。一旦数据库罢工，&#8220;无论这种情况什么时候发生，未缓存的数据都不能从SQL Server获得，那么你就必然看到一个&#8216;意外错误&#8217;提示。&#8221;他解释说。<br />
去年夏天，MySpace的Windows 2003多次自动停止服务。后来发现是操作系统一个内置功能惹的祸——预防分布式拒绝服务攻击（黑客使用很多客户机向服务器发起大量连接请求，以致服务器瘫痪）。MySpace和其他很多顶级大站点一样，肯定会经常遭受攻击，但它应该从网络级而不是依靠Windows本身的功能来解决问题——否则，大量MySpace合法用户连接时也会引起服务器反击。<br />
&#8220;我们花了大约一个月时间寻找Windows 2003服务器自动停止的原因。&#8221;Benedetto说。最后，通过Microsoft的帮助，他们才知道该怎么通知服务器：&#8220;别开枪，是友军。&#8221;<br />
紧接着是在去年7月某个周日晚上，MySpace总部所在地洛杉矶停电，造成整个系统停运12小时。大型Web站点通常要在地理上分布配置多个数据中心以预防单点故障。本来，MySpace还有其他两个数据中心以应对突发事件，但Web服务器都依赖于部署在洛杉矶的SAN。没有洛杉矶的SAN，Web服务器除了恳求你耐心等待，不能提供任何服务。<br />
Benedetto说，主数据中心的可靠性通过下列措施保证：可接入两张不同电网，另有后备电源和一台储备有30天燃料的发电机。但在这次事故中，不仅两张电网失效，而且在切换到备份电源的过程中，操作员烧掉了主动力线路。<br />
2007年中，MySpace在另两个后备站点上也建设了SAN。这对分担负荷大有帮助——正常情况下，每个SAN都能负担三分之一的数据访问量。而在紧急情况下，任何一个站点都可以独立支撑整个服务，Benedetto说。<br />
MySpace仍然在为提高稳定性奋斗，虽然很多用户表示了足够信任且能原谅偶现的错误页面。<br />
&#8220;作为开发人员，我憎恶Bug，它太气人了。&#8221;Dan Tanner这个31岁的德克萨斯软件工程师说，他通过MySpace重新联系到了高中和大学同学。&#8220;不过，MySpace对我们的用处很大，因此我们可以原谅偶发的故障和错误。&#8221; Tanner说，如果站点某天出现故障甚至崩溃，恢复以后他还是会继续使用。<br />
这就是为什么Drew在论坛里咆哮时，大部分用户都告诉他应该保持平静，如果等几分钟，问题就会解决的原因。Drew无法平静，他写道，&#8220;我已经两次给MySpace发邮件，而它说一小时前还是正常的，现在出了点问题&#8230;&#8230;完全是一堆废话。&#8221;另一个用户回复说，&#8220;毕竟它是免费的。&#8221;Benedetto坦承100%的可靠性不是他的目标。&#8220;它不是银行，而是一个免费的服务。&#8221;他说。<br />
换句话说，MySpace的偶发故障可能造成某人最后更新的个人资料丢失，但并不意味着网站弄丢了用户的钱财。&#8220;关键是要认识到，与保证站点性能相比，丢失少许数据的故障是可接受的。&#8221;Benedetto说。所以，MySpace甘冒丢失2分钟到2小时内任意点数据的危险，在SQL Server配置里延长了&#8220;checkpoint&#8221;操作——它将待更新数据永久记录到磁盘——的间隔时间，因为这样做可以加快数据库的运行。<br />
Benedetto说，同样，开发人员还经常在几个小时内就完成构思、编码、测试和发布全过程。这有引入Bug的风险，但这样做可以更快实现新功能。而且，因为进行大规模真实测试不具可行性，他们的测试通常是在仅以部分活跃用户为对象，且用户对软件新功能和改进不知就里的情况下进行的。因为事实上不可能做真实的加载测试，他们做的测试通常都是针对站点。<br />
&#8220;我们犯过大量错误，&#8221;Benedetto说，&#8220;但到头来，我认为我们做对的还是比做错的多。&#8221;<br />
<script src="http://www.yaosansi.com/PLUGIN/copytofriends/copy.js" type="text/javascript"></script>
 <img src ="http://www.blogjava.net/jinfeng_wang/aggbug/318514.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jinfeng_wang/" target="_blank">jinfeng_wang</a> 2010-04-16 14:22 <a href="http://www.blogjava.net/jinfeng_wang/archive/2010/04/16/318514.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Web 2.0网站性能调优实践 zz</title><link>http://www.blogjava.net/jinfeng_wang/archive/2010/04/16/318511.html</link><dc:creator>jinfeng_wang</dc:creator><author>jinfeng_wang</author><pubDate>Fri, 16 Apr 2010 05:58:00 GMT</pubDate><guid>http://www.blogjava.net/jinfeng_wang/archive/2010/04/16/318511.html</guid><wfw:comment>http://www.blogjava.net/jinfeng_wang/comments/318511.html</wfw:comment><comments>http://www.blogjava.net/jinfeng_wang/archive/2010/04/16/318511.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jinfeng_wang/comments/commentRss/318511.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jinfeng_wang/services/trackbacks/318511.html</trackback:ping><description><![CDATA[<a href="http://www.yaosansi.com/post/1150.html">http://www.yaosansi.com/post/1150.html</a>&nbsp; <br />
<br />
<br />
<h3>Web2.0网站性能调优实践</h3>
<p style="text-align: right" align="right">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 文/王宗义</p>
<p style="text-indent: 21pt">当前web2.0革命风起云涌，web2.0强调服务，而服务最基本的要求是速度快和稳定，离开这两个谈功能强大和易用性都没有任何意义。本文介绍一些关于笔者运营一个web2.0网站的优化心得和经验，希望能够和大家共同探讨。</p>
<p style="text-indent: 21pt">Web2.0网站不同于以往以静态信息为主的网站架构，以往的结构大体分为2层，一个是客户端浏览器，一个就是web服务器；而web2.0以动态和交互为主，一般是3层或者4层，在静态信息网站的结构上的web服务器后端会增加应用服务器和数据库。一般会把浏览器和web服务器归为最上一层即为web层，应用服务器为中间一层，数据库为最底层。从优化角度来讲，越上层优化获得益处越大，优化也是从上自下而来。</p>
<h3 style="margin: 15.6pt 0cm 0pt; line-height: normal">Web层优化</h3>
<h4 style="margin: 15.6pt 0cm 0pt; line-height: normal">DNS的解析时间</h4>
<p style="text-indent: 21pt">这个时间就是在用户第一次访问网站的时候产生，解析时间会影响用户的访问感受，因此想要网站响应速度快，第一就是不要在DNS解析上产生问题。另外DNS的TTL时间也要考量，IE的DNS过期时间是30分钟，TTL设置的比这个长一点就可以。另外在web服务器上使用keep-live也会减少DNS查询次数。</p>
<h4 style="margin: 15.6pt 0cm 0pt; line-height: normal">降低浏览器发起请求的数量</h4>
<p style="text-indent: 21pt">尽量降低浏览器发起请求的数量，就是说尽量能够让浏览器缓存任何可以缓存的东西。这样当用户访问过一次后，第二次访问可能会使得发起的请求数趋近1或者等于1，如果是静态的页面则可能是0。方法包括：</p>
<p style="text-indent: 21pt">把所有的样式表文件并为1个</p>
<p style="text-indent: 21pt">把所有的js文件并成1个</p>
<p style="text-indent: 21pt">图片尽量能够合成1张，这个跟以前不一样，现在大多数是adsl上网，反而是大量的零碎图片能够影响速度</p>
<h4 style="margin: 15.6pt 0cm 0pt; line-height: normal">页面布局与样式</h4>
<p style="text-indent: 21pt">页面采用xhtml，采用div+css布局，而把样式表和xhtml文件分开，一则能够降低xhtml文件大小，二则能够对样式表文件进行其他缓存处理。这里还有个ui设计的原则，ui跟系统结构一样，越简洁越好，这样整体页面代码会比较少，速度也会比较不错。</p>
<h4 style="margin: 15.6pt 0cm 0pt; line-height: normal">JavaScript文件</h4>
<p style="text-indent: 21pt">JavaScript文件也最好放到html文件外，原因同上。</p>
<h4 style="margin: 15.6pt 0cm 0pt; line-height: normal">静态文件的优化方法</h4>
<p style="text-indent: 21pt">a)目前大多数的浏览器都支持gzip压缩文件，因此为文本、静态页面、样式表、JavaScript文件等可以压缩处理的文件进行压缩处理能够减少内容获取时间，一般压缩完的大小为原大小的10-30%。这个在apache等web服务器上进行设置，笔者使用lighttpd的设置为：</p>
<p style="text-indent: 21pt">server.modules = ( </p>
<p style="text-indent: 21pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#8230;.</p>
<p style="text-indent: 21pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "mod_compress",</p>
<p style="text-indent: 21pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#8230;</p>
<p style="text-indent: 21pt">)</p>
<p style="text-indent: 21pt">compress.cache-dir="/usr/local/lighttpd/cache"</p>
<p style="text-indent: 21pt">compress.filetype = ("text/plain", "text/html", "text/css", "text/javascript")</p>
<p style="text-indent: 21pt">b)还可以在静态文件服务器前面增加缓存服务器比如squid，进一步增强客户端的访问性能。如果有好的财力，还可以使用一些商业的CDN加速服务。</p>
<h4 style="margin: 15.6pt 0cm 0pt; line-height: normal">应用Cookie的注意事项</h4>
<p style="text-indent: 21pt">Cookie的应用要注意，要限制cookie的应用域和应用的目录以及过期时间。不然如果用户是第一次访问的话，可能连一个小小的静态图片都要发送cookie到服务器，这样增加了通信负载。另外要限制cookie的大小，一个3k的cookie能够增加延迟达到80ms。</p>
<h4 style="margin: 15.6pt 0cm 0pt; line-height: normal">提高页面速度</h4>
<p style="text-indent: 21pt">页面由2-4个不同域名的服务器提供服务能够提高速度，这个国外也有研究证明。比如主html文件由app.domain.com提供，样式表由style.domain.com提供，图片等由img.domain.com提供，这样浏览器可以同时从多个服务器下载文件，速度就能够上去。但是最好不要超过4个。</p>
<h4 style="margin: 15.6pt 0cm 0pt; line-height: normal">样式表文件位置</h4>
<p style="text-indent: 21pt">把样式表文件放在页面的&lt;head&gt;，这样能够先读取。因为在ie中有个样式表的问题，样式表如果没有加载完会影响后面的html内容的页面显示，因此虽然html文件都已经在浏览器了，但是页面还是显示不出来。</p>
<h4 style="margin: 15.6pt 0cm 0pt; line-height: normal">把JavaScript移到html文件末尾</h4>
<p style="text-indent: 21pt">把JavaScript移到html文件末尾。为什么这么做呢，因为JavaScript处理的过程中会阻塞后面的页面显示，并且也会使得http请求也被阻止。笔者的网站就有过这样的例子，网站上放了一个合作方的JavaScript，结果每次访问时候感觉页面都停滞，用户体验特别差，后来让同事处理了一下，放到末尾等页面加载完了再显示在原有位置，一下子就好了。</p>
<h4 style="margin: 15.6pt 0cm 0pt; line-height: normal">尽量避免跳转</h4>
<p style="text-indent: 21pt">尽量避免跳转比如301和302。如果必须的话，对301和302的页面添加过期头。笔者原来的单点登录就需要进行跳转，后来改进了不需要跳转，整体的速度效果就出来了。</p>
<h4 style="margin: 15.6pt 0cm 0pt; line-height: normal">移除重复的脚本</h4>
<p style="text-indent: 21pt">要移除重复的脚本，ie会对重复的脚本发起重复的http请求，大多数网站在运营一段时间都有可能出现这个情况，笔者的网站中就经常有市场人员添加的重复的广告脚本。</p>
<h4 style="margin: 15.6pt 0cm 0pt; line-height: normal">AJAX内容</h4>
<p style="text-indent: 21pt">AJAX内容也是可以进行缓存的，同样可以压缩和缓存异步调用的xml、json等数据。</p>
<h4 style="margin: 15.6pt 0cm 0pt; line-height: normal">对爬虫进行限制</h4>
<p style="text-indent: 21pt">对爬虫进行限制，国内的一些爬虫非常厉害，并且不遵守robots规矩，经常有反应某某厉害爬虫把网站搞瘫的事件。怎么对爬虫进行限制呢，只能在web服务器上下功夫了，apache等服务器都能够进行限制，笔者的lighttpd限制10个并发的配置如下：&nbsp; </p>
<p style="text-indent: 21pt">&nbsp;evasive.max-conns-per-ip = 10</p>
<p style="text-indent: 21pt">web层的优化目的就是极大的利用了浏览器的缓存特性，从而达到几乎是本地访问的速度，下图是笔者访问douban.com首页的效果图对比：</p>
<p style="text-indent: 21pt"><img id="图片 2" height="189" alt="" src="http://book.csdn.net/BookFiles/569/img/image032.jpg" width="420" border="0" /></p>
<p style="text-indent: 21pt">前一列数据是空的缓存所需要下载的文件大小和http请求数量，后面是真实访问的带cache的情况，效果特别明显。http请求减少了95%，内容cache了82%。</p>
<h3 style="margin: 15.6pt 0cm 0pt; line-height: normal">应用程序层优化</h3>
<h4 style="margin: 15.6pt 0cm 0pt; line-height: normal">应用服务器的优化</h4>
<p style="text-indent: 21pt">Php的可以采用一些优化手段比如Zend Optimizer、eAccelerator、MMCache、Zend Performance Suite等</p>
<p style="text-indent: 21pt">Java的可以采用一些性能强的jdk、应用服务器，对jdk参数进行优化等等</p>
<h4 style="margin: 15.6pt 0cm 0pt; line-height: normal">使用ETag</h4>
<p style="text-indent: 21pt">ETag就像版本控制服务器中的版本号一样，每次更新后的ETag是不一样的，而浏览器处理就类似版本服务器的客户端一样，先把版本号发到服务器请求。ETag的处理过程，先是Web服务器在响应的http头中发送ETag，比如这样：</p>
<p style="text-indent: 21pt">ETag: "1111-2222-3333"</p>
<p style="text-indent: 21pt">Last-Modified: Thu, 07 Oct 2007 15:20:18 GMT</p>
<p style="text-indent: 21pt">而浏览器如果再次请求该页面就会发送类似如下的头：</p>
<p style="text-indent: 21pt">If-None-Match: "1111-2222-3333"</p>
<p style="text-indent: 21pt">If-Modified-Since: Thu, 07 Oct 2007 15:20:18 GMT</p>
<p style="text-indent: 21pt">此时，如果该页面没有任何变更，则web服务器会响应一个304的头，并且不需要附带页面内容给浏览器（即不需要再动态生成页面内容），这样就大大减少了服务器的处理和网路通信负载。</p>
<h4 style="margin: 15.6pt 0cm 0pt; line-height: normal">同步变异步</h4>
<p style="text-indent: 21pt">同步变异步，在web2.0网站中经常有很复杂的处理，比如一个用户的注册还需要发邮件等操作，有时候可能还有其他的处理，这样用户的等待时间比较长，并且容易出现错误。此种情况下，把其他处理变成异步的，从而直接把页面尽快响应给用户。笔者的一个数据上传的程序也是如此处理，一大堆数据，上传时间可能就1-2秒，而处理时间可能长的需要接近10秒（需要在数据库中进行上千次的插入操作），而在应用服务器容器内处理耗时则更长，笔者后来改成异步处理以后，用户满意度则大幅上升。</p>
<h4 style="margin: 15.6pt 0cm 0pt; line-height: normal">使用缓存</h4>
<p style="text-indent: 21pt">还是缓存，可能的情况下尽量使用缓存，毕竟现在内存非常便宜，用空间换取时间效率应该是非常划算的。尤其是对耗时比较长的、需要建立网络链接的，方法：采用memcached进行数据库或者常用数据的缓存；应用数据库缓冲池减少建立数据库连接的时间</p>
<h4 style="margin: 15.6pt 0cm 0pt; line-height: normal">采用gzip压缩动态页面</h4>
<p style="text-indent: 21pt">可能情况下，也可以采用gzip压缩动态页面。如果服务器较多，cpu负载不高，则可以考虑对动态页面增加gzip压缩功能</p>
<h4 style="margin: 15.6pt 0cm 0pt; line-height: normal">集群处理</h4>
<p style="text-indent: 21pt">访问压力大的时候，对应用服务器采用集群处理。</p>
<p style="text-indent: 21pt">应用服务器的优化主要是减少程序处理的时间，提高运行效率。</p>
<h3 style="margin: 15.6pt 0cm 0pt; line-height: normal">数据库优化</h3>
<p style="text-indent: 21pt">这个议题跟具体数据库关系比较大，议题也比较广泛，笔者就只简要列举一下：</p>
<p style="text-indent: 21pt">设置专门的DBA，专门负责数据库的安装、优化；对sql进行优化采用数据库集群和复制功能分担数据库压力。</p>
<h3 style="margin: 15.6pt 0cm 0pt; line-height: normal">其他优化措施</h3>
<p style="text-indent: 21pt">网站的优化涉及的方面比较多，其他方面涉及的还包括网站架构、操作系统、服务器硬件、网络设备、isp机房网络等等的调优。</p>
<h3 style="margin: 15.6pt 0cm 0pt; line-height: normal">工具</h3>
<p style="text-indent: 21pt">笔者用到的工具，都是firefox插件，所以firefox是必备的了：</p>
<p style="text-indent: 21pt">1、LiveHTTPHeaders (<a href="http://livehttpheaders.mozdev.org/"><font color="#336699">http://livehttpheaders.mozdev.org/</font></a>)</p>
<p style="text-indent: 21pt">2、Firebug (<a href="http://getfirebug.com/"><font color="#336699">http://getfirebug.com</font></a>)</p>
<p style="text-indent: 21pt">3、YSlow (<a href="http://developer.yahoo.com/yslow/"><font color="#336699">http://developer.yahoo.com/yslow/</font></a>)，要先装Firebug</p>
<p style="text-indent: 21pt">4、Web Developer (<a href="http://chrispederick.com/work/web-developer/"><font color="#336699">http://chrispederick.com/work/web-developer/</font></a>)</p>
<p style="text-indent: 21pt">除了这些免费的工具外，还可以采用一些商业的网站性能监测服务。一般网站性能监测服务商都会在不同的isp设置数据采集点，然后会定期模拟浏览器的访问对网站进行访问获取各种数据，比如dsn查询时间、第一个包获取时间、整个页面加载时间等等，然后汇总到数据中心。数据中心则可以产生性能报表、不同时间的可访问率、哪个isp容易出问题、发出警报等等。如果预算足够的话，可以采用这个服务。国外的有keynote、ip-label等，功能比较齐全，但是服务费用比较贵而且国内的点比较少。国内近些年也开始涌现出一些厂商，比如基调网络。笔者使用的监测系统的图例：</p>
<p style="margin-left: 21pt"><img id="图片 1" height="202" alt="" src="http://book.csdn.net/BookFiles/569/img/image033.jpg" width="553" border="0" /></p>
<h3 style="margin: 15.6pt 0cm 0pt; line-height: normal">笔者网站3年不同阶段的优化过程</h3>
<p style="text-indent: 21pt">优化的原则是尽量不去优化，在未发生性能问题的时候，没有必要去专门考虑细节的性能问题，当然大的结构应该是能够适应网站不断发展变化的。笔者的网站近3年的优化过程如下：</p>
<p style="text-indent: 21pt">1、开发完成，刚上线的时候，不做优化，用户量少，用了3台服务器。</p>
<p style="text-indent: 21pt">2、10万用户的时候，主要对sql进行了优化，还是3台服务器。</p>
<p style="text-indent: 21pt">3、10万用户到100万的过程中，采用了AJAX等，因此开始关注JavaScript的优化手段，访问量也快速上去，因此对静态文件进行分离并优化。服务器也进行了扩展，扩展到5台服务器。</p>
<p style="text-indent: 21pt">4、100万-200万用户，业务系统增加了很多，因此数据库采用了复制，程序方面应用了各种缓存处理，在数据库和程序之间增加了memcached进行数据缓存。</p>
<p style="text-indent: 21pt">5、在200万用户以上，主要在程序架构上做文章，对某些服务使用了集群。另外为了监测国内不同城市、isp的网络状况，使用了商业化的网站性能监测服务。</p>
 <img src ="http://www.blogjava.net/jinfeng_wang/aggbug/318511.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jinfeng_wang/" target="_blank">jinfeng_wang</a> 2010-04-16 13:58 <a href="http://www.blogjava.net/jinfeng_wang/archive/2010/04/16/318511.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>网络服务器设计的模型及一些设计方法zz</title><link>http://www.blogjava.net/jinfeng_wang/archive/2010/04/16/318495.html</link><dc:creator>jinfeng_wang</dc:creator><author>jinfeng_wang</author><pubDate>Fri, 16 Apr 2010 03:36:00 GMT</pubDate><guid>http://www.blogjava.net/jinfeng_wang/archive/2010/04/16/318495.html</guid><wfw:comment>http://www.blogjava.net/jinfeng_wang/comments/318495.html</wfw:comment><comments>http://www.blogjava.net/jinfeng_wang/archive/2010/04/16/318495.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jinfeng_wang/comments/commentRss/318495.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jinfeng_wang/services/trackbacks/318495.html</trackback:ping><description><![CDATA[<span class="Apple-style-span" style="word-spacing: 0px; font: medium 'MS PGothic'; text-transform: none; color: rgb(0,0,0); text-indent: 0px; white-space: normal; letter-spacing: normal; border-collapse: separate; orphans: 2; widows: 2; webkit-border-horizontal-spacing: 0px; webkit-border-vertical-spacing: 0px; webkit-text-decorations-in-effect: none; webkit-text-size-adjust: auto; webkit-text-stroke-width: 0px"><span class="Apple-style-span" style="font-size: 12px; line-height: 18px; font-family: verdana, sans-serif; text-align: center"><img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="1" alt="" src="http://cq144.csdn.net/visitlog.php?screen=1280x800&amp;host=blog.csdn.net&amp;browser=Netscape%205%20&amp;os=Windows&amp;url=http://blog.csdn.net/proad/archive/2008/04/16/2296925.aspx&amp;username=J2eeLearner" width="1" border="0" /><iframe id="myframe" border="0" name="myframe" src="http://www.csdn.net/ggmm/dd333.htm" frameborder="no" width="0" scrolling="no" height="0"></iframe></span></span> <a href="http://blog.csdn.net/proad/archive/2008/04/16/2296925.aspx">http://blog.csdn.net/proad/archive/2008/04/16/2296925.aspx</a><br />
<br />
<br />
<span class="Apple-style-span" style="word-spacing: 0px; font: medium 'MS PGothic'; text-transform: none; color: rgb(0,0,0); text-indent: 0px; white-space: normal; letter-spacing: normal; border-collapse: separate; orphans: 2; widows: 2; webkit-border-horizontal-spacing: 0px; webkit-border-vertical-spacing: 0px; webkit-text-decorations-in-effect: none; webkit-text-size-adjust: auto; webkit-text-stroke-width: 0px"><span class="Apple-style-span" style="font-size: 14px; line-height: 21px; font-family: verdana, sans-serif; text-align: left">
<p style="padding-right: 0px; padding-left: 0px; padding-bottom: 0px; margin: 1em 0px 0.5em; padding-top: 0px"><strong>1. 常用服务器模型</strong><br />
a.迭代服务器：只有一个进程/线程处理请求。一般为单进程,加上select多路复用,非阻塞socket。<br />
b.迭代/并发混合型服务器：平时迭代处理，对消耗大的请求并发处理。处理请求时设置一个超时，当请求的处理时间超时时，创建一个进程/线程，把处理转给新的进程/线程处理，主进程/线程继续处理其他请求。<br />
c.并发服务器：多个进程/线程并发处理请求。</p>
<p style="padding-right: 0px; padding-left: 0px; padding-bottom: 0px; margin: 1em 0px 0.5em; padding-top: 0px"><strong>2. 以上三类的服务器比较</strong><br />
迭代服务器：最简单，性能不高。<br />
并发服务器：性能较高，但结构相对比较复杂，开发难度中等。<br />
迭代/并发混合型服务器：性能不错，但结构通常比单纯的并发服务器更复杂。</p>
<p style="padding-right: 0px; padding-left: 0px; padding-bottom: 0px; margin: 1em 0px 0.5em; padding-top: 0px"><strong>3. 多进程的并发服务器</strong><br />
a. 每个连接fork一个进程：主进程accpet连接，有新连接到来时fork一个进程，然后继续accept，等待新的连接。数据传输由子进程处理，处理完后子进程exit。每个子进程只处理一个连接。<br />
b. Prefork进程：主进程预先fork一些进程，各个子进程竞争accept，然后处理数据传输。一个子进程可以处理一个连接，也可以同时处理多个连接（通过select等）。<br />
c. Prefork进程：由父进程accept请求，通过流管道转发fd到子进程，子进程收到fd后，处理数据传输，处理结束后通知父进程。父进程处理的事情比较简单，容易监控子进程。</p>
<p style="padding-right: 0px; padding-left: 0px; padding-bottom: 0px; margin: 1em 0px 0.5em; padding-top: 0px">以上3种方式性能比较：<br />
a.每个连接fork一个进程：处理smtp等状态较多，数据量比较大时比较简单实用，总体性能不大好。<br />
b.Prefork进程，各个子进程竞争accept：比较简单，性能不错。<br />
c.Prefork进程，由父进程accept请求，通过流管道转发fd到子进程：代码复杂，性能一般不如上一种。</p>
<p style="padding-right: 0px; padding-left: 0px; padding-bottom: 0px; margin: 1em 0px 0.5em; padding-top: 0px"><strong>4. 多线程的并发服务器</strong><br />
a.每个连接一个线程<br />
b.Prethread多个线程，各个线程互斥accept<br />
c.Prethread多个线程，主线程accept并分发连接给子线程</p>
<p style="padding-right: 0px; padding-left: 0px; padding-bottom: 0px; margin: 1em 0px 0.5em; padding-top: 0px"><strong>5. 多进程与多线程的比较</strong><br />
使用线程的模型：性能比使用进程要高，但代码比较复杂，对代码质量要求更高，线程出错后可能会影响到所有线程，多进程的模式一个进程出错一般不会影响其他进程。<br />
多线程模型共享数据比较简单有效，多进程模型共享数据比较麻烦，效率也不如线程。</p>
<p style="padding-right: 0px; padding-left: 0px; padding-bottom: 0px; margin: 1em 0px 0.5em; padding-top: 0px"><strong>6. 一些流行的网络服务器采用的模型</strong></p>
<p style="padding-right: 0px; padding-left: 0px; padding-bottom: 0px; margin: 1em 0px 0.5em; padding-top: 0px"><strong>Sendmail:</strong><span class="Apple-converted-space">&nbsp;</span>采用多进程，每个连接fork一个进程.<br />
每个连接fork一个子进程<br />
子进程只处理一个连接<br />
子进程fork一个localmail进程（可以由用户自己编写），通过管道把数据转给localmail处理，把邮件处理业务逻辑独立出来<br />
优点：结构简单，不用维护复杂的状态机</p>
<p style="padding-right: 0px; padding-left: 0px; padding-bottom: 0px; margin: 1em 0px 0.5em; padding-top: 0px"><strong>Apache1.3:</strong>采用多进程, prefork进程<br />
子进程竞争accept，每次只处理一个连接<br />
主进程不accept，根据负载情况调整子进程数量<br />
子进程运行一段时间后，主进程会让它退出，然后创建一个新的进程，防止内存泄漏等<br />
主进程通过shared memory监控子进程</p>
<p style="padding-right: 0px; padding-left: 0px; padding-bottom: 0px; margin: 1em 0px 0.5em; padding-top: 0px"><strong>移动QQ:</strong><span class="Apple-converted-space">&nbsp;</span>Prefork多个进程，竞争accept,<br />
典型的一问一答TCP服务器，结构简单<br />
每个进程通过select可以同时处理多个连接<br />
采用这种结构的原因有：<br />
每秒请求&lt;1000，可以满足要求<br />
结构简单，容易开发、维护</p>
</span></span>
 <img src ="http://www.blogjava.net/jinfeng_wang/aggbug/318495.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jinfeng_wang/" target="_blank">jinfeng_wang</a> 2010-04-16 11:36 <a href="http://www.blogjava.net/jinfeng_wang/archive/2010/04/16/318495.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Network Programming Using Libevent zz</title><link>http://www.blogjava.net/jinfeng_wang/archive/2010/04/16/318479.html</link><dc:creator>jinfeng_wang</dc:creator><author>jinfeng_wang</author><pubDate>Fri, 16 Apr 2010 02:29:00 GMT</pubDate><guid>http://www.blogjava.net/jinfeng_wang/archive/2010/04/16/318479.html</guid><wfw:comment>http://www.blogjava.net/jinfeng_wang/comments/318479.html</wfw:comment><comments>http://www.blogjava.net/jinfeng_wang/archive/2010/04/16/318479.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jinfeng_wang/comments/commentRss/318479.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jinfeng_wang/services/trackbacks/318479.html</trackback:ping><description><![CDATA[http://blog.gslin.org/archives/2005/11/24/220/<br />
<br />
<br />
在課堂上學過 Unix Network Programming 後，我們知道在處理多 User 時會有幾種方法解決：<br />
<ol>
    <li>一個新的 Connection 進來，用 <code>fork()</code> 產生一個 Process 處理。
    <li>一個新的 Connection 進來，用 <code>pthread_create()</code> 產生一個 Thread 處理。
    <li>一個新的 Connection 進來，丟入 Event-based Array，由 Main Process 以 Nonblocking 的方式處理所有的 I/O。<br />
    </li>
</ol>
這三種方法當然也都有各自的缺點：<br />
<ol>
    <li>用 <code>fork()</code> 的問題在於每一個 Connection 進來時的成本太高。
    <li>用 Multi-thread 的問題在於 Thread-safe 與 Deadlock 問題難以解決，另外有 Memory-leak 的問題要處理。
    <li>用 Event-based 的方式在於實做上不好寫，尤其是要注意到事件產生時必須 Nonblocking，於是會需要實做 Buffering 的問題，而 Multi-thread 所會遇到的 Memory-leak 問題在這邊會更嚴重。而在多 CPU 的系統上沒有辦法使用到所有的 CPU resource。<br />
    </li>
</ol>
當然，針對前面兩項有各自的解法：<br />
<ol>
    <li>以 Poll 的方式解決：當一個 Process 處理完一個 Connection 後，不直接死掉，而繼續回到 accept() 的狀態繼續處理，但這樣會遇到 Memory-leak 的問題，於是採用這種方式的人通常會再加上「處理過 N 個 Connection 後死掉，由 Parent Process 再 <code>fork()</code> 一隻新的」。最有名的例子是 <a href="http://httpd.apache.org/">Apache</a> 1.3。
    <li>Thread-safe 的問題可以透過自己撰寫，或是尋找其他 Thread-safe Library 直接使用。Memory-leak 的問題可以試著透過 Garbage Collection Library 分析出來。<a href="http://httpd.apache.org/">Apache</a> 2.0 的 Thread MPM 就是使用這個模式。<br />
    </li>
</ol>
然而，目前高效率的 Server 都偏好採用 Event-based，一方面是沒有 Create Process/Thread 所造成的 Overhead，另外一方面是不需要透過 Shared Memory 或是 Mutex 在不同的 Process/Thread 之間交換資料。<br />
<br />
然而，Event-based 在實做上的幾個複雜的地方在於：<br />
<ol>
    <li><code>select()</code> 與 <code>poll()</code> 的效率過慢，造成每次要判斷「有哪些 Event 發生」這件事情的成本很高，這在 BSD 支援 <code>kqueue()</code>、Linux 支援 <code>epoll()</code>、Solaris 支援 <code>/dev/poll</code> 後就解決了，但這兩組 Function 都不是 Standard，於是在不同的平台上就必須再改一次。<br />
    <li>因為 Nonblocking，所以在 <code>write()</code> 或是 <code>send()</code> 時滿了需要自己 Buffering。
    <li>因為 Nonblocking，所以不能使用 <code>fgets()</code> 或是其他類似的 function，於是需要自己刻一個 Nonblocking 的 <code>fgets()</code>。但是使用者所丟過來的資料又不能保證在一次 <code>read()</code> 或 <code>recv()</code> 就有一行，於是要自己做 Buffering。</li>
</ol>
實際上這三件事情在 <a href="http://www.monkey.org/%7Eprovos/libevent/">libevent</a> 都有 Library 處理掉了。<br />
<br />
另外值得注意的一點在於 <a href="http://www.monkey.org/%7Eprovos/libevent/">libevent</a> 使用的是 3-clause BSD license 而非 GPL，所以在不想公開程式碼 (像是商業用途) 的情況下會比其他的 Library 適合。<br />
<br />
<br />
<br />
<div class="post-body">
<p>
<div style="clear: both"></div>
接下來要談的是 <a href="http://www.monkey.org/%7Eprovos/libevent/">libevent</a> 要如何使用，不過為了方便起見，我們直接寫一個很簡單的 Time Server 來當作例子：當你連上去以後 Server 端直接提供時間，然後結束連線。<br />
<br />
在這些例子裡面我以 <a href="http://www.tw.freebsd.org/">FreeBSD</a> 6.0 當作測試的平台，另外使用 <a href="http://www.monkey.org/%7Eprovos/libevent/">libevent</a> 1.1a 當作 Event-based Library，Compile 時請使用 <code>gcc -I/usr/local/include -o timeserver timeserver.c -L/usr/local/lib -levent</code> (如果 <a href="http://www.monkey.org/%7Eprovos/libevent/">libevent</a> 的 Header 與 Library 放在 <code>/usr/include</code> 與 <code>/usr/lib</code> 下的話可以省略這兩個參數)。<br />
<br />
原始程式碼在文章的最後頭。<br />
<br />
<code>event_init()</code> 表示初始化 <a href="http://www.monkey.org/%7Eprovos/libevent/">libevent</a> 所使用到的變數。<br />
<br />
<code>event_set(&amp;ev, s, EV_READ | EV_PERSIST, connection_accept, &amp;ev)</code> 把 <code>s</code> 這個 File Description 放入 <code>ev</code> (第一個參數與第二個參數)，並且告知當事件 (第三個參數的 <code>EV_READ</code>) 發生時要呼叫 <code>connection_accept()</code> (第四個參數)，呼叫時要把 <code>ev</code> 當作參數丟進去 (第五個參數)。<br />
<br />
其中的 <code>EV_PERSIST</code> 表示當呼叫進去的時候不要把這個 event 拿掉 (繼續保留在 Event Queue 裡面)，這點可以跟 <code>connection_accept()</code> 內在註冊 <code>connection_time()</code> 的程式碼做比較。<br />
<br />
而 <code>event_add(&amp;ev, NULL)</code> 就是把 <code>ev</code> 註冊到 event queue 裡面，第二個參數指定的是 Timeout 時間，設定成 <code>NULL</code> 表示忽略這項設定。<br />
<br />
最後的 <code>event_dispatch()</code> 表示進入 event loop，當 Queue 裡面的任何一個 File Description 發生事件的時候就會進入 callback function 執行。<br />
<br />
這隻程式非常粗糙，有很多地方沒有注意到 Blocking 的問題，這點我們就先不管了。當跑起來以後你就可以連到 port 7000，就會出現類似下面的結果：gslin@netnews [~] [3:14/W5] t 0 7000<br />
<blockquote><code><br />
gslin@netnews [~/work/C] [3:15/W3] t 0 7000<br />
Trying 0.0.0.0...<br />
Connected to 0.<br />
Escape character is '^]'.<br />
Fri Nov 25 03:15:10 2005<br />
Connection closed by foreign host.<br />
</code></blockquote><br />
最基本的使用就是這樣了，你可以 <code>man event</code> 看到完整的說明。<br />
<br />
這是 <code>timeserver.c</code>：<br />
<pre><code><br />
#include &lt;netinet/in.h&gt;<br />
#include &lt;sys/socket.h&gt;<br />
#include &lt;sys/types.h&gt;<br />
#include &lt;event.h&gt;<br />
#include &lt;stdio.h&gt;<br />
#include &lt;time.h&gt;<br />
<br />
void connection_time(int fd, short event, struct event *arg)<br />
{<br />
char buf[32];<br />
struct tm t;<br />
time_t now;<br />
<br />
time(&amp;now);<br />
localtime_r(&amp;now, &amp;t);<br />
asctime_r(&amp;t, buf);<br />
<br />
write(fd, buf, strlen(buf));<br />
shutdown(fd, SHUT_RDWR);<br />
<br />
free(arg);<br />
}<br />
<br />
void connection_accept(int fd, short event, void *arg)<br />
{<br />
/* for debugging */<br />
fprintf(stderr, "%s(): fd = %d, event = %d.\n", __func__, fd, event);<br />
<br />
/* Accept a new connection. */<br />
struct sockaddr_in s_in;<br />
socklen_t len = sizeof(s_in);<br />
int ns = accept(fd, (struct sockaddr *) &amp;s_in, &amp;len);<br />
if (ns &lt; 0) {<br />
perror("accept");<br />
return;<br />
}<br />
<br />
/* Install time server. */<br />
struct event *ev = malloc(sizeof(struct event));<br />
event_set(ev, ns, EV_WRITE, (void *) connection_time, ev);<br />
event_add(ev, NULL);<br />
}<br />
<br />
int main(void)<br />
{<br />
/* Request socket. */<br />
int s = socket(PF_INET, SOCK_STREAM, 0);<br />
if (s &lt; 0) {<br />
perror("socket");<br />
exit(1);<br />
}<br />
<br />
/* bind() */<br />
struct sockaddr_in s_in;<br />
bzero(&amp;s_in, sizeof(s_in));<br />
s_in.sin_family = AF_INET;<br />
s_in.sin_port = htons(7000);<br />
s_in.sin_addr.s_addr = INADDR_ANY;<br />
if (bind(s, (struct sockaddr *) &amp;s_in, sizeof(s_in)) &lt; 0) {<br />
perror("bind");<br />
exit(1);<br />
}<br />
<br />
/* listen() */<br />
if (listen(s, 5) &lt; 0) {<br />
perror("listen");<br />
exit(1);<br />
}<br />
<br />
/* Initial libevent. */<br />
event_init();<br />
<br />
/* Create event. */<br />
struct event ev;<br />
event_set(&amp;ev, s, EV_READ | EV_PERSIST, connection_accept, &amp;ev);<br />
<br />
/* Add event. */<br />
event_add(&amp;ev, NULL);<br />
<br />
event_dispatch();<br />
<br />
return 0;<br />
}<br />
</code></pre>
<div style="clear: both; padding-bottom: 0.25em"></div>
<p>&nbsp;</p>
</div>
<div class="post-body">
<p>
<div style="clear: both"></div>
這次要談的跟 Network Programming 沒有直接的關係。<br />
<br />
在寫 Nonblocking Network Program 通常要處理 Buffering 的問題，但並不好寫，主要是因為 <code>read()</code> 或 <code>recv()</code> 不保證可以一次讀到一行的份量進來。<br />
<br />
在 <a href="http://www.monkey.org/%7Eprovos/libevent/">libevent</a> 裡面提供相當不錯的 Buffer Library 可以用，完整的說明在 <code>man event</code> 的時候可以看到，最常用的應該就是以 <code>evbuffer_add()</code>、<code>evbuffer_readline()</code> 這兩個 Function，其他的知道存在就可以了，需要的時候再去看詳細的用法。<br />
<br />
下面直接提供 <code>libevent-buff.c</code> 當作範例，編譯後看執行結果，再回頭來看 source code 應該就有感覺了：<br />
<pre><code><br />
#include &lt;sys/time.h&gt;<br />
#include &lt;event.h&gt;<br />
#include &lt;stdio.h&gt;<br />
<br />
void printbuf(struct evbuffer *evbuf)<br />
{<br />
for (;;) {<br />
char *buf = evbuffer_readline(evbuf);<br />
printf("* buf = %p, the string = \"\e[1;33m%s\e[m\"\n", buf, buf);<br />
if (buf == NULL)<br />
break;<br />
free(buf);<br />
}<br />
}<br />
<br />
int main(void)<br />
{<br />
struct evbuffer *evbuf;<br />
<br />
evbuf = evbuffer_new();<br />
if (evbuf == NULL) {<br />
fprintf(stderr, "%s(): evbuffer_new() failed.\n", __func__);<br />
exit(1);<br />
}<br />
<br />
/* Add "gslin" into buffer. */<br />
u_char *buf1 = "gslin";<br />
printf("* Add \"\e[1;33m%s\e[m\".\n", buf1);<br />
evbuffer_add(evbuf, buf1, strlen(buf1));<br />
printbuf(evbuf);<br />
<br />
u_char *buf2 = " is reading.\nAnd he is at home.\nLast.";<br />
printf("* Add \"\e[1;33m%s\e[m\".\n", buf2);<br />
evbuffer_add(evbuf, buf2, strlen(buf2));<br />
printbuf(evbuf);<br />
<br />
evbuffer_free(evbuf);<br />
}<br />
</code></pre>
<div style="clear: both; padding-bottom: 0.25em"></div>
<p>&nbsp;</p>
</div>
 <img src ="http://www.blogjava.net/jinfeng_wang/aggbug/318479.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jinfeng_wang/" target="_blank">jinfeng_wang</a> 2010-04-16 10:29 <a href="http://www.blogjava.net/jinfeng_wang/archive/2010/04/16/318479.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>亿级数据的高并发通用搜索引擎架构设计zz</title><link>http://www.blogjava.net/jinfeng_wang/archive/2010/04/15/318434.html</link><dc:creator>jinfeng_wang</dc:creator><author>jinfeng_wang</author><pubDate>Thu, 15 Apr 2010 08:35:00 GMT</pubDate><guid>http://www.blogjava.net/jinfeng_wang/archive/2010/04/15/318434.html</guid><wfw:comment>http://www.blogjava.net/jinfeng_wang/comments/318434.html</wfw:comment><comments>http://www.blogjava.net/jinfeng_wang/archive/2010/04/15/318434.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jinfeng_wang/comments/commentRss/318434.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jinfeng_wang/services/trackbacks/318434.html</trackback:ping><description><![CDATA[http://blog.s135.com/post/385/<br />
http://blog.s135.com/post/360/<br />
<br />
<br />
曾经在七月，写过一篇文章──《<a href="http://blog.s135.com/post/360.htm" target="_blank">基于Sphinx+MySQL的千万级数据全文检索（搜索引擎）架构设计</a>》，前公司的分类信息搜索基于此架构，效果明显，甚至将很大一部分带Where条件的MySQL SQL查询，都改用了Sphinx+MySQL搜索。但是，这套架构仍存在局限：一是MySQL本身的并发能力有限，在200～300个并发连接下，查询和更新就比较慢了；二是由于MySQL表的主键与Sphinx索引的ID一一对应，从而无法跨多表建立整站查询，而且新增加类别还得修改配置文件，比较麻烦；三是因为和MySQL集成，无法发挥出Sphinx的优势。<br />
<br />
　　最近，我设计出了下列这套最新的搜索引擎架构，目前已经写出&#8220;搜索查询接口&#8221;和&#8220;索引更新接口&#8221;的beta版。经测试，在一台&#8220;奔腾四 3.6GHz 双核CPU、2GB内存&#8221;的普通PC机，7000万条索引记录的条件下，&#8220;搜索查询接口&#8221;平均查询速度为0.0XX秒（查询速度已经达到百度、谷歌、搜狗、中国雅虎等搜索引擎的水平，详见文章末尾的&#8220;附2&#8221;），并且能够支撑高达5000的并发连接；而&#8220;索引更新接口&#8221;进行数据分析、入队列、返回信息给用户的全过程，高达1500 Requests/Sec。<br />
<br />
　　&#8220;队列控制器&#8221;这一部分是核心，它要控制队列读取，更新MySQL主表与增量表，更新搜索引擎数据存储层Tokyo Tyrant，准实时（1分钟内）完成更新Sphinx增量索引，定期合并Sphinx索引。我预计在这周写出beta版。<br />
<br />
<a href="http://blog.s135.com/attachment/200812/search.gif" target="_blank"><img class="insertimage" title="点击在新窗口中浏览此图片" alt="点击在新窗口中浏览此图片" src="http://blog.s135.com/attachment/200812/search.gif" border="0" /></a><br />
<br />
　　<span style="font-size: 14px"><strong>图示说明：</strong></span><br />
　　<strong>1、搜索查询接口：</strong><br />
<a name="entrymore"></a>　　①、Web应用服务器通过HTTP POST/GET方式，将搜索关键字等条件，传递给搜索引擎服务器的search.php接口；<br />
　　②③、search.php通过Sphinx的API（我根据最新的Sphinx 0.9.9-rc1 API，改写了一个C语言的PHP扩展sphinx.so），查询Sphinx索引服务，取得满足查询条件的搜索引擎唯一ID（15位搜索唯一ID：前5位类别ID+后10位原数据表主键ID）列表；<br />
　　④⑤、search.php将这些ID号作为key，通过Memcache协议一次性从Tokyo Tyrant中mget取回ID号对应的文本数据。<br />
　　⑥⑦、search.php将搜索结果集，按查询条件，进行摘要和关键字高亮显示处理，以JSON格式或XML格式返回给Web应用服务器。<br />
<br />
　　<strong>2、索引更新接口：</strong><br />
　　⑴、Web应用服务器通过HTTP POST/GET方式，将要增加、删除、更新的内容告知搜索服务器的update.php接口；<br />
　　⑵、update.php将接收到的信息处理后，写入TT高速队列（我基于Tokyo Tyrant做的一个队列系统）；<br />
　　注：这两步的速度可达到1500次请求/秒以上，可应对6000万PV的搜索索引更新调用。<br />
<br />
　　<strong>3、搜索索引与数据存储控制：</strong><br />
　　㈠、&#8220;队列控制器&#8221;守护进程从TT高速队列中循环读取信息（每次50条，直到末尾）；<br />
　　㈡、&#8220;队列控制器&#8221;将读取出的信息写入搜索引擎数据存储层Tokyo Tyrant；<br />
　　㈢、&#8220;队列控制器&#8221;将读取出的信息<strong>异步</strong>写入MySQL主表（这张主表按500万条记录进行分区，仅作为数据永久性备份用）；<br />
　　㈣、&#8220;队列控制器&#8221;将读取出的信息写入MySQL增量表；<br />
　　㈤、&#8220;队列控制器&#8221;在1分钟内，触发Sphinx更新增量索引，Sphinx的indexer会将MySQL增量表作为数据源，建立增量索引。Sphinx的增量索引和作为数据源的MySQL增量表成对应关系；<br />
　　㈥、&#8220;队列控制器&#8221;每间隔3小时，短暂停止从TT高速队列中读取信息，并触发Sphinx将增量索引合并入主索引（这个过程非常快），同时清空MySQL增量表（保证了MySQL增量表的记录数始终只有几千条至几十万条，大大加快Sphinx增量索引更新速度），然后恢复从TT高速队列中取出数据，写入MySQL增量表。<br />
<br />
　　<span style="font-size: 14px"><strong>本架构使用的开源软件：</strong></span><br />
　　1、Sphinx 0.9.9-rc1<br />
　　2、Tokyo Tyrant 1.1.9<br />
　　3、MySQL 5.1.30<br />
　　4、Nginx 0.7.22<br />
　　5、PHP 5.2.6<br />
<br />
　　<span style="font-size: 14px"><strong>本架构自主研发的程序：</strong></span><br />
　　1、搜索查询接口（search.php）<br />
　　2、索引更新接口（update.php）<br />
　　3、队列控制器<br />
　　4、Sphinx 0.9.9-rc1 API的PHP扩展（sphinx.so）<br />
　　5、基于Tokyo Tyrant的高速队列系统<br />
<br />
<br />
<br />
<br />
<br />
在DELL PowerEdge 6850服务器（四颗64 位Inter Xeon MP 7110N处理器 / 8GB内存）、RedHat AS4 Linux操作系统、MySQL 5.1.26、MyISAM存储引擎、key_buffer=1024M环境下实测，单表1000万条记录的数据量（这张MySQL表拥有int、datetime、varchar、text等类型的10多个字段，只有主键，无其它索引），用主键（PRIMARY KEY）作为WHERE条件进行SQL查询，速度非常之快，只耗费0.01秒。<br />
<br />
　　出自俄罗斯的开源全文搜索引擎软件<a href="http://www.sphinxsearch.com/" target="_blank">Sphinx</a>，单一索引最大可包含1亿条记录，在1千万条记录情况下的查询速度为0.x秒（毫秒级）。Sphinx创建索引的速度为：创建100万条记录的索引只需3～4分钟，创建1000万条记录的索引可以在50分钟内完成，而只包含最新10万条记录的增量索引，重建一次只需几十秒。<br />
<br />
　　基于以上几点，我设计出了这套搜索引擎架构。在生产环境运行了一周，效果非常不错。有时间我会专为配合Sphinx搜索引擎，开发一个逻辑简单、速度快、占用内存低、非表锁的MySQL存储引擎插件，用来代替MyISAM引擎，以解决MyISAM存储引擎在频繁更新操作时的锁表延迟问题。另外，分布式搜索技术上已无任何问题。<br />
<br />
<hr />
<br />
　　<span style="font-size: 14px"><strong>一、搜索引擎架构设计：</strong></span><br />
　　<strong>1、搜索引擎架构图：</strong><br />
　　<a href="http://blog.s135.com/attachment/200807/sphinx.png" target="_blank"><img class="insertimage" title="点击在新窗口中浏览此图片" alt="点击在新窗口中浏览此图片" src="http://blog.s135.com/attachment/200807/sphinx.png" border="0" /></a><br />
<br />
　　<strong>2、搜索引擎架构设计思路：</strong><br />
　　<strong>(1)、调用方式最简化：</strong><br />
　　尽量方便前端Web工程师，只需要一条简单的SQL语句&#8220;SELECT ... FROM myisam_table JOIN sphinx_table ON (sphinx_table.sphinx_id=myisam_table.id) WHERE query='...';&#8221;即可实现高效搜索。<br />
<br />
　　<strong>(2)、创建索引、查询速度快：</strong><br />
　　①、Sphinx Search 是由俄罗斯人Andrew Aksyonoff 开发的高性能全文搜索软件包，在GPL与商业协议双许可协议下发行。<br />
　　<strong>Sphinx的特征：</strong><br />
　　&#8226;Sphinx支持高速建立索引（可达10MB/秒，而Lucene建立索引的速度是1.8MB/秒）<br />
　　&#8226;高性能搜索（在2-4 GB的文本上搜索，平均0.1秒内获得结果）<br />
　　&#8226;高扩展性（实测最高可对100GB的文本建立索引，单一索引可包含1亿条记录）<br />
　　&#8226;支持分布式检索<br />
　　&#8226;支持基于短语和基于统计的复合结果排序机制<br />
　　&#8226;支持任意数量的文件字段（数值属性或全文检索属性）<br />
　　&#8226;支持不同的搜索模式（&#8220;完全匹配&#8221;，&#8220;短语匹配&#8221;和&#8220;任一匹配&#8221;）<br />
　　&#8226;支持作为Mysql的存储引擎<br />
<br />
　　②、通过国外《High Performance MySQL》专家组的测试可以看出，根据主键进行查询的类似&#8220;SELECT ... FROM ... WHERE id = ...&#8221;的SQL语句（其中id为PRIMARY KEY），每秒钟能够处理10000次以上的查询，而普通的SELECT查询每秒只能处理几十次到几百次：<br />
　　<a href="http://blog.s135.com/attachment/200807/mysqlselect.png" target="_blank"><img class="insertimage" title="点击在新窗口中浏览此图片" alt="点击在新窗口中浏览此图片" src="http://blog.s135.com/attachment/200807/mysqlselect.png" border="0" /></a><br />
<br />
　　③、Sphinx不负责文本字段的存储。假设将数据库的id、date、title、body字段，用sphinx建立搜索索引。根据关键字、时间、类别、范围等信息查询一下sphinx，sphinx只会将查询结果的ID号等非文本信息告诉我们。要显示title、body等信息，还需要根据此ID号去查询MySQL数据库，或者从Memcachedb等其他的存储中取得。安装SphinxSE作为MySQL的存储引擎，将MySQL与Sphinx结合起来，是一种便捷的方法。<br />
　　创建一张Sphinx类型表，将MyISAM表的主键ID和Sphinx表的ID作一个JOIN联合查询。这样，对于MyISAM表来所，只相当于一个WHERE id=...的主键查询，WHERE后的条件都交给Sphinx去处理，可以充分发挥两者的优势，实现高速搜索查询。<br />
<br />
　　<strong>(3)、按服务类型进行分离：</strong><br />
　　为了保证数据的一致性，我在配置Sphinx读取索引源的MySQL数据库时，进行了锁表。Sphinx读取索引源的过程会耗费一定时间，由于MyISAM存储引擎的读锁和写锁是互斥的，为了避免写操作被长时间阻塞，导致数据库同步落后跟不上，我将提供&#8220;搜索查询服务&#8221;的和提供&#8220;索引源服务&#8221;的MySQL数据库进行了分开。监听3306端口的MySQL提供&#8220;搜索查询服务&#8221;，监听3406端口的MySQL提供&#8220;索引源服务&#8221;。<br />
<br />
　　<strong>(4)、&#8220;主索引＋增量索引&#8221;更新方式：</strong><br />
　　一般网站的特征：信息发布较为频繁；刚发布完的信息被编辑、修改的可能性大；两天以前的老帖变动性较小。<br />
　　基于这个特征，我设计了Sphinx主索引和增量索引。对于前天17:00之前的记录建立主索引，每天凌晨自动重建一次主索引；对于前天17:00之后到当前最新的记录，间隔3分钟自动重建一次增量索引。<br />
<br />
　　<strong>(5)、&#8220;Ext3文件系统＋tmpfs内存文件系统&#8221;相结合：</strong><br />
　　为了避免每3分钟重建增量索引导致磁盘IO较重，从而引起系统负载上升，我将主索引文件创建在磁盘，增量索引文件创建在tmpfs内存文件系统&#8220;/dev/shm/&#8221;内。&#8220;/dev/shm/&#8221;内的文件全部驻留在内存中，读写速度非常快。但是，重启服务器会导致&#8220;/dev/shm/&#8221;内的文件丢失，针对这个问题，我会在服务器开机时自动创建&#8220;/dev/shm/&#8221;内目录结构和Sphinx增量索引。<br />
<br />
　　<strong>(6)、中文分词词库：</strong><br />
　　我根据&#8220;自整理的中文分词库&#8221;＋&#8220;搜狗拼音输入法细胞词库&#8221;＋&#8220;LibMMSeg高频字库&#8221;＋... 综合整理成一份中文分词词库，出于某些考虑暂不提供。你可以使用LibMMSeg自带的中文分词词库。
 <img src ="http://www.blogjava.net/jinfeng_wang/aggbug/318434.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jinfeng_wang/" target="_blank">jinfeng_wang</a> 2010-04-15 16:35 <a href="http://www.blogjava.net/jinfeng_wang/archive/2010/04/15/318434.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>用rsync实现网站镜像和备份 zz</title><link>http://www.blogjava.net/jinfeng_wang/archive/2010/04/14/318279.html</link><dc:creator>jinfeng_wang</dc:creator><author>jinfeng_wang</author><pubDate>Wed, 14 Apr 2010 09:14:00 GMT</pubDate><guid>http://www.blogjava.net/jinfeng_wang/archive/2010/04/14/318279.html</guid><wfw:comment>http://www.blogjava.net/jinfeng_wang/comments/318279.html</wfw:comment><comments>http://www.blogjava.net/jinfeng_wang/archive/2010/04/14/318279.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jinfeng_wang/comments/commentRss/318279.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jinfeng_wang/services/trackbacks/318279.html</trackback:ping><description><![CDATA[<span class="Apple-style-span" style="word-spacing: 0px; font: 12px 'MS PGothic'; text-transform: none; color: rgb(0,0,0); text-indent: 0px; white-space: normal; letter-spacing: normal; border-collapse: separate; orphans: 2; widows: 2; webkit-border-horizontal-spacing: 0px; webkit-border-vertical-spacing: 0px; webkit-text-decorations-in-effect: none; webkit-text-size-adjust: auto; webkit-text-stroke-width: 0px"><span class="Apple-style-span" style="line-height: 18px; border-collapse: collapse">
<p><br class="Apple-interchange-newline" />
2、rsync的配置</p>
<p>对于rsync服务器来说，最重要和复杂的就是它的配置了。rsync服务器的配置文件为/etc/rsyncd.conf，其控制认证、访问、日志记录等等。</p>
<p>该文件是由一个或多个模块结构组成。一个模块定义以方括弧中的模块名开始，直到下一个模块定义开始或者文件结束，模块中包含格式为name = value的参数定义。每个模块其实就对应需要备份的一个目录树，比方说在我们的实例环境中，有三个目录树需要备份：/www/、/home/web_user1/和/home/web_user2/，那么就需要在配置文件中定义三个模块，分别对应三个目录树。</p>
<p>配置文件是行为单位的，也就是每个新行都表示一个新的注释、模块定义或者参数赋值。以#开始的行表示注释，以""结束的行表示下面一行是该行的继续。参数赋值中等号后可能是一个大小写不敏感的字符串、一个以trure/false表示的布尔值。</p>
<p>全局参数</p>
<p>在文件中[modlue]之前的所有参数都是全局参数，当然也可以在全局参数部分定义模块参数，这时候该参数的值就是所有模块的默认值。</p>
<p>motd file</p>
<p>"motd file"参数用来指定一个消息文件，当客户连接服务器时该文件的内容显示给客户，默认是没有motd文件的。</p>
<p>log file</p>
<p>"log file"指定rsync的日志文件，而不将日志发送给syslog。</p>
<p>pid file</p>
<p>指定rsync的pid文件。</p>
<p>syslog facility</p>
<p>指定rsync发送日志消息给syslog时的消息级别，常见的消息级别是：uth, authpriv, cron, daemon, ftp, kern, lpr, mail, news, security, sys-log, user, uucp, local0, local1, local2, local3,local4, local5, local6和local7。默认值是daemon。</p>
<p>模块参数</p>
<p>在全局参数之后就需要定义一个或多个模块了，模块中可以定义以下参数：</p>
<p>comment</p>
<p>给模块指定一个描述，该描述连同模块名在客户连接得到模块列表时显示给客户。默认没有描述定义。</p>
<p>path</p>
<p>指定该模块的供备份的目录树路径，该参数是必须指定的。</p>
<p>use chroot</p>
<p>如果"use chroot"指定为true，那么rsync在传输文件以前首先chroot到path参数所指定的目录下。这样做的原因是实现额外的安全防护，但是缺点是需要以roots权限，并且不能备份指向外部的符号连接所指向的目录文件。默认情况下chroot值为true。</p>
<p>max connections</p>
<p>指定该模块的最大并发连接数量以保护服务器，超过限制的连接请求将被告知随后再试。默认值是0，也就是没有限制。</p>
<p>lock file</p>
<p>指定支持max connections参数的锁文件，默认值是/var/run/rsyncd.lock。</p>
<p>read only</p>
<p>该选项设定是否允许客户上载文件。如果为true那么任何上载请求都会失败，如果为false并且服务器目录读写权限允许那么上载是允许的。默认值为true。</p>
<p>list</p>
<p>该选项设定当客户请求可以使用的模块列表时，该模块是否应该被列出。如果设置该选项为false，可以创建隐藏的模块。默认值是true。</p>
<p>uid</p>
<p>该选项指定当该模块传输文件时守护进程应该具有的uid，配合gid选项使用可以确定哪些可以访问怎么样的文件权限，默认值是"nobody"。</p>
<p>gid</p>
<p>该选项指定当该模块传输文件时守护进程应该具有的gid。默认值为"nobody"。</p>
<p>exlude</p>
<p>用来指定多个由空格隔开的多个模式列表，并将其添加到exclude列表中。这等同于在客户端命令中使用--exclude来指定模式，不过配置文件中指定的exlude模式不会传递给客户端，而仅仅应用于服务器。一个模块只能指定一个exlude选项，但是可以在模式前面使用"-"和"+"来指定是exclude还是include。</p>
<p>但是需要注意的一点是该选项有一定的安全性问题，客户很有可能绕过exlude列表，如果希望确保特定的文件不能被访问，那就最好结合uid/gid选项一起使用。</p>
<p>exlude from</p>
<p>指定一个包含exclude模式的定义的文件名，服务器从该文件中读取exlude列表定义。</p>
<p>include</p>
<p>用来指定多个由空格隔开的多个rsync并应该exlude的模式列表。这等同于在客户端命令中使用--include来指定模式，结合include和exlude可以定义复杂的exlude/include规则 。一个模块只能指定一个include选项，但是可以在模式前面使用"-"和"+"来指定是exclude还是include。</p>
<p>include from</p>
<p>指定一个包含include模式的定义的文件名，服务器从该文件中读取include列表定义。</p>
<p>auth users</p>
<p>该选项指定由空格或逗号分隔的用户名列表，只有这些用户才允许连接该模块。这里的用户和系统用户没有任何关系。如果"auth users"被设置，那么客户端发出对该模块的连接请求以后会被rsync请求challenged进行验证身份这里使用的challenge/response认证协议。用户的名和密码以明文方式存放在"secrets file"选项指定的文件中。默认情况下无需密码就可以连接模块(也就是匿名方式)。</p>
<p>secrets file</p>
<p>该选项指定一个包含定义用户名:密码对的文件。只有在"auth users"被定义时，该文件才有作用。文件每行包含一个username:passwd对。一般来说密码最好不要超过8个字符。没有默认的secures file名，需要限式指定一个。(例如：/etc/rsyncd.secrets)</p>
<p>strict modes</p>
<p>该选项指定是否监测密码文件的权限，如果该选项值为true那么密码文件只能被rsync服务器运行身份的用户访问，其他任何用户不可以访问该文件。默认值为true。</p>
<p>hosts allow</p>
<p>该选项指定哪些IP的客户允许连接该模块。客户模式定义可以是以下形式：</p>
<p>o xxx.xxx.xxx.xxx，客户主机只有完全匹配该IP才允许访问。例如：192.167.0.1</p>
<p>o a.b.c.d/n，属于该网络的客户都允许连接该模块。例如：192.168.0.0/24</p>
<p>o a.b.c.d/e.f.g.h，属于该网络的客户都允许连接该模块。例如：192.168.0.0/255.255.255.0</p>
<p>o 一个主机名，客户主机只有拥有该主机名才允许访问，例如：backup.linuxaid.com.cn。</p>
<p><br />
o *.linuxaid.com.cn，所有属于该域的主机都允许。</p>
<p>默认是允许所有主机连接。</p>
<p>hosts deny</p>
<p>指定不允许连接rsync服务器的机器，可以使用hosts allow的定义方式来进行定义。默认是没有hosts deny定义。</p>
<p>ignore errors</p>
<p>指定rsyncd在判断是否运行传输时的删除操作时忽略server上的IP错误，一般来说rsync在出现IO错误时将将跳过--delete操作，以防止因为暂时的资源不足或其它IO错误导致的严重问题。</p>
<p>ignore nonreadable</p>
<p>指定rysnc服务器完全忽略那些用户没有访问权限的文件。这对于在需要备份的目录中有些文件是不应该被备份者得到的情况是有意义的。</p>
<p>transfer logging</p>
<p>使rsync服务器使用ftp格式的文件来记录下载和上载操作在自己单独的日志中。</p>
<p>log format</p>
<p>通过该选项用户在使用transfer logging可以自己定制日志文件的字段。其格式是一个包含格式定义符的字符串，可以使用的格式定义符如下所示：</p>
<p>o %h 远程主机名</p>
<p>o %a 远程IP地址</p>
<p>o %l 文件长度字符数</p>
<p>o %p 该次rsync会话的进程id</p>
<p>o %o 操作类型："send"或"recv"</p>
<p>o %f 文件名</p>
<p>o %P 模块路径</p>
<p>o %m 模块名</p>
<p>o %t 当前时间</p>
<p>o %u 认证的用户名(匿名时是null)</p>
<p>o %b 实际传输的字节数</p>
<p>o %c 当发送文件时，该字段记录该文件的校验码</p>
<p>默认log格式为："%o %h [%a] %m (%u) %f %l"，一般来说,在每行的头上会添加"%t [%p] "。在源代码中同时发布有一个叫rsyncstats的perl脚本程序来统计这种格式的日志文件。</p>
<p>timeout</p>
<p>通过该选项可以覆盖客户指定的IP超时时间。通过该选项可以确保rsync服务器不会永远等待一个崩溃的客户。超时单位为秒钟，0表示没有超时定义，这也是默认值。对于匿名rsync服务器来说，一个理想的数字是600。</p>
<p>refuse options</p>
<p>通过该选项可以定义一些不允许客户对该模块使用的命令参数列表。这里必须使用命令全名，而不能是简称。但发生拒绝某个命令的情况时服务器将报告错误信息然后退出。如果要防止使用压缩，应该是："dont compress = *"。</p>
<p>dont compress</p>
<p>用来指定那些不进行压缩处理再传输的文件，默认值是</p>
<p>*.gz *.tgz *.zip *.z *.rpm *.deb *.iso *.bz2 *.tbz</p>
<p>rsync客户命令</p>
<p>在对rsync服务器配置结束以后，下一步就需要在客户端发出rsync命令来实现将服务器端的文件备份到客户端来。rsync是一个功能非常强大的工具，其命令也有很多功能特色选项，我们下面就对它的选项一一进行分析说明。</p>
<p>首先，rsync的命令格式可以为：</p>
<p>rsync [OPTION]... SRC [SRC]... [USER@]HOST:DEST</p>
<p>rsync [OPTION]... [USER@]HOST:SRC DEST</p>
<p>rsync [OPTION]... SRC [SRC]... DEST</p>
<p>rsync [OPTION]... [USER@]HOST::SRC [DEST]</p>
<p>rsync [OPTION]... SRC [SRC]... [USER@]HOST::DEST</p>
<p>rsync [OPTION]... rsync://[USER@]HOST[:PORT]/SRC [DEST]<span class="Apple-converted-space">&nbsp;</span><br />
rsync有六种不同的工作模式：</p>
<p>拷贝本地文件；当SRC和DES路径信息都不包含有单个冒号":"分隔符时就启动这种工作模式。</p>
<p>使用一个远程shell程序（如rsh、ssh）来实现将本地机器的内容拷贝到远程机器。当DST路径地址包含单个冒号":"分隔符时启动该模式。</p>
<p>使用一个远程shell程序（如rsh、ssh）来实现将远程机器的内容拷贝到本地机器。当SRC地址路径包含单个冒号":"分隔符时启动该模式。</p>
<p>从远程rsync服务器中拷贝文件到本地机。当SRC路径信息包含"::"分隔符时启动该模式。</p>
<p>从本地机器拷贝文件到远程rsync服务器中。当DST路径信息包含"::"分隔符时启动该模式。</p>
<p>列远程机的文件列表。这类似于rsync传输，不过只要在命令中省略掉本地机信息即可。</p>
<p>1、用法</p>
<p>在使用rsync传输文件时，需要指定一个源和一个目的，其中一个可能是远程机器的资源信息。例如：</p>
<p>rsync *.c foo:src/</p>
<p>表示将传输当前目录下所有以.c结尾的文件到机器foo的src目录下。如果任何文件已经存在于远程系统，则会调用远程更新协议来实现仅仅传输那些更新过的文件。</p>
<p>rsync -avz foo:src/bar /data/tmp</p>
<p>该命令则递归地传输机器foo上的src/bar目录下的所有内容到本地/data/tmp/bar目录中。文件以归档模式进行传输，以确保符号链结、属性、权限、属主等信息在传输中都被保存。此外，可以使用压缩技术来加快数据传输：</p>
<p>rsync -avz foo:src/bar/ /data/tmp</p>
<p>路径信息以"/"结尾时表示拷贝该目录，而不以"/"结尾表示拷贝该目录。当配合使用--delete选项时这两种情况的区别将会表现出来。</p>
<p>也可以以本地模式来使用rsync，如果SRC和DST路径中都没有任何":"符号则表示该命令运行在本地模式，等同于cp命令。</p>
<p>rsync somehost.mydomain.com::</p>
<p>这种模式则将会列出somehost.mydomain.com.可以访问的所有模块信息。</p>
<p>选项说明</p>
<p>-v, --verbose 详细模式输出<span class="Apple-converted-space">&nbsp;</span><br />
-q, --quiet 精简输出模式<span class="Apple-converted-space">&nbsp;</span><br />
-c, --checksum 打开校验开关，强制对文件传输进行校验<span class="Apple-converted-space">&nbsp;</span><br />
-a, --archive 归档模式，表示以递归方式传输文件，并保持所有文件属性，等于-rlptgoD<span class="Apple-converted-space">&nbsp;</span><br />
-r, --recursive 对子目录以递归模式处理<span class="Apple-converted-space">&nbsp;</span><br />
-R, --relative 使用相对路径信息</p>
<p>rsync foo/bar/foo.c remote:/tmp/</p>
<p>则在/tmp目录下创建foo.c文件，而如果使用-R参数：</p>
<p>rsync -R foo/bar/foo.c remote:/tmp/</p>
<p>则会创建文件/tmp/foo/bar/foo.c，也就是会保持完全路径信息。</p>
<p>-b, --backup 创建备份，也就是对于目的已经存在有同样的文件名时，将老的文件重新命名为~filename。可以使用--suffix选项来指定不同的备份文件前缀。<span class="Apple-converted-space">&nbsp;</span><br />
--backup-dir 将备份文件(如~filename)存放在在目录下。<span class="Apple-converted-space">&nbsp;</span><br />
-suffix=SUFFIX 定义备份文件前缀<span class="Apple-converted-space">&nbsp;</span><br />
-u, --update 仅仅进行更新，也就是跳过所有已经存在于DST，并且文件时间晚于要备份的文件。(不覆盖更新的文件)<span class="Apple-converted-space">&nbsp;</span><br />
-l, --links 保留软链结<span class="Apple-converted-space">&nbsp;</span><br />
-L, --copy-links 想对待常规文件一样处理软链结<span class="Apple-converted-space">&nbsp;</span><br />
--copy-unsafe-links 仅仅拷贝指向SRC路径目录树以外的链结<span class="Apple-converted-space">&nbsp;</span><br />
--safe-links 忽略指向SRC路径目录树以外的链结<span class="Apple-converted-space">&nbsp;</span><br />
-H, --hard-links 保留硬链结<span class="Apple-converted-space">&nbsp;</span><br />
-p, --perms 保持文件权限<span class="Apple-converted-space">&nbsp;</span><br />
-o, --owner 保持文件属主信息<span class="Apple-converted-space">&nbsp;</span><br />
-g, --group 保持文件属组信息<span class="Apple-converted-space">&nbsp;</span><br />
-D, --devices 保持设备文件信息<span class="Apple-converted-space">&nbsp;</span><br />
-t, --times 保持文件时间信息<span class="Apple-converted-space">&nbsp;</span><br />
-S, --sparse 对稀疏文件进行特殊处理以节省DST的空间<span class="Apple-converted-space">&nbsp;</span><br />
-n, --dry-run现实哪些文件将被传输<span class="Apple-converted-space">&nbsp;</span><br />
-W, --whole-file 拷贝文件，不进行增量检测<span class="Apple-converted-space">&nbsp;</span><br />
-x, --one-file-system 不要跨越文件系统边界<span class="Apple-converted-space">&nbsp;</span><br />
-B, --block-size=SIZE 检验算法使用的块尺寸，默认是700字节<span class="Apple-converted-space">&nbsp;</span><br />
-e, --rsh=COMMAND 指定替代rsh的shell程序<span class="Apple-converted-space">&nbsp;</span><br />
--rsync-path=PATH 指定远程服务器上的rsync命令所在路径信息<span class="Apple-converted-space">&nbsp;</span><br />
-C, --cvs-exclude 使用和CVS一样的方法自动忽略文件，用来排除那些不希望传输的文件<span class="Apple-converted-space">&nbsp;</span><br />
--existing 仅仅更新那些已经存在于DST的文件，而不备份那些新创建的文件<span class="Apple-converted-space">&nbsp;</span><br />
--delete 删除那些DST中SRC没有的文件<span class="Apple-converted-space">&nbsp;</span><br />
--delete-excluded 同样删除接收端那些被该选项指定排除的文件<span class="Apple-converted-space">&nbsp;</span><br />
--delete-after 传输结束以后再删除<span class="Apple-converted-space">&nbsp;</span><br />
--ignore-errors 及时出现IO错误也进行删除<span class="Apple-converted-space">&nbsp;</span><br />
--max-delete=NUM 最多删除NUM个文件<span class="Apple-converted-space">&nbsp;</span><br />
--partial 保留那些因故没有完全传输的文件，以是加快随后的再次传输<span class="Apple-converted-space">&nbsp;</span><br />
--force 强制删除目录，即使不为空<span class="Apple-converted-space">&nbsp;</span><br />
--numeric-ids 不将数字的用户和组ID匹配为用户名和组名<span class="Apple-converted-space">&nbsp;</span><br />
--timeout=TIME IP超时时间，单位为秒<span class="Apple-converted-space">&nbsp;</span><br />
-I, --ignore-times 不跳过那些有同样的时间和长度的文件<span class="Apple-converted-space">&nbsp;</span><br />
--size-only 当决定是否要备份文件时，仅仅察看文件大小而不考虑文件时间<span class="Apple-converted-space">&nbsp;</span><br />
--modify-window=NUM 决定文件是否时间相同时使用的时间戳窗口，默认为0<span class="Apple-converted-space">&nbsp;</span><br />
-T --temp-dir=DIR 在DIR中创建临时文件<span class="Apple-converted-space">&nbsp;</span><br />
--compare-dest=DIR 同样比较DIR中的文件来决定是否需要备份<span class="Apple-converted-space">&nbsp;</span><br />
-P 等同于 --partial<span class="Apple-converted-space">&nbsp;</span><br />
--progress 显示备份过程<span class="Apple-converted-space">&nbsp;</span><br />
-z, --compress 对备份的文件在传输时进行压缩处理<span class="Apple-converted-space">&nbsp;</span><br />
--exclude=PATTERN 指定排除不需要传输的文件模式<span class="Apple-converted-space">&nbsp;</span><br />
--include=PATTERN 指定不排除而需要传输的文件模式<span class="Apple-converted-space">&nbsp;</span><br />
--exclude-from=FILE 排除FILE中指定模式的文件<span class="Apple-converted-space">&nbsp;</span><br />
--include-from=FILE 不排除FILE指定模式匹配的文件<span class="Apple-converted-space">&nbsp;</span><br />
--version 打印版本信息<span class="Apple-converted-space">&nbsp;</span><br />
--address 绑定到特定的地址<span class="Apple-converted-space">&nbsp;</span><br />
--config=FILE 指定其他的配置文件，不使用默认的rsyncd.conf文件<span class="Apple-converted-space">&nbsp;</span><br />
--port=PORT 指定其他的rsync服务端口<span class="Apple-converted-space">&nbsp;</span><br />
--blocking-io 对远程shell使用阻塞IO<span class="Apple-converted-space">&nbsp;</span><br />
-stats 给出某些文件的传输状态<span class="Apple-converted-space">&nbsp;</span><br />
--progress 在传输时现实传输过程<span class="Apple-converted-space">&nbsp;</span><br />
--log-format=FORMAT 指定日志文件格式<span class="Apple-converted-space">&nbsp;</span><br />
--password-file=FILE 从FILE中得到密码<span class="Apple-converted-space">&nbsp;</span><br />
--bwlimit=KBPS 限制I/O带宽，KBytes per second<span class="Apple-converted-space">&nbsp;</span><br />
-h, --help 显示帮助信息</p>
<p>实例分析</p>
<p>这里假设有两台服务器：A和B。其中A是主web服务器，具有域名<a style="font-size: 9pt; color: black; text-decoration: none" href="http://www.linuxaid.com.cn(202.99.11.120/">www.linuxaid.com.cn(202.99.11.120</a>)，B服务器是备份机，其域名为backup.linuxaid.com.cn(202.99.11.121)。其中A的web内容存放在以下几个地方：/www/和/home/web_user1/和/home/web_user2/。我们需要在备份机B上建立对这几个目录内容的备份。</p>
<p>服务器配置实例</p>
<p>那么在<a style="font-size: 9pt; color: black; text-decoration: none" href="http://www.linuxaid.com.cn/">www.linuxaid.com.cn</a>上创建rsyncd的配置文件/etc/rsyncd.conf，内容如下：</p>
<p>uid = nobody<span class="Apple-converted-space">&nbsp;</span><br />
gid = nobody<span class="Apple-converted-space">&nbsp;</span><br />
use chroot = no<span class="Apple-converted-space">&nbsp;</span><br />
max connections = 4<span class="Apple-converted-space">&nbsp;</span><br />
pid file = /var/run/rsyncd.pid<span class="Apple-converted-space">&nbsp;</span><br />
lock file = /var/run/rsync.lock<span class="Apple-converted-space">&nbsp;</span><br />
log file = /var/log/rsyncd.log</p>
<p>[www]<span class="Apple-converted-space">&nbsp;</span><br />
path = /www/<span class="Apple-converted-space">&nbsp;</span><br />
ignore errors<span class="Apple-converted-space">&nbsp;</span><br />
read only = true<span class="Apple-converted-space">&nbsp;</span><br />
list = false<span class="Apple-converted-space">&nbsp;</span><br />
hosts allow = 202.99.11.121<span class="Apple-converted-space">&nbsp;</span><br />
hosts deny = 0.0.0.0/32<span class="Apple-converted-space">&nbsp;</span><br />
auth users = backup<span class="Apple-converted-space">&nbsp;</span><br />
secrets file = /etc/backserver.pas</p>
<p>[web_user1]<span class="Apple-converted-space">&nbsp;</span><br />
path = /home/web_user1/<span class="Apple-converted-space">&nbsp;</span><br />
ignore errors<span class="Apple-converted-space">&nbsp;</span><br />
read only = true<span class="Apple-converted-space">&nbsp;</span><br />
list = false<span class="Apple-converted-space">&nbsp;</span><br />
hosts allow = 202.99.11.121<span class="Apple-converted-space">&nbsp;</span><br />
hosts deny = 0.0.0.0/32<span class="Apple-converted-space">&nbsp;</span><br />
uid = web_user1<span class="Apple-converted-space">&nbsp;</span><br />
gid = web_user1<span class="Apple-converted-space">&nbsp;</span><br />
auth users = backup<span class="Apple-converted-space">&nbsp;</span><br />
secrets file = /etc/backserver.pas</p>
<p>[web_user2]<span class="Apple-converted-space">&nbsp;</span><br />
path = /home/web_user2/<span class="Apple-converted-space">&nbsp;</span><br />
ignore errors<span class="Apple-converted-space">&nbsp;</span><br />
read only = true<span class="Apple-converted-space">&nbsp;</span><br />
list = false<span class="Apple-converted-space">&nbsp;</span><br />
hosts allow = 202.99.11.121<span class="Apple-converted-space">&nbsp;</span><br />
hosts deny = 0.0.0.0/32<span class="Apple-converted-space">&nbsp;</span><br />
uid = web_user2<span class="Apple-converted-space">&nbsp;</span><br />
gid = web_user2<span class="Apple-converted-space">&nbsp;</span><br />
auth users = backup<span class="Apple-converted-space">&nbsp;</span><br />
secrets file = /etc/backserver.pas</p>
<p>这里定义有四个三个模块，分别对应于三个需要备份的目录树。这里只允许202.99.11.121备份本机的数据，并且需要认证。三个模块授权的备份用户都为backup，并且用户信息保存在文件/etc/backserver.pas中，其内容如下：</p>
<p>backup:bk_passwd</p>
<p>并且该文件只能是root用户可读写的，否则rsyncd启动时会出错。这些文件配置完毕以后，就需要在A服务器上启动rsyncd服务器：</p>
<p>rsync --daemon</p>
<p>客户命令示例</p>
<p>/usr/local/bin/rsync -vzrtopg --delete --exclude "logs/" --exclude "conf/ssl.*/" --progress<a style="font-size: 9pt; color: black; text-decoration: none" href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#98;&#97;&#99;&#107;&#117;&#112;&#64;&#50;&#48;&#50;&#46;&#57;&#57;&#46;&#49;&#49;&#46;&#49;&#50;&#48;&#58;&#58;&#119;&#119;&#119;">backup@202.99.11.120::www</a><span class="Apple-converted-space">&nbsp;</span>/backup/www/ --password-file=/etc/rsync.pass</p>
<p>上面这个命令行中-vzrtopg里的v是verbose，z是压缩，r是recursive，topg都是保持文件原有属性如属主、时间的参数。--progress是指显示出详细的进度情况，--delete是指如果服务器端删除了这一文件，那么客户端也相应把文件删除，保持真正的一致。--exclude "logs/" 表示不对/www/logs目录下的文件进行备份。--exclude "conf/ssl.*/"表示不对/www/conf/ssl.*/目录下的文件进行备份。</p>
<p><a style="font-size: 9pt; color: black; text-decoration: none" href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#98;&#97;&#99;&#107;&#117;&#112;&#64;&#50;&#48;&#50;&#46;&#57;&#57;&#46;&#49;&#49;&#46;&#49;&#50;&#48;&#58;&#58;&#119;&#119;&#119;">backup@202.99.11.120::www</a><span class="Apple-converted-space">&nbsp;</span>表示对该命令是对服务器202.99.11.120中的www模块进行备份，backup表示使用backup来对该模块进行备份。</p>
<p>--password-file=/etc/rsync.pass来指定密码文件，这样就可以在脚本中使用而无需交互式地输入验证密码了，这里需要注意的是这份密码文件权限属性要设得只有root可读。</p>
<p>这里将备份的内容存放在备份机的/backup/www/目录下。</p>
<p>[root@linuxaid /]# /usr/local/bin/rsync -vzrtopg --delete --exclude "logs/" --exclude "conf/ssl.*/" --progress<span class="Apple-converted-space">&nbsp;</span><a style="font-size: 9pt; color: black; text-decoration: none" href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#98;&#97;&#99;&#107;&#117;&#112;&#64;&#50;&#48;&#50;&#46;&#57;&#57;&#46;&#49;&#49;&#46;&#49;&#50;&#48;&#58;&#58;&#119;&#119;&#119;">backup@202.99.11.120::www</a><span class="Apple-converted-space">&nbsp;</span>/backup/www/ --password-file=/etc/rsync.pass<span class="Apple-converted-space">&nbsp;</span><br />
receiving file list ... done<span class="Apple-converted-space">&nbsp;</span><br />
./<span class="Apple-converted-space">&nbsp;</span><br />
1<span class="Apple-converted-space">&nbsp;</span><br />
785 (100%)<span class="Apple-converted-space">&nbsp;</span><br />
1.py<span class="Apple-converted-space">&nbsp;</span><br />
4086 (100%)<span class="Apple-converted-space">&nbsp;</span><br />
2.py<span class="Apple-converted-space">&nbsp;</span><br />
10680 (100%)<span class="Apple-converted-space">&nbsp;</span><br />
a<span class="Apple-converted-space">&nbsp;</span><br />
0 (100%)<span class="Apple-converted-space">&nbsp;</span><br />
ip<span class="Apple-converted-space">&nbsp;</span><br />
3956 (100%)<span class="Apple-converted-space">&nbsp;</span><br />
./<span class="Apple-converted-space">&nbsp;</span><br />
wrote 2900 bytes read 145499 bytes 576.34 bytes/sec<span class="Apple-converted-space">&nbsp;</span><br />
total size is 2374927 speedup is 45.34</p>
<p>对其它两个模块操作的命令分别为：</p>
<p>/usr/local/bin/rsync -vzrtopg --delete --progress<span class="Apple-converted-space">&nbsp;</span><a style="font-size: 9pt; color: black; text-decoration: none" href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#98;&#97;&#99;&#107;&#117;&#112;&#64;&#50;&#48;&#50;&#46;&#57;&#57;&#46;&#49;&#49;&#46;&#49;&#50;&#48;&#58;&#58;&#119;&#101;&#98;&#95;&#117;&#115;&#101;&#114;&#49;">backup@202.99.11.120::web_user1</a><span class="Apple-converted-space">&nbsp;</span>/backup/web_user1/ --password-file=/etc/rsync.pass</p>
<p>/usr/local/bin/rsync -vzrtopg --delete --progress<span class="Apple-converted-space">&nbsp;</span><a style="font-size: 9pt; color: black; text-decoration: none" href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#98;&#97;&#99;&#107;&#117;&#112;&#64;&#50;&#48;&#50;&#46;&#57;&#57;&#46;&#49;&#49;&#46;&#49;&#50;&#48;&#58;&#58;&#119;&#101;&#98;&#95;&#117;&#115;&#101;&#114;&#50;">backup@202.99.11.120::web_user2</a><span class="Apple-converted-space">&nbsp;</span>/backup/web_user2/ --password-file=/etc/rsync.pass</p>
<p>可以将客户命令通过crontab -e命令来实现自动备份，如crontab -e：</p>
<p>一些示例脚本</p>
<p>这里这些脚本都是rsync网站上的例子：</p>
<p>1、每隔七天将数据往中心服务器做增量备份</p>
<p>#!/bin/sh</p>
<p># This script does personal backups to a rsync backup server. You will end up<span class="Apple-converted-space">&nbsp;</span><br />
# with a 7 day rotating incremental backup. The incrementals will go<span class="Apple-converted-space">&nbsp;</span><br />
# into subdirectories named after the day of the week, and the current<span class="Apple-converted-space">&nbsp;</span><br />
# full backup goes into a directory called "current"<span class="Apple-converted-space">&nbsp;</span><br />
#<span class="Apple-converted-space">&nbsp;</span><a style="font-size: 9pt; color: black; text-decoration: none" href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#116;&#114;&#105;&#100;&#103;&#101;&#64;&#108;&#105;&#110;&#117;&#120;&#99;&#97;&#114;&#101;&#46;&#99;&#111;&#109;">tridge@linuxcare.com</a></p>
<p># directory to backup<span class="Apple-converted-space">&nbsp;</span><br />
BDIR=/home/$USER</p>
<p># excludes file - this contains a wildcard pattern per line of files to exclude<span class="Apple-converted-space">&nbsp;</span><br />
EXCLUDES=$HOME/cron/excludes</p>
<p># the name of the backup machine<span class="Apple-converted-space">&nbsp;</span><br />
BSERVER=owl</p>
<p># your password on the backup server<span class="Apple-converted-space">&nbsp;</span><br />
export RSYNC_PASSWORD=XXXXXX</p>
<p><br />
########################################################################</p>
<p>BACKUPDIR=`date +%A`<span class="Apple-converted-space">&nbsp;</span><br />
OPTS="--force --ignore-errors --delete-excluded --exclude-from=$EXCLUDES<span class="Apple-converted-space">&nbsp;</span><br />
--delete --backup --backup-dir=/$BACKUPDIR -a"</p>
<p>export PATH=$PATH:/bin:/usr/bin:/usr/local/bin</p>
<p># the following line clears the last weeks incremental directory<span class="Apple-converted-space">&nbsp;</span><br />
[ -d $HOME/emptydir ]' 'mkdir $HOME/emptydir<span class="Apple-converted-space">&nbsp;</span><br />
rsync --delete -a $HOME/emptydir/ $BSERVER::$USER/$BACKUPDIR/<span class="Apple-converted-space">&nbsp;</span><br />
rmdir $HOME/emptydir</p>
<p># now the actual transfer<span class="Apple-converted-space">&nbsp;</span><br />
rsync $OPTS $BDIR $BSERVER::$USER/current</p>
<p>2、备份至一个空闲的硬盘</p>
<p>#!/bin/sh</p>
<p>export PATH=/usr/local/bin:/usr/bin:/bin</p>
<p>LIST="rootfs usr data data2"</p>
<p>for d in $LIST; do<span class="Apple-converted-space">&nbsp;</span><br />
mount /backup/$d<span class="Apple-converted-space">&nbsp;</span><br />
rsync -ax --exclude fstab --delete /$d/ /backup/$d/<span class="Apple-converted-space">&nbsp;</span><br />
umount /backup/$d<span class="Apple-converted-space">&nbsp;</span><br />
done</p>
<p>DAY=`date "+%A"`</p>
<p>rsync -a --delete /usr/local/apache /data2/backups/$DAY<span class="Apple-converted-space">&nbsp;</span><br />
rsync -a --delete /data/solid /data2/backups/$DAY</p>
<p>3、对vger.rutgers.edu的cvs树进行镜像</p>
<p>#!/bin/bash</p>
<p>cd /var/www/cvs/vger/<span class="Apple-converted-space">&nbsp;</span><br />
PATH=/usr/local/bin:/usr/freeware/bin:/usr/bin:/bin</p>
<p>RUN=`lps x | grep rsync | grep -v grep | wc -l`<span class="Apple-converted-space">&nbsp;</span><br />
if [ "$RUN" -gt 0 ]; then<span class="Apple-converted-space">&nbsp;</span><br />
echo already running<span class="Apple-converted-space">&nbsp;</span><br />
exit 1<span class="Apple-converted-space">&nbsp;</span><br />
fi</p>
<p>rsync -az vger.rutgers.edu::cvs/CVSROOT/ChangeLog $HOME/ChangeLog</p>
<p>sum1=`sum $HOME/ChangeLog`<span class="Apple-converted-space">&nbsp;</span><br />
sum2=`sum /var/www/cvs/vger/CVSROOT/ChangeLog`</p>
<p>if [ "$sum1" = "$sum2" ]; then<span class="Apple-converted-space">&nbsp;</span><br />
echo nothing to do<span class="Apple-converted-space">&nbsp;</span><br />
exit 0<span class="Apple-converted-space">&nbsp;</span><br />
fi</p>
<p>rsync -az --delete --force vger.rutgers.edu::cvs/ /var/www/cvs/vger/<span class="Apple-converted-space">&nbsp;</span><br />
exit 0</p>
<p>FAQ</p>
<p>Q：如何通过ssh进行rsync，而且无须输入密码？<span class="Apple-converted-space">&nbsp;</span><br />
A：可以通过以下几个步骤</p>
<p>1. 通过ssh-keygen在server A上建立SSH keys，不要指定密码，你会在~/.ssh下看到identity和identity.pub文件<span class="Apple-converted-space">&nbsp;</span><br />
2. 在server B上的home目录建立子目录.ssh<span class="Apple-converted-space">&nbsp;</span><br />
3. 将A的identity.pub拷贝到server B上<span class="Apple-converted-space">&nbsp;</span><br />
4. 将identity.pub加到~[user b]/.ssh/authorized_keys<span class="Apple-converted-space">&nbsp;</span><br />
5. 于是server A上的A用户，可通过下面命令以用户B ssh到server B上了<span class="Apple-converted-space">&nbsp;</span><br />
e.g. ssh -l userB serverB<span class="Apple-converted-space">&nbsp;</span><br />
这样就使server A上的用户A就可以ssh以用户B的身份无需密码登陆到server B上了。</p>
<p>Q：如何通过在不危害安全的情况下通过防火墙使用rsync?<span class="Apple-converted-space">&nbsp;</span><br />
A：解答如下：</p>
<p>这通常有两种情况，一种是服务器在防火墙内，一种是服务器在防火墙外。无论哪种情况，通常还是使用ssh，这时最好新建一个备份用户，并且配置sshd仅允许这个用户通过RSA认证方式进入。 如果服务器在防火墙内，则最好限定客户端的IP地址，拒绝其它所有连接。如果客户机在防火墙内，则可以简单允许防火墙打开TCP端口22的ssh外发连接就ok了。</p>
<p>Q：我能将更改过或者删除的文件也备份上来吗？<span class="Apple-converted-space">&nbsp;</span><br />
A：当然可以：</p>
<p>你可以使用如：rsync -other -options -backupdir = ./backup-2000-2-13 ...这样的命令来实现。<span class="Apple-converted-space">&nbsp;</span><br />
这样如果源文件:/path/to/some/file.c改变了，那么旧的文件就会被移到./backup-2000-2-13/path/to/some/file.c，<span class="Apple-converted-space">&nbsp;</span><br />
这里这个目录需要自己手工建立起来</p>
<p>Q：我需要在防火墙上开放哪些端口以适应rsync？<span class="Apple-converted-space">&nbsp;</span><br />
A：视情况而定</p>
<p>rsync可以直接通过873端口的tcp连接传文件，也可以通过22端口的ssh来进行文件传递，但你也可以通过下列命令改变它的端口：</p>
<p>rsync --port 8730 otherhost::<span class="Apple-converted-space">&nbsp;</span><br />
或者<span class="Apple-converted-space">&nbsp;</span><br />
rsync -e 'ssh -p 2002' otherhost:</p>
<p>Q：我如何通过rsync只复制目录结构，忽略掉文件呢？<span class="Apple-converted-space">&nbsp;</span><br />
A：rsync -av --include '*/' --exclude '*' source-dir dest-dir</p>
<p>Q：为什么我总会出现"Read-only file system"的错误呢？<span class="Apple-converted-space">&nbsp;</span><br />
A：看看是否忘了设"read only = no"了</p>
<p>Q：为什么我会出现<a style="font-size: 9pt; color: black; text-decoration: none" href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#39;&#64;&#69;&#82;&#82;&#79;&#82;">'@ERROR</a>: invalid gid'的错误呢？<span class="Apple-converted-space">&nbsp;</span><br />
A：rsync使用时默认是用uid=nobody;gid=nobody来运行的，如果你的系统不存在nobody组的话，就会出现这样的错误，可以试试gid = nogroup或者其它</p>
<p>Q：绑定端口873失败是怎么回事？<span class="Apple-converted-space">&nbsp;</span><br />
A：如果你不是以root权限运行这一守护进程的话，因为1024端口以下是特权端口，会出现这样的错误。你可以用--port参数来改变。</p>
<p>Q：为什么我认证失败？<span class="Apple-converted-space">&nbsp;</span><br />
A：从你的命令行看来：</p>
<p>你用的是：<span class="Apple-converted-space">&nbsp;</span><br />
&gt; bash$ rsync -a 144.16.251.213::test test<span class="Apple-converted-space">&nbsp;</span><br />
&gt; Password:<span class="Apple-converted-space">&nbsp;</span><br />
&gt; @ERROR: auth failed on module test<span class="Apple-converted-space">&nbsp;</span><br />
&gt;<span class="Apple-converted-space">&nbsp;</span><br />
&gt; I dont understand this. Can somebody explain as to how to acomplish this.<span class="Apple-converted-space">&nbsp;</span><br />
&gt; All suggestions are welcome.</p>
<p>应该是没有以你的用户名登陆导致的问题，试试rsync -a<span class="Apple-converted-space">&nbsp;</span><a style="font-size: 9pt; color: black; text-decoration: none" href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#109;&#97;&#120;&#64;&#49;&#52;&#52;&#46;&#49;&#54;&#46;&#50;&#53;&#49;&#46;&#50;&#49;&#51;&#58;&#58;&#116;&#101;&#115;&#116;">max@144.16.251.213::test</a><span class="Apple-converted-space">&nbsp;</span>test<span class="Apple-converted-space">&nbsp;</span></p>
</span></span>
 <img src ="http://www.blogjava.net/jinfeng_wang/aggbug/318279.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jinfeng_wang/" target="_blank">jinfeng_wang</a> 2010-04-14 17:14 <a href="http://www.blogjava.net/jinfeng_wang/archive/2010/04/14/318279.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>