﻿<?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-疯狂-随笔分类-架构</title><link>http://www.blogjava.net/freeman1984/category/46575.html</link><description>STANDING ON THE SHOULDERS OF GIANTS
</description><language>zh-cn</language><lastBuildDate>Mon, 14 Dec 2015 10:38:24 GMT</lastBuildDate><pubDate>Mon, 14 Dec 2015 10:38:24 GMT</pubDate><ttl>60</ttl><item><title>JAVA Thread Dump 分析综述</title><link>http://www.blogjava.net/freeman1984/archive/2015/12/14/428645.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Mon, 14 Dec 2015 10:04:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2015/12/14/428645.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/428645.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2015/12/14/428645.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/428645.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/428645.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 转载自:http://blog.csdn.net/rachel_luo/article/details/8920596最近在做性能测试，需要对线程堆栈进行分析，在网上收集了一些资料，学习完后，将相关知识整理在一起，输出文章如下。一、Thread Dump介绍1.1什么是Thread Dump？Thread Dump是非常有用的诊断Java应用问题的工具。每一个Java虚拟机都有及时生成所有线程在某...&nbsp;&nbsp;<a href='http://www.blogjava.net/freeman1984/archive/2015/12/14/428645.html'>阅读全文</a><img src ="http://www.blogjava.net/freeman1984/aggbug/428645.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2015-12-14 18:04 <a href="http://www.blogjava.net/freeman1984/archive/2015/12/14/428645.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>(转)Oracle数据库如何授权收费（Database Licensing） </title><link>http://www.blogjava.net/freeman1984/archive/2014/10/27/419097.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Mon, 27 Oct 2014 08:43:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2014/10/27/419097.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/419097.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2014/10/27/419097.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/419097.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/419097.html</trackback:ping><description><![CDATA[<p><span style="font-family: Courier New; font-size: 12px;"><br />说白了，Oracle License就是一张纸，一张许可证。这跟许多软件产品是一样的，有没有许可证的产品在功能上是没有区别的，仅仅是一个法律问题。也就是说，随便到网上下的Oracle都可以免费正常使用，只不过这个使用是有区别的，如果是测试或研发，那没关系，随便用；如果是用于商业用途，那就是违法的了，Oracle公司有权起诉！</span></p><p><span style="font-family: Courier New; font-size: 12px;">&nbsp;</span></p><p><span style="font-family: Courier New; font-size: 12px;">与免费的下载版本不同，正式版的Oracle在购买后，用户会得到一个产品服务码，凭此Oracle服务码，可以得到Oracle的在线升级等服务，Oracle的服务分为好多级，不同级别提供相对应的在线或是现场服务。</span></p><p><span style="font-family: Courier New; font-size: 12px;">&nbsp;</span></p><p><span style="font-family: Courier New; font-size: 12px;"><strong>现在Oracle有两种授权方式，按CPU(Process)数和按用户数(NamedUser Plus)。</strong>前一种方式一般用于用户数不确定或者用户数量很大的情况，典型的如互联网环境，而后一种则通常被用于用户数确定或者较少的情况。</span></p><p><span style="font-family: Courier New; font-size: 12px;">&nbsp;</span></p><p><span style="font-family: Courier New; font-size: 12px;"><strong>按CPU：</strong>License数=CPU数*系数。系数来自Oracle的一个参数表，如IBM Power6的处理器为1，AMD和Intel的处理器为0.5，详细情况见下：</span></p><table border="1" cellspacing="0" cellpadding="0"><tbody><tr><td valign="top"><p><span style="font-family: Courier New; font-size: 12px;">参数</span></p></td><td valign="top"><p><span style="font-family: Courier New; font-size: 12px;">处理器型号</span></p></td></tr><tr><td valign="top"><p><span style="font-family: Courier New; font-size: 12px;">0.25</span></p></td><td valign="top"><p><span style="font-family: Courier New; font-size: 12px;">Sun UltraSPARC T1 处理器</span></p></td></tr><tr><td valign="top"><p><span style="font-family: Courier New; font-size: 12px;">0.50</span></p></td><td valign="top"><p><span style="font-family: Courier New; font-size: 12px;">Sun UltraSPARC T1处理器</span></p></td></tr><tr><td valign="top"><p><span style="font-family: Courier New; font-size: 12px;">0.50</span></p></td><td valign="top"><p><span style="font-family: Courier New; font-size: 12px;">Intel、AMD处理器</span></p></td></tr><tr><td valign="top"><p><span style="font-family: Courier New; font-size: 12px;">0.50</span></p></td><td valign="top"><p><span style="font-family: Courier New; font-size: 12px;">Sun UltraSPARC T2+ 处理器</span></p></td></tr><tr><td valign="top"><p><span style="font-family: Courier New; font-size: 12px;">1.00</span></p></td><td valign="top"><p><span style="font-family: Courier New; font-size: 12px;">IBM POWER6、POWER7 处理器</span></p></td></tr><tr><td valign="top"><p><span style="font-family: Courier New; font-size: 12px;">0.75</span></p></td><td valign="top"><p><span style="font-family: Courier New; font-size: 12px;">其他多核处理器</span></p></td></tr><tr><td valign="top"><p><span style="font-family: Courier New; font-size: 12px;">1.00</span></p></td><td valign="top"><p><span style="font-family: Courier New; font-size: 12px;">单核处理器</span></p></td></tr></tbody></table><p><span style="font-family: Courier New; font-size: 12px;">则根据公式可以算出，一个SUN UltraSparc T1的4*8核处理器需要4*8*0.25=8个CPU licenses</span></p><p><span style="font-family: Courier New; font-size: 12px;">&nbsp;</span></p><p><span style="font-family: Courier New; font-size: 12px;"><strong>按用户数：</strong>Oracle数据库按照用户数授权，是指最终端的连接到Oracle数据库的用户数。按照用户数来买的时候只能用于一个系统，不允许在多台机器上安装。每一个访问Oracle数据库的用户，无论是自然人还是设备，都算作一个用户 (Named User)。如果是B/S架构，那么是指连接到中间件上的用户数。</span></p><p><span style="font-family: Courier New; font-size: 12px;">&nbsp;</span></p><p><span style="font-family: Courier New; font-size: 12px;">Named User Plus: is defined as anindividual authorized by you to use the programs which are installed on a singleserver or multiple servers, regardless of whether the individual is activelyusing the programs at any given time. A non human operated device will becounted.</span></p><p><span style="font-family: Courier New; font-size: 12px;">&nbsp;</span></p><p><span style="font-family: Courier New; font-size: 12px;">按用户数购买则对应相应的产品有对应的License的最低购买量限制，如下：</span></p><table border="1" cellspacing="0" cellpadding="0"><tbody><tr><td valign="top"><p><span style="font-family: Courier New; font-size: 12px;">产品</span></p></td><td valign="top"><p><span style="font-family: Courier New; font-size: 12px;">最低License数</span></p></td></tr><tr><td valign="top"><p><span style="font-family: Courier New; font-size: 12px;">Oracle Database Standard Edition ONE</span></p></td><td valign="top"><p><span style="font-family: Courier New; font-size: 12px;">5 Named User Plus licenses</span></p></td></tr><tr><td valign="top"><p><span style="font-family: Courier New; font-size: 12px;">Oracle Database Standard Edition</span></p></td><td valign="top"><p><span style="font-family: Courier New; font-size: 12px;">5 Named User Plus licenses</span></p></td></tr><tr><td valign="top"><p><span style="font-family: Courier New; font-size: 12px;">Oracle Database Enterprise Edition</span></p></td><td valign="top"><p><span style="font-family: Courier New; font-size: 12px;">25 Named User Plus licenses per CPU</span></p></td></tr><tr><td valign="top"><p><span style="font-family: Courier New; font-size: 12px;">Oracle Application Server Standard Edition ONE</span></p></td><td valign="top"><p><span style="font-family: Courier New; font-size: 12px;">5 Named User Plus licenses</span></p></td></tr><tr><td valign="top"><p><span style="font-family: Courier New; font-size: 12px;">All other Oracle Application Server products</span></p></td><td valign="top"><p><span style="font-family: Courier New; font-size: 12px;">10 Named User Plus licenses per CPU</span></p></td></tr></tbody></table><p><span style="font-family: Courier New; font-size: 12px;">当然用户应该根据自己的实际用户数订购，且不少于相应版本所要求的最低用户数。</span></p><p><span style="font-family: Courier New; font-size: 12px;"><strong>一般情况下，1CPU的费用约等于50user的费用，所以如果用户数&gt;CPU数*系数*50，则按CPU订购反而更为经济。</strong></span></p><p><span style="font-family: Courier New; font-size: 12px;"><strong>&nbsp;</strong></span></p><p><span style="font-family: Courier New; font-size: 12px;"><strong>更换服务器，OracleLicense要重新购买吗？</strong></span></p><p><span style="font-family: Courier New; font-size: 12px;">如果用户是按照用户数购买的Oracle，更改硬件不需要重新购买License；</span></p><p><span style="font-family: Courier New; font-size: 12px;">如果是按照CPU个数买，有相应的换算方法，具体请咨询Oracle公司。</span></p><p><span style="font-family: Courier New; font-size: 12px;">&nbsp;</span></p><p><span style="font-family: Courier New; font-size: 12px;"><strong>这里是Oracle 11g企业版的销售价格：</strong></span></p><p><span style="font-family: Courier New; font-size: 12px;">每个License还有有效期的分类（不论是User License还是CPU License），分别为：1年、2年、3年、4年、5年、永久。当然价格也是依次增加。</span></p><p><span style="font-family: Courier New; font-size: 12px;">&nbsp;</span></p><p><span style="font-family: Courier New; font-size: 12px;">当前Oracle 11G的User License无限使用期的价格为人民币3千5左右，按50个User License无限使用期的购买量则价格为17.5万;每个CPU License无限使用期的价格为17万9千，按IBM小机的系数计算，则购买价格为17万9千，和50个User License的价格相近。</span></p><p><span style="font-family: Courier New; font-size: 12px;">&nbsp;</span></p><p><span style="font-family: Courier New; font-size: 12px;">关于服务价格：一般地，购买Oracle的License都包含首年的服务费，以后的费用按每年原价的22%计算。</span></p><p><span style="font-family: Courier New; font-size: 12px;">&nbsp;</span></p><p><span style="font-family: Courier New; font-size: 12px;">更多的产品价格可以访问http://shop.oracle.com查看。</span></p><p><span style="font-family: Courier New; font-size: 12px;"><br /></span></p><p><span style="font-family: Courier New; font-size: 12px;"><strong>这里我们再介绍一下如何查看服务器上物理CPU总数以及核数：</strong></span></p><p><span style="font-family: Courier New; font-size: 12px;">a.如果已安装了数据库实例，那么直接查看V$license视图即可:</span></p><pre><span style="font-family: Courier New; font-size: 12px;">SQL&gt; select cpu_count_current,CPU_CORE_COUNT_CURRENT,CPU_SOCKET_COUNT_CURRENT from v$license;

CPU_COUNT_CURRENT CPU_CORE_COUNT_CURRENT CPU_SOCKET_COUNT_CURRENT
----------------- ---------------------- ------------------------
                2                      2                        1</span></pre><span style="font-family: Courier New; font-size: 12px;">以上通过v$license 视图反应了数据库服务器当前的逻辑CPU总数为2，而总的核数也是2，实际的物理CPU Socket是1，那么说明是1个双核的物理CPU。</span> <p><span style="font-family: Courier New; font-size: 12px;"><br /></span></p><p><span style="font-family: Courier New; font-size: 12px;">b. 如果服务器上尚没有部署实例则不能使用v$license视图，那么可以通过OS 命令来获取必要的信息。</span></p><p><span style="font-family: Courier New; font-size: 12px;">在x86 Linux服务器上：</span></p><p><span style="font-family: Courier New; font-size: 12px;"><br /></span></p><pre><span style="font-family: Courier New; font-size: 12px;">列出当前使用的物理CPU的个数：

grep core\ id /proc/cpuinfo | grep -c \ 0$ | grep ^0$ &gt;&gt; /dev/null &amp;&amp; grep -c processor /proc/cpuinfo || \
grep core\ id /proc/cpuinfo | grep -c \ 0$

列出单个物理CPU的核数

grep "cpu cores" /proc/cpuinfo |uniq</span></pre><p>&nbsp;</p><p>&nbsp;</p><span style="font-family: Courier New; font-size: 12px;"><p>在Power系列的IBM小机上按照cpu模块方式来购买，在IBM Dual-Core Module（双核模块）的power芯片上，一个双核模块（内含2颗物理cpu）只需要购买1.5个license ， 具体的模块类型可以咨询IBM厂家或者集成商。<br /><br />转自：<a href="http://blog.csdn.net/eurasiaxz/article/details/10699869">http://blog.csdn.net/eurasiaxz/article/details/10699869</a></p></span><p>当然随着cpu计算能力的提高，cpu个数有可能并不需要太多。oracle的收费模式肯定会变化。</p><img src ="http://www.blogjava.net/freeman1984/aggbug/419097.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2014-10-27 16:43 <a href="http://www.blogjava.net/freeman1984/archive/2014/10/27/419097.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>URL最大长度限制(转)</title><link>http://www.blogjava.net/freeman1984/archive/2013/05/30/399942.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Thu, 30 May 2013 01:29:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2013/05/30/399942.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/399942.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2013/05/30/399942.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/399942.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/399942.html</trackback:ping><description><![CDATA[<div id="article_content" class="article_content">
<p class="entry">转自：<a href="http://blog.csdn.net/jinhill/article/details/3961881">http://blog.csdn.net/jinhill/article/details/3961881</a></p>
<div class="entry">
<ol><li>URL不能大于255bytes的说法确实存在，在<a title="RFC2616" href="http://www.w3.org/Protocols/rfc2616/rfc2616.html" target="_blank">RFC2616</a>中提到：<br />
<blockquote>
<p>The HTTP protocol does not place any a priori limit on the length of a URI. Servers MUST be able to handle the URI of any resource they serve, and SHOULD be able to handle URIs of unbounded length if they provide GET-based forms that could generate such URIs. A server SHOULD return 414 (Request-URI Too Long) status if a URI is longer than the server can handle (see section 10.4.15).</p>
<p>Note: <span style="color: #ff0000">Servers ought to be cautious about depending on URI lengths above 255 bytes, because some older client or proxy implementations might not properly support these lengths.</span></p></blockquote></li><li>从上一点也可以看出，255bytes的说法也是为了兼容性考虑。实际上现代浏览器的限制如下：<br />
<blockquote>
<p><strong>Microsoft Internet Explorer (Browser)</strong><br />Microsoft states that the maximum length of a URL in Internet Explorer is <a title="Maximum URL length is 2,083 characters in Internet Explorer" href="http://support.microsoft.com/kb/q208427/" target="_blank">2,083 characters</a>, with no more than 2,048 characters in the path portion of the URL. In my tests, attempts to use URLs longer than this produced a clear error message in Internet Explorer.<br /><strong>Firefox (Browser)</strong><br />After 65,536 characters, the location bar no longer displays the URL in Windows Firefox 1.5.x. However, longer URLs will work. I stopped testing after 100,000 characters.<br /><strong>Safari (Browser)</strong><br />At least 80,000 characters will work. I stopped testing after 80,000 characters.<br /><strong>Opera (Browser)</strong><br />At least 190,000 characters will work. I stopped testing after 190,000 characters. Opera 9 for Windows continued to display a fully editable, copyable and pasteable URL in the location bar even at 190,000 characters.<br /><strong>Apache (Server)</strong><br />My early attempts to measure the maximum URL length in web browsers bumped into a server URL length limit of approximately 4,000 characters, after which Apache produces a &#8220;413 Entity Too Large&#8221; error. I used the current up to date Apache build found in Red Hat Enterprise Linux 4. The official Apache documentation only mentions an 8,192-byte limit on an individual field in a request.<br /><strong>Microsoft Internet Information Server</strong><br />The default limit is 16,384 characters (yes, Microsoft&#8217;s web server accepts longer URLs than Microsoft&#8217;s web browser). This is configurable.<br /><strong>Perl HTTP::Daemon (Server)</strong><br />Up to 8,000 bytes will work. Those constructing web application servers with Perl&#8217;s HTTP::Daemon module will encounter a 16,384 byte limit on the combined size of all HTTP request headers. This does not include POST-method form data, file uploads, etc., but it does include the URL. In practice this resulted in a 413 error when a URL was significantly longer than 8,000 characters. This limitation can be easily removed. Look for all occurrences of 16&#215;1024 in Daemon.pm and replace them with a larger value. Of course, this does increase your exposure to denial of service attacks.</p></blockquote></li><li>另外值得注意的是，有文章提到作为&lt;a&gt;的href属性时，URL不能超过1024bytes，这点没有详细查证 </li></ol></div>
<p>综上，URL还是不适合太长，不是不得已，尽量不要通过GET方式提交大量参数，可以考虑用POST方式（大约在2M左右，应该是和服务器及设定有关）。另外这么长的URL在访问和收藏（有文章提到有些浏览器在收藏超长地址时也是会出现问题）时也是相当不友好的。当然，之前数据库字段设置时还是作为255bytes处理，现在可能要考虑扩充一下了。</p>
<p>参考：</p>
<ol><li><a title="What is the maximum length of a URL?" href="http://www.boutell.com/newfaq/misc/urllength.html" target="_blank">What is the maximum length of a URL?</a> </li><li><a title="What is the limit on QueryString / GET / URL parameters?" href="http://classicasp.aspfaq.com/forms/what-is-the-limit-on-querystring/get/url-parameters.html" target="_blank">What is the limit on QueryString / GET / URL parameters?</a> </li></ol></div><img src ="http://www.blogjava.net/freeman1984/aggbug/399942.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2013-05-30 09:29 <a href="http://www.blogjava.net/freeman1984/archive/2013/05/30/399942.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于tomcat和sessionCookieName和SESSION_PARAMETER_NAME以及disableURLRewriting参数原理和使用</title><link>http://www.blogjava.net/freeman1984/archive/2012/12/24/393402.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Mon, 24 Dec 2012 07:16:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2012/12/24/393402.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/393402.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2012/12/24/393402.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/393402.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/393402.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 关于tomcat和sessionCookieName和SESSION_PARAMETER_NAME以及disableURLRewriting参数原理和使用&nbsp;&nbsp;<a href='http://www.blogjava.net/freeman1984/archive/2012/12/24/393402.html'>阅读全文</a><img src ="http://www.blogjava.net/freeman1984/aggbug/393402.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2012-12-24 15:16 <a href="http://www.blogjava.net/freeman1984/archive/2012/12/24/393402.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>A/B测试(转载)</title><link>http://www.blogjava.net/freeman1984/archive/2012/08/28/386419.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Tue, 28 Aug 2012 03:41:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2012/08/28/386419.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/386419.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2012/08/28/386419.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/386419.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/386419.html</trackback:ping><description><![CDATA[<p>A / B测试不是一个时髦名词。现在很多有经验的营销和设计工作者用它来获得访客行为信息，来提高转换率。然而， A / B测试与SEO不同的是，人们都不太知道徒河进行网站分析和可用性分析。他们并不完全明白它是什么或如何更有效的使用它。本文将为你提供有史以来最好的A / B测试教程。</p>
<p><strong>什么是A/B测试?</strong></p>
<p>A / B测试的核心就是：确定两个元素或版本（A和B）哪个版本更好，你需要同时实验两个版本。最后，选择最好的版本使用。</p>
<p><img class="alignnone size-full wp-image-2227" title="ab-testing" alt="" src="http://img.ucdchina.com/upload/snap/2010-07/3063eb0c3e2e6ef65e81e1fee7c885a3.png" width="498" height="381" /></p>
<p>网络上的A / B测试，即你设计的页面有两个版本（A和B），A为现行的设计（称为控制） ， B是新的设计。比较这两个版本之间你所关心的数据（转化率，业绩，跳出率等） 。最后，您选择效果最好的版本。</p>
<p><strong>测试哪些东西?</strong></p>
<p>你要选择什么去测试取决于你的目标。例如，如果你的目标是增加顾客数量，那么您可能测试下列内容：注册表单数量，字段类型要求，隐私政策等。在这种情况下A / B测试的目标是要弄清楚什么阻止了游客注册。需要填写的表单的数量？用户的隐私？还是该网站做了让游客不信任的事情？所有这些问题都可以通过一个个A/B 测试获得答案。</p>
<p>每一个A / B测试内容都是独一无二的，单通常测试一下这些内容：</p>
<ul><li>行动按钮的措辞，大小，颜色和位置，</li><li>标题或产品说明，</li><li>表单的数量和字段类型，</li><li>网站的布局和风格，</li><li>产品定价和促销活动，</li><li>着陆和产品页面上的图片，</li><li>页面上文字的长度（少Vs多）。</li></ul>
<p>一旦你决定要测试什么，下一步当然是要选择一个合适的测试工具。如果你想要一个基础的免费工具，可以使用<a href="http://www.google.com/websiteoptimizer">Google Website Optimizer</a>。如果你想要功能更加强大的工具，可以使用<a href="http://visualwebsiteoptimizer.com/">Visual Website Optimizer</a>&nbsp; 。其他的一些选择都是可以的，建立试验在所有工具中都很相似，所以我们只需讨论一种即可。</p>
<p>你可以通过两种方法建立A / B测试：</p>
<ul><li><strong>在页面测试加载前替换元素</strong><br />如果你测试的是页面上的单个元素，如注册按钮，然后需要在测试工具中设置按钮。当测试时，在A / B工具将在页面给用户前随机替换按钮。</li><li><strong>重定向到另一页面</strong><br />如果你想通过A / B测试整个页面，比如说，一个绿色的主题和一个红色主题，那么你就需要创建和上传新的页面。例如，如果您的主页是 http://www.example.com/index.html，那么你需要创建另外一个页面 http://www.example.com/index1.html。当测试运行时，您的测试工具将一部分访问者重定向到第二个网址。</li></ul>
<p>一旦您使用了上面的两种变换方法，下一步是建立您的转换目标。通常，你会得到一个JavaScript代码，您可以复制并粘贴到一个需要游客到达的目标网页。例如，如果您有一个电子商务网站，你正在测试的&#8220;立即购买&#8220;按钮的颜色，然后您的转换目标将是购买成功后的&#8220;谢谢您&#8220;页面。</p>
<p>在转换事件发生的同时，在A / B测试工具，记录了哪种页面显示给了访问者。经过足够数量的游客，您可以确定哪个页面带来了最多的转化！建立和运行的A / B测试，其实很简单。</p>
<p><strong>该做什么和不该做什么</strong></p>
<p>虽然A / B测试是超级简单的概念，但是请记住，以下这些都只是我自己的经验。</p>
<p><strong>注意事项</strong></p>
<ul><li>不要分开你的测试情况。始终两个版本同时进行测试。如果您第一星期测试第一版本，第二星期测试第二个版本，你就错了。有可能B版本带来的流量更糟糕，但是带来了更好的业绩，因为两个版本之间的流量始终存在不一样。</li><li>不要结束得太早。有一个概念叫做&#8220;统计信心&#8220; ，无论你的测试结果明显的。如果你只有少数转换或游客，它都无法确定最终的结果。大多数A / B测试工具都有报告统计，但如果你是手动测试，你可以使用 <a href="http://visualwebsiteoptimizer.com/ab-split-significance-calculator/">在线计算器</a>。</li><li>不要让常客惊讶。如果你正在测试网站的一部分。包括新访客和常客，不要使他们觉得震惊。尤其不要因为哪些可能不会最终实施变化。</li><li>不要让你的直觉推翻了测试结果。在A / B测试的结果往往是令人惊讶的或直观的。在一个绿色为主题的网站，一个明显的红色按钮有可能成为赢家。即使红色按钮不容易吸引注意。您要测试的目标是一个更好的转换率，而不是美学，所以在得到测试借过钱不要拒绝任何尝试。</li></ul>
<p><strong>需要做的</strong></p>
<ul><li>知道运行测试多久。结束太早，可能会使你花了时间但是没有得到有意义的结果。结束太晚也不好，因为效果不佳的页面可能影响你的转化和业绩。使用一个<a href="http://visualwebsiteoptimizer.com/ab-split-test-duration/">计算器</a>，来确定测试多久以后来结束它。</li><li>将相同的页面呈献给同一个访客。您的工具应该有一个记忆访问者已经看到的页面的功能。这样可以防止向同一用户显示一不同的价格或不同的促销优惠。</li><li>让您的A / B测试在整个网站保持一致。如果你正在测试的登录按钮在多个地点出现，然后一个访问者应在所有的地方看到同样的变化。在页面1显示一个样子，在页面2显示两外一个样子，会使试验结果被干扰。</li><li>做很多的A / B测试。让我们面对现实吧：你的第一个A / B测试可能会无效。但是不要绝望。一个A / B测试只能有三个结果：没有结果，不好的结果和好的结果。优化转换率的关键是要做大量的A / B测试，把所有的好的结果拼接起来，最终推动业绩。</li></ul>
<p><strong>经典A/B测试案例研究</strong></p>
<p>这里有一些如何进行A/B测试的案例研究。</p>
<p><a href="http://37signals.com/svn/posts/1525-writing-decisions-headline-tests-on-the-highrise-signup-page">Writing Decisions: Headline Tests on the Highrise Sign-Up Page</a>&nbsp;37Signals测试他们的价格页面的标题。最终发现， &#8220;30-Day Free Trial on All Accounts &#8220;比原来的&#8220;Start a Highrise Account. &#8220;多产生30 ％以上的订单。</p>
<p><img class="alignnone size-full wp-image-2228" title="hrhq-signuphead-30day60sec" alt="" src="http://img.ucdchina.com/upload/snap/2010-07/66e534c4fe2b5c4e1483f27ffcf4d9d3.png" width="530" height="140" /></p>
<p><a href="http://dustincurtis.com/you_should_follow_me_on_twitter.html">&#8220;You Should Follow Me on Twitter Here&#8221;</a> (Dustin Curtis) 这是一个用来测试召唤用户在Twitter上关注自己的试验。. Dustin 发现提示文字是&#8220;You should follow me on Twitter here&#8221; 的效果是&#8220;I&#8217;m on Twitter.&#8221; 173%</p>
<p><span><img class="alignnone size-full wp-image-2229" title="dustin" alt="" src="http://img.ucdchina.com/upload/snap/2010-07/4a6eb53aa4fd0052d5fc82a45b0f8c7b.png" width="488" height="59" /></span></p>
<p><a href="http://carsonified.com/blog/design/human-photos-double-your-conversion-rate/">Human Photos Double Conversion Rates</a>&nbsp;从两个不同的A / B测试将在网站上增加转换率的人的照片：一个令人令人惊讶的结论，A/B测试两张图片，将真人照片放在网站上会获得一倍的转化。研究说明，我们潜意识被照片吸引了。</p>
<p><img class="alignnone size-full wp-image-2230" title="human" alt="" src="http://img.ucdchina.com/upload/snap/2010-07/7fcea0efd7ae306f97f3aec87097bce8.png" width="415" height="184" /></p>
<p><a href="http://www.fourhourworkweek.com/blog/2009/08/12/google-website-optimizer-case-study/">Google Website Optimizer Case Study: Daily Burn, 20%+ Improvement</a> (Tim Ferriss) 一个将用户选择减少的变化使转化提高了20%，最终的版本在细节和文字上更易吸引目光。</p>
<p><img class="alignnone size-full wp-image-2231" title="gymnii" alt="" src="http://img.ucdchina.com/upload/snap/2010-07/ec7bb024417da83432775f01d6791cc7.jpeg" width="300" height="241" /></p>
<p><a href="http://visualwebsiteoptimizer.com/split-testing-blog/ab-test-case-study-how-two-magical-words-increased-conversion-rate-by-28/">Two Magical Words Increased Conversion Rate by 28%</a>&nbsp;&#8220;It&#8217;s free&#8221; 这个单词增加了注册按钮点击次数的28%, 测试结果表明，在行动召唤上一些很小的变化会带来令人惊讶的结果。</p>
<p><img class="alignnone size-full wp-image-2232" title="its-free-shot" alt="" src="http://img.ucdchina.com/upload/snap/2010-07/3b795b7011cb5afb70c96d2e3f0f9332.png" width="440" height="70" /></p>
<p><a href="http://dmix.ca/2010/05/how-we-increased-our-conversion-rate-by-72/">Changing the Sign-Up Button from Green to Red</a>&nbsp;依靠A / B测试， CareLogger把注册按钮从绿色修改为红色增加了34％转换率！</p>
<p><img class="alignnone size-full wp-image-2233" title="get-started" alt="" src="http://img.ucdchina.com/upload/snap/2010-07/e5668dadf2bd002d01684a1e745ca8a3.png" width="580" height="122" /></p>
<p><a href="http://www.getelastic.com/single-vs-two-page-checkout/">Single page vs. multi-step checkout</a>&nbsp;如果你有一个在线商店，很常见的就是支付流程。这个A / B测试发现，多个支付流程比单个支付流程完成的销售更好。</p>
<p><img class="alignnone size-full wp-image-2234" title="getelastic" alt="" src="http://img.ucdchina.com/upload/snap/2010-07/d3a976fd670d3c1ebe8015d629ad0f3a.jpeg" width="300" height="283" /></p>
<p><a href="http://www.lukew.com/ff/entry.asp?1007">&#8220;Mad Libs&#8221; style form increases conversion 25-40%</a>&nbsp;打败传统的智慧，此A / B测试发现一<em>段风格</em>形式输入字段比传统形式的布局更好。</p>
<p><img class="alignnone size-full wp-image-2235" title="madlibs" alt="" src="http://img.ucdchina.com/upload/snap/2010-07/c7c204f8c987200255542d3678ab8d48.gif" width="558" height="164" /></p>
<p><a href="http://carsonified.com/blog/business/the-business-case-for-ab-testing/">Complete redesign of product page increased sales by 20%</a>&nbsp;一个软件产品的公司重新设计他们的产品页给它一个现代的外观和增加信任模块。最终结果：他们成功地增加20 ％的总销售额。本案例研究证明了设计对销售的影响。</p>
<p><img class="alignnone size-full wp-image-2236" title="aquasoft" alt="" src="http://img.ucdchina.com/upload/snap/2010-07/cbf9c7829abaaef547ac2fe2dbe2e879.png" width="450" height="291" /></p>
<p><a href="http://www.marketingexperiments.com/blog/research-topics/response-capture-case-study.html">Marketing Experiments response capture case study &#8211; triple digit increase in conversions</a>&nbsp;通过优化邮件地址获取提高了258 ％。重点是消除所有的干扰，并要求游客只需提供电子邮件地址。使用亚马逊礼品卡让他/她的完成个人资料。</p>
<p><img class="alignnone size-full wp-image-2237" title="marketing-experiments" alt="" src="http://img.ucdchina.com/upload/snap/2010-07/37b713d6f858ddd9bbd11d594b817b3b.jpeg" width="300" height="225" /></p>
<p><strong>A/B</strong><strong>测试工具</strong></p>
<p>有许多侧重点，价位和功能不同的A / B测试工具，这里是一些：</p>
<ul><li><a href="http://www.google.com/websiteoptimizer">Google Website Optimizer</a><br />搜索巨头提供的免费A/B测试工具。一个很好的入门级工具，但是没有一些先进的功能。</li><li><a href="http://www.bingocardcreator.com/abingo/">A/Bingo</a> and <a href="http://vanity.labnotes.org/">Vanity</a><br />基于Ruby on Rails开发的服务器组件。需要编程和代码集成。</li><li><a href="http://visualwebsiteoptimizer.com/">Visual Website Optimizer</a><br />一个易于使用的A / B测试工具，包含一些先进的功能，如所见即所得的编辑器，单击地图，访问者分割和标签等。</li><li><a href="http://unbounce.com/">Unbounce</a> and <a href="http://performable.com/">Performable</a><br />集成着陆页设计的A / B测试工具。</li><li><a href="http://vertster.com/">Vertster</a>, <a href="http://sitespect.com/">SiteSpect</a>, <a href="http://www.webtrends.com/products/optimize.aspx">Webtrends Optimize</a> and <a href="http://www.omniture.com/en/products/conversion/testandtarget">Omniture&#8217;s Test&amp;Target</a><br />企业级测试工具。</li></ul>
<p><strong>一些深入研究的A/B测试资料</strong></p>
<p>如果你已经读到这里，那么A / B测试大概已经激起你的兴趣。在这里，有一些非常好的A/B测试资源。</p>
<p><strong>寻找你下一个A/B测试的灵感</strong></p>
<ul><li><a href="http://whichtestwon.com/">Which Test Won?</a><br />一个猜测那种情况会最终胜利的游戏。</li><li><a href="http://www.conversion-rate-experts.com/articles/101-google-website-optimizer-tips/">101 A/B Testing Tips</a><br />大量的A/B测试技巧和方法。</li><li><a href="http://abtests.com/">ABtests.com</a><br />一个可以分享和阅读A/B测试结果的地方。</li><li><a href="http://visualwebsiteoptimizer.com/ideafox.php">A/B Ideafox</a><br />搜索引擎的A / B和多变量的案例研究。</li></ul>
<p><strong>一些介绍性文章</strong></p>
<ul><li><a href="http://elem.com/~btilly/effective-ab-testing/">Effective A/B Testing</a><br />By Ben Tilly.</li><li><a href="http://exp-platform.com/Documents/GuideControlledExperiments.pdf">Practical Guide to Controlled Experiments on the Web</a> (PDF)<br />From Microsoft Research.</li><li><a href="http://20bits.com/articles/an-introduction-to-ab-testing/">Introduction to A/B Testing</a><br />From the 20bits blog</li></ul>
<p><strong>A/B</strong><strong>测试中的数学</strong></p>
<ul><li><a href="http://20bits.com/articles/statistical-analysis-and-ab-testing/">Statistics for A/B Testing</a><br />From the 20bits blog.</li><li><a href="http://www.evanmiller.org/how-not-to-run-an-ab-test.html">How Not to Do A/B Testing</a></li><li><a href="http://visualwebsiteoptimizer.com/split-testing-blog/what-you-really-need-to-know-about-mathematics-of-ab-split-testing/">What You Should Know About the Mathematics of A/B Testing</a><br />From my own blog.</li><li><a href="http://blog.asmartbear.com/easy-statistics-for-adwords-ab-testing-and-hamsters.html">Easy Statistics for AdWords A/B Testing, and Hamsters</a></li><li><a href="http://www.cennydd.co.uk/2009/statistical-significance-other-ab-test-pitfalls/">Statistical Significance and Other A/B Test Pitfalls</a></li></ul>
<p>原文地址：<a href="http://www.smashingmagazine.com/2010/06/24/the-ultimate-guide-to-a-b-testing/">http://www.smashingmagazine.com/2010/06/24/the-ultimate-guide-to-a-b-testing/</a><br />转载自：<a href="http://ucdchina.com/snap/7203">http://ucdchina.com/snap/7203</a></p><img src ="http://www.blogjava.net/freeman1984/aggbug/386419.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2012-08-28 11:41 <a href="http://www.blogjava.net/freeman1984/archive/2012/08/28/386419.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>数字证书原理(转)</title><link>http://www.blogjava.net/freeman1984/archive/2012/07/24/383817.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Tue, 24 Jul 2012 02:35:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2012/07/24/383817.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/383817.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2012/07/24/383817.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/383817.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/383817.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 数字证书原理 文中首先解释了加密解密的一些基础知识和概念，然后通过一个加密通信过程的例子说明了加密算法的作用，以及数字证书的出现所起的作用。接着对数字证书做一个详细的解释，并讨论一下windows中数字证书的管理，最后演示使用makecert生成数字证书。如果发现文中有错误的地方，或者有什么地方说得不够清楚，欢迎指出！1、基础知识&nbsp;&nbsp;&nbsp;&nbsp;...&nbsp;&nbsp;<a href='http://www.blogjava.net/freeman1984/archive/2012/07/24/383817.html'>阅读全文</a><img src ="http://www.blogjava.net/freeman1984/aggbug/383817.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2012-07-24 10:35 <a href="http://www.blogjava.net/freeman1984/archive/2012/07/24/383817.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Quartz+Spring的集群配置(转)</title><link>http://www.blogjava.net/freeman1984/archive/2012/05/11/377882.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Fri, 11 May 2012 03:02:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2012/05/11/377882.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/377882.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2012/05/11/377882.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/377882.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/377882.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 原来配置的Quartz是通过spring配置文件生效的，发现在非集群式的服务器上运行良好，但是将工程部署到水平集群服务器上去后改定时功能不能正常运行，没有任何错误日志，于是从jar包、JDK版本、cronExpression到服务器类型，甚至查到了服务器操作系统的类型，都没能找到解决的办法，后来才知道是集群惹的祸！ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nb...&nbsp;&nbsp;<a href='http://www.blogjava.net/freeman1984/archive/2012/05/11/377882.html'>阅读全文</a><img src ="http://www.blogjava.net/freeman1984/aggbug/377882.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2012-05-11 11:02 <a href="http://www.blogjava.net/freeman1984/archive/2012/05/11/377882.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>select, iocp, epoll,kqueue及各种I/O复用机制</title><link>http://www.blogjava.net/freeman1984/archive/2011/12/07/365746.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Wed, 07 Dec 2011 05:45:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2011/12/07/365746.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/365746.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2011/12/07/365746.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/365746.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/365746.html</trackback:ping><description><![CDATA[<p><strong>首先，介绍几种常见的I/O模型及其区别</strong>，如下：</p>
<ul><li>
<p>blocking I/O</p></li><li>
<p>nonblocking I/O</p></li><li>
<p>I/O multiplexing (<tt>select</tt> and <tt>poll</tt>)</p></li><li>
<p>signal driven I/O (<tt>SIGIO</tt>)</p></li><li>
<p>asynchronous I/O (the POSIX <tt>aio_</tt>functions)</p></li></ul>
<p><strong>blocking I/O</strong> <br />这个不用多解释吧，阻塞套接字。下图是它调用过程的图示：</p>
<p><img src="http://hi.csdn.net/attachment/201001/28/156467_126466013140tA.jpg"  alt="" /> </p>
<p>重点解释下上图，下面例子都会讲到。首先application调用 recvfrom()转入kernel，注意kernel有2个过程，wait for data和copy data from kernel to user。直到最后copy complete后，recvfrom()才返回。此过程一直是阻塞的。</p>
<p><strong>nonblocking I/O：</strong> <br />与blocking I/O对立的，非阻塞套接字，调用过程图如下：</p>
<p><img src="http://hi.csdn.net/attachment/201001/28/156467_1264660132Vc0H.jpg"  alt="" /> </p>
<p>可以看见，如果直接操作它，那就是个轮询。。直到内核缓冲区有数据。</p>
<p><strong>I/O multiplexing (select and poll)</strong> <br />最常见的I/O复用模型，select。</p>
<p><img src="http://hi.csdn.net/attachment/201001/28/156467_126466013344Mb.jpg"  alt="" /> </p>
<p>select先阻塞，有活动套接字才返回。与<strong>blocking I/O</strong>相比，select会有两次系统调用，但是select能处理多个套接字。</p>
<p><strong>signal driven I/O (SIGIO)</strong> <br />只有UNIX系统支持，感兴趣的课查阅相关资料</p>
<p><img src="http://hi.csdn.net/attachment/201001/28/156467_1264660134r93R.jpg"  alt="" /> </p>
<p>与<strong>I/O multiplexing (select and poll)</strong>相比，它的优势是，免去了select的阻塞与轮询，当有活跃套接字时，由注册的handler处理。</p>
<p><font color="#ff0000"><strong>asynchronous I/O (the POSIX aio_functions)</strong> <br /></font>很少有*nix系统支持，windows的IOCP则是此模型</p>
<p><img src="http://hi.csdn.net/attachment/201001/28/156467_1264660135UGwy.jpg"  alt="" /> </p>
<p>完全异步的I/O复用机制，因为纵观上面其它四种模型，至少都会在由kernel copy data to appliction时阻塞。而该模型是当copy<font color="#ff0000">完成</font>后才通知application，可见是<font color="#ff0000">纯异步</font>的。好像只有windows的<font color="#ff0000">完成端口</font>是这个模型，效率也很出色。</p>
<p><strong>下面是以上五种模型的比较</strong></p>
<p><strong><img src="http://hi.csdn.net/attachment/201001/28/156467_1264660135Ow47.jpg"  alt="" /> </strong></p>
<p>可以看出，越往后，阻塞越少，理论上效率也是最优。</p>
<p>=====================分割线==================================</p>
<p>5种模型的比较比较清晰了，剩下的就是把select,epoll,iocp,kqueue按号入座那就OK了。</p>
<p>select和iocp分别对应第3种与第5种模型，那么epoll与kqueue呢？其实也于select属于同一种模型，只是更高级一些，可以看作有了第4种模型的某些特性，如callback机制。</p>
<p><strong>那么，为什么epoll,kqueue比select高级？ <br /></strong></p>
<p>答案是，他们无<font color="#ff0000"><strong>轮询</strong></font>。因为他们用callback取代了。想想看，当套接字比较多的时候，每次select()都要通过遍历FD_SETSIZE个Socket来完成调度,不管哪个Socket是活跃的,都遍历一遍。这会浪费很多CPU时间。如果能给套接字注册某个回调函数，当他们活跃时，自动完成相关操作，那就避免了轮询，这正是epoll与kqueue做的。</p>
<p><strong>windows or *nix （IOCP or kqueue/epoll）？</strong></p>
<p>诚然，Windows的IOCP非常出色，目前很少有支持<strong>asynchronous I/O</strong>的系统，但是由于其系统本身的局限性，大型服务器还是在UNIX下。而且正如上面所述，kqueue/epoll 与 IOCP相比，就是多了一层从内核copy数据到应用层的阻塞，从而不能算作<strong>asynchronous I/O类。</strong>但是，这层小小的阻塞无足轻重，kqueue与epoll已经做得很优秀了。</p>
<p><strong>提供一致的接口，IO Design Patterns</strong></p>
<p>实际上，不管是哪种模型，都可以抽象一层出来，提供一致的接口，广为人知的有ACE,Libevent这些，他们都是跨平台的，而且他们自动选择最优的I/O复用机制，用户只需调用接口即可。说到这里又得说说2个设计模式，<strong>Reactor</strong> and <strong>Proactor。</strong>有一篇经典文章<a href="http://www.artima.com/articles/io_design_patterns.html"><font color="#336699">http://www.artima.com/articles/io_design_patterns.html</font></a>值得阅读，Libevent是<strong>Reactor</strong>模型，ACE提供<strong>Proactor</strong>模型。实际都是对各种I/O复用机制的封装。</p>
<p><strong>Java nio包是什么I/O机制？</strong></p>
<p>我曾天真的认为java nio封装的是IOCP。。现在可以确定，目前的java本质是select()模型，可以检查/jre/bin/nio.dll得知。至于java服务器为什么效率还不错。。我也不得而知，可能是设计得比较好吧。。-_-。</p>
<p>=====================分割线==================================</p>
<p><strong><font color="#ff0000">总结一些重点：</font></strong></p>
<ol><li>只有IOCP是asynchronous I/O，其他机制或多或少都会有一点阻塞。 </li><li>select低效是因为每次它都需要轮询。但低效也是相对的，视情况而定，也可通过良好的设计改善 </li><li>epoll, kqueue是Reacor模式，IOCP是Proactor模式。 </li><li>java nio包是select模型。。 </li></ol>
<p>转载自：<a href="http://blog.csdn.net/shallwake/article/details/5265287">http://blog.csdn.net/shallwake/article/details/5265287</a><br /></p><img src ="http://www.blogjava.net/freeman1984/aggbug/365746.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2011-12-07 13:45 <a href="http://www.blogjava.net/freeman1984/archive/2011/12/07/365746.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>nginx和tomcat负载简单配置(windows环境)</title><link>http://www.blogjava.net/freeman1984/archive/2011/12/07/365726.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Wed, 07 Dec 2011 02:40:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2011/12/07/365726.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/365726.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2011/12/07/365726.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/365726.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/365726.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: nginx和tomcat负载简单配置(windows环境)&nbsp;&nbsp;<a href='http://www.blogjava.net/freeman1984/archive/2011/12/07/365726.html'>阅读全文</a><img src ="http://www.blogjava.net/freeman1984/aggbug/365726.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2011-12-07 10:40 <a href="http://www.blogjava.net/freeman1984/archive/2011/12/07/365726.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>hibernate，spring管理事务中(transaction，JDBC connection，Hibernate Session的使用研究)（一）</title><link>http://www.blogjava.net/freeman1984/archive/2011/11/18/363984.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Fri, 18 Nov 2011 03:25:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2011/11/18/363984.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/363984.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2011/11/18/363984.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/363984.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/363984.html</trackback:ping><description><![CDATA[如果单独使用hibernate可参考上一篇文章<a href="http://www.blogjava.net/freeman1984/archive/2011/08/04/355808.html">http://www.blogjava.net/freeman1984/archive/2011/08/04/355808.html</a><br /><br /><strong>首先hibernate的Connection release mode有以下几种：<br /></strong>1 after_statement 2 after_transaction 3 on_close 其中after_statement 用在jta中 ，<span style="color: red"><strong>on_close 是3.1之前遗留的（也许是为spring留的-_-），也就是3.1之前默认是on_close ，但3.1之后默认如果单独使用hibernate是after_transaction，</strong></span>如果有第三方事务管理，就用第三方提供的默认值，spring就是默认使用了on_close。<br /><strong>在spring管理事务中我们看看系统启动后默认使用的配置：<br /></strong>1,ransaction strategy: org.springframework.orm.hibernate3.SpringTransactionFactory使用spring事务策略<br />2，hibernate内部 Automatic session close at end of transaction: disabled 因为已经交给spring了<br />3&nbsp;&nbsp; Connection release mode: auto 默认，也就是没有配置hibernate.connection.release_mode的时候，但是这里有地方需要注意：也就是前面提到的使用第三方策略时的问题：看一下代码： 
<div style="border-bottom: #cccccc 1px solid; border-left: #cccccc 1px solid; padding-bottom: 4px; background-color: #eeeeee; padding-left: 4px; width: 98%; padding-right: 5px; font-size: 13px; word-break: break-all; border-top: #cccccc 1px solid; border-right: #cccccc 1px solid; padding-top: 4px"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><img alt="" align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif" /><span style="color: #000000">String&nbsp;releaseModeName&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;PropertiesHelper.getString(&nbsp;Environment.RELEASE_CONNECTIONS,&nbsp;properties,&nbsp;</span><span style="color: #000000">"</span><span style="color: #000000">auto</span><span style="color: #000000">"</span><span style="color: #000000">&nbsp;);<br /><img alt="" align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;log.info(&nbsp;</span><span style="color: #000000">"</span><span style="color: #000000">Connection&nbsp;release&nbsp;mode:&nbsp;</span><span style="color: #000000">"</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">+</span><span style="color: #000000">&nbsp;releaseModeName&nbsp;);<br /><img alt="" align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ConnectionReleaseMode&nbsp;releaseMode;<br /><img id="Codehighlighter1_246_311_Open_Image" onclick="this.style.display='none'; Codehighlighter1_246_311_Open_Text.style.display='none'; Codehighlighter1_246_311_Closed_Image.style.display='inline'; Codehighlighter1_246_311_Closed_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif"><img style="display: none" id="Codehighlighter1_246_311_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_246_311_Closed_Text.style.display='none'; Codehighlighter1_246_311_Open_Image.style.display='inline'; Codehighlighter1_246_311_Open_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">if</span><span style="color: #000000">&nbsp;(&nbsp;</span><span style="color: #000000">"</span><span style="color: #000000">auto</span><span style="color: #000000">"</span><span style="color: #000000">.equals(releaseModeName)&nbsp;)&nbsp;</span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_246_311_Closed_Text"><img alt="" src="http://www.blogjava.net/Images/dot.gif" /></span><span id="Codehighlighter1_246_311_Open_Text"><span style="color: #000000">{<br /><img alt="" align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: red">releaseMode&nbsp;</span><span style="color: red">=</span><span style="color: red">&nbsp;transactionFactory.getDefaultReleaseMode();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span><span style="color: #000000"><br /><img alt="" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" /></span></span><span style="color: #000000"><br /><img id="Codehighlighter1_320_663_Open_Image" onclick="this.style.display='none'; Codehighlighter1_320_663_Open_Text.style.display='none'; Codehighlighter1_320_663_Closed_Image.style.display='inline'; Codehighlighter1_320_663_Closed_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif"><img style="display: none" id="Codehighlighter1_320_663_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_320_663_Closed_Text.style.display='none'; Codehighlighter1_320_663_Open_Image.style.display='inline'; Codehighlighter1_320_663_Open_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">else</span><span style="color: #000000">&nbsp;</span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_320_663_Closed_Text"><img alt="" src="http://www.blogjava.net/Images/dot.gif" /></span><span id="Codehighlighter1_320_663_Open_Text"><span style="color: #000000">{<br /><img alt="" align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;releaseMode&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;ConnectionReleaseMode.parse(&nbsp;releaseModeName&nbsp;);<br /><img id="Codehighlighter1_494_659_Open_Image" onclick="this.style.display='none'; Codehighlighter1_494_659_Open_Text.style.display='none'; Codehighlighter1_494_659_Closed_Image.style.display='inline'; Codehighlighter1_494_659_Closed_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif"><img style="display: none" id="Codehighlighter1_494_659_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_494_659_Closed_Text.style.display='none'; Codehighlighter1_494_659_Open_Image.style.display='inline'; Codehighlighter1_494_659_Open_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">if</span><span style="color: #000000">&nbsp;(&nbsp;releaseMode&nbsp;</span><span style="color: #000000">==</span><span style="color: #000000">&nbsp;ConnectionReleaseMode.AFTER_STATEMENT&nbsp;</span><span style="color: #000000">&amp;&amp;</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">!</span><span style="color: #000000">connections.supportsAggressiveRelease()&nbsp;)&nbsp;</span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_494_659_Closed_Text"><img alt="" src="http://www.blogjava.net/Images/dot.gif" /></span><span id="Codehighlighter1_494_659_Open_Text"><span style="color: #000000">{<br /><img alt="" align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;log.warn(&nbsp;</span><span style="color: #000000">"</span><span style="color: #000000">Overriding&nbsp;release&nbsp;mode&nbsp;as&nbsp;connection&nbsp;provider&nbsp;does&nbsp;not&nbsp;support&nbsp;'after_statement'</span><span style="color: #000000">"</span><span style="color: #000000">&nbsp;);<br /><img alt="" align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;releaseMode&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;ConnectionReleaseMode.AFTER_TRANSACTION;<br /><img alt="" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: #000000"><br /><img alt="" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span></div>其中红色部分就是调用了spring提供的默认值，而spring的默认值：在jta和cmt中都默认使用的是after_statement<br />
<div style="border-bottom: #cccccc 1px solid; border-left: #cccccc 1px solid; padding-bottom: 4px; background-color: #eeeeee; padding-left: 4px; width: 98%; padding-right: 5px; font-size: 13px; word-break: break-all; border-top: #cccccc 1px solid; border-right: #cccccc 1px solid; padding-top: 4px"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><img id="Codehighlighter1_0_328_Open_Image" onclick="this.style.display='none'; Codehighlighter1_0_328_Open_Text.style.display='none'; Codehighlighter1_0_328_Closed_Image.style.display='inline'; Codehighlighter1_0_328_Closed_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif"><img style="display: none" id="Codehighlighter1_0_328_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_0_328_Closed_Text.style.display='none'; Codehighlighter1_0_328_Open_Image.style.display='inline'; Codehighlighter1_0_328_Open_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif"><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_0_328_Closed_Text">/**&nbsp;*/</span><span id="Codehighlighter1_0_328_Open_Text"><span style="color: #008000">/**</span><span style="color: #008000"><br /><img alt="" align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;Sets&nbsp;connection&nbsp;release&nbsp;mode&nbsp;"on_close"&nbsp;as&nbsp;default.<br /><img alt="" align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;&lt;p&gt;This&nbsp;was&nbsp;the&nbsp;case&nbsp;for&nbsp;Hibernate&nbsp;3.0;&nbsp;Hibernate&nbsp;3.1&nbsp;changed<br /><img alt="" align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;it&nbsp;to&nbsp;"auto"&nbsp;(i.e.&nbsp;"after_statement"&nbsp;or&nbsp;"after_transaction").<br /><img alt="" align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;However,&nbsp;for&nbsp;Spring's&nbsp;resource&nbsp;management&nbsp;(in&nbsp;particular&nbsp;for<br /><img alt="" align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;HibernateTransactionManager),&nbsp;"on_close"&nbsp;is&nbsp;the&nbsp;better&nbsp;default.<br /><img alt="" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000">*/</span></span><span style="color: #000000"><br /><img id="Codehighlighter1_384_428_Open_Image" onclick="this.style.display='none'; Codehighlighter1_384_428_Open_Text.style.display='none'; Codehighlighter1_384_428_Closed_Image.style.display='inline'; Codehighlighter1_384_428_Closed_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif"><img style="display: none" id="Codehighlighter1_384_428_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_384_428_Closed_Text.style.display='none'; Codehighlighter1_384_428_Open_Image.style.display='inline'; Codehighlighter1_384_428_Open_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;ConnectionReleaseMode&nbsp;getDefaultReleaseMode()&nbsp;</span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_384_428_Closed_Text"><img alt="" src="http://www.blogjava.net/Images/dot.gif" /></span><span id="Codehighlighter1_384_428_Open_Text"><span style="color: #000000">{<br /><img alt="" align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">return</span><span style="color: #000000">&nbsp;ConnectionReleaseMode.ON_CLOSE;<br /><img alt="" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" />&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: #000000"><br /><img alt="" align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif" /></span></div><br />而spring为什么要使用on_close ，而不是用after_transaction ,我们想想opensessioninview的原理也许能明白，session在view成还要使用，所以不能再transactio<span>n使用完后关闭JDBC connection，必须要在session之后，所以要使用on<strong>_close</strong></span><strong><span>（</span><span>也就是在on session(flush.auto，或者flush.Eagerly) 关闭）。这种情况hibernate内部还会在spring关闭JDBC connection后提示(费解，因为after transaction之后session没有关闭，但是&nbsp;Connection release mode配置的是on_close,session的关闭和&nbsp;Connection 的关闭都由spring来管理，hibernate就不知道了)，所以hibernate有好的提示如下(其实session，已经关闭。当然随着session的关闭jdbc链接释放回连接池)：</span><br /><span style="color: red">transaction completed on session with on_close connection release mode; be sure to cl</span></strong>ose the session to release JDBC resources!，<br /><br />。当然我们也可以使用after_transaction ，这种情况对使用编程式事务非常适用。<br />&nbsp;&nbsp;&nbsp;&nbsp;   <img src ="http://www.blogjava.net/freeman1984/aggbug/363984.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2011-11-18 11:25 <a href="http://www.blogjava.net/freeman1984/archive/2011/11/18/363984.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>jsessionid 问题分析</title><link>http://www.blogjava.net/freeman1984/archive/2011/09/02/357833.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Fri, 02 Sep 2011 08:33:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2011/09/02/357833.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/357833.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2011/09/02/357833.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/357833.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/357833.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: JSESSIONID 问题分析&nbsp;&nbsp;<a href='http://www.blogjava.net/freeman1984/archive/2011/09/02/357833.html'>阅读全文</a><img src ="http://www.blogjava.net/freeman1984/aggbug/357833.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2011-09-02 16:33 <a href="http://www.blogjava.net/freeman1984/archive/2011/09/02/357833.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>raid技术</title><link>http://www.blogjava.net/freeman1984/archive/2011/06/21/352756.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Tue, 21 Jun 2011 09:07:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2011/06/21/352756.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/352756.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2011/06/21/352756.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/352756.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/352756.html</trackback:ping><description><![CDATA[<h3><span style="letter-spacing: 0.25pt">RAID 0</span><span style="font-family: 宋体; letter-spacing: 0.25pt">：无差错控制的带区组</span><span style="letter-spacing: 0.25pt"></span></h3>
<p><span style="font-family: 宋体; letter-spacing: 0.25pt">　　</span> </p>
<p style="text-indent: 15.75pt"><span style="font-family: 宋体">要实现</span>RAID0<span style="font-family: 宋体">必须要有两个以上硬盘驱动器，</span>RAID0<span style="font-family: 宋体">实现了带区组，数据并不是保存在一个硬盘上，而是分成数据块保存在不同驱动器上。因为将数据分布在不同驱动器上，所以数据吞吐率大大提高，驱动器的负载也比较平衡。如果刚好所需要的数据在不同的驱动器上效率最好。它不需要计算校验码，实现容易。它的缺点是它没有数据差错控制，如果一个驱动器中的数据发生错误，即使其它盘上的数据正确也无济于事了。不应该将它用于对数据稳定性要求高的场合。如果用户进行图象（包括动画）编辑和其它要求传输比较大的场合使用</span>RAID0<span style="font-family: 宋体">比较合适。同时，</span>RAID<span style="font-family: 宋体">可以提高数据传输速率，比如所需读取的文件分布在两个硬盘上，这两个硬盘可以同时读取。那么原来读取同样文件的时间被缩短为</span>1/2<span style="font-family: 宋体">。在所有的级别中，</span>RAID 0<span style="font-family: 宋体">的速度是最快的。但是</span>RAID 0<span style="font-family: 宋体">没有冗余功能的，如果一个磁盘（物理）损坏，则所有的数据都无法使用。</span></p>
<p style="text-indent: 21pt">RAID0<span style="font-family: 宋体">又称为</span>Stripe<span style="font-family: 宋体">或</span>Striping<span style="font-family: 宋体">，它代表了所有</span>RAID<span style="font-family: 宋体">级别中最高的</span><span style="font-family: 宋体"><span>存储</span></span><span style="font-family: 宋体">性能。</span>RAID 0<span style="font-family: 宋体">提高存储性能的原理是把连续的数据分散到多个磁盘上存取，这样，系统有数据请求就可以被多个磁盘并行的执行，每个磁盘执行属于它自己的那部分数据请求。这种数据上的并行操作可以充分利用总线的带宽，显著提高磁盘整体存取性能。</span></p>
<p><span style="font-family: 宋体">　　如图所示</span>:<span style="font-family: 宋体">系统向三个磁盘组成的逻辑硬盘</span>(RADI 0 <span style="font-family: 宋体">磁盘组</span>)<span style="font-family: 宋体">发出的</span>I/O<span style="font-family: 宋体">数据请求被转化为</span>3<span style="font-family: 宋体">项操作，其中的每一项操作都对应于一块物理硬盘。我们从图中可以清楚的看到通过建立</span>RAID 0<span style="font-family: 宋体">，原先顺序的数据请求被分散到所有的三块硬盘中同时执行。</span></p>
<p style="text-align: center; line-height: 160%" align="center"></p>
<p><span style="font-family: 宋体">　　从理论上讲，三块硬盘的并行操作使同一时间内磁盘读写速度提升了</span>3<span style="font-family: 宋体">倍。</span> <span style="font-family: 宋体">但由于总线带宽等多种因素的影响，实际的提升速率肯定会低于理论值，但是，大量数据并行传输与串行传输比较，提速效果显著显然毋庸置疑。</span></p>
<p><span style="font-family: 宋体">　　</span>RAID 0<span style="font-family: 宋体">的缺点是不提供数据冗余，因此一旦用户数据损坏，损坏的数据将无法得到恢复。</span></p>
<p><span style="font-family: 宋体">　　</span>RAID 0<span style="font-family: 宋体">具有的特点，使其特别适用于对性能要求较高，而对数据</span><span style="font-family: 宋体"><span>安全</span></span><span style="font-family: 宋体">不太在乎的领域，如图形工作站等。对于个人用户，</span>RAID 0<span style="font-family: 宋体">也是提高硬盘存储性能的绝佳选择。</span></p>
<p>&nbsp;</p>
<h3><span style="letter-spacing: 0.25pt">RAID 1</span><span style="font-family: 宋体; letter-spacing: 0.25pt">：镜象结构</span></h3>
<p style="text-align: center; margin: 1.5pt 0cm 0pt;background: #f6f6f6; word-break: break-all" align="center"><span style="font-family: 宋体; letter-spacing: 0.25pt">　　</span> </p>
<p style="text-indent: 22pt"><span style="font-family: 宋体; letter-spacing: 0.25pt">对于使用这种</span><span style="letter-spacing: 0.25pt">RAID1</span><span style="font-family: 宋体; letter-spacing: 0.25pt">结构的设备来说，</span><span style="letter-spacing: 0.25pt">RAID</span><span style="font-family: 宋体; letter-spacing: 0.25pt">控制器必须能够同时对两个盘进行读操作和对两个镜象盘进行写操作。通过下面的结构图您也可以看到必须有两个驱动器。因为是镜象结构在一组盘出现问题时，可以使用镜象，提高系统的容错能力。它比较容易设计和实现。每读一次盘只能读出一块数据，也就是说数据块传送速率与单独的盘的读取速率相同。因为</span><span style="letter-spacing: 0.25pt">RAID1</span><span style="font-family: 宋体; letter-spacing: 0.25pt">的校验十分完备，因此对系统的处理能力有很大的影响，通常的</span><span style="letter-spacing: 0.25pt">RAID</span><span style="font-family: 宋体; letter-spacing: 0.25pt">功能由软件实现，而这样的实现方法在服务器负载比较重的时候会大大影响服务器效率。当您的系统需要极高的可靠性时，如进行数据统计，那么使用</span><span style="letter-spacing: 0.25pt">RAID1</span><span style="font-family: 宋体; letter-spacing: 0.25pt">比较合适。而且</span><span style="letter-spacing: 0.25pt">RAID1</span><span style="font-family: 宋体; letter-spacing: 0.25pt">技术支持</span><span style="letter-spacing: 0.25pt">&#8220;</span><span style="font-family: 宋体; letter-spacing: 0.25pt">热替换</span><span style="letter-spacing: 0.25pt">&#8221;</span><span style="font-family: 宋体; letter-spacing: 0.25pt">，即不断电的情况下对故障磁盘进行更换，更换完毕只要从镜像盘上恢复数据即可。当主硬盘损坏时，镜像硬盘就可以代替主硬盘工作。镜像硬盘相当于一个备份盘，可想而知，这种硬盘模式的安全性是非常高的，</span><span style="letter-spacing: 0.25pt">RAID 1</span><span style="font-family: 宋体; letter-spacing: 0.25pt">的数据安全性在所有的</span><span style="letter-spacing: 0.25pt">RAID</span><span style="font-family: 宋体; letter-spacing: 0.25pt">级别上来说是最好的。但是其磁盘的利用率却只有</span><span style="letter-spacing: 0.25pt">50%</span><span style="font-family: 宋体; letter-spacing: 0.25pt">，是所有</span><span style="letter-spacing: 0.25pt">RAID</span><span style="font-family: 宋体; letter-spacing: 0.25pt">级别中最低的。</span></p>
<p><span style="font-family: 宋体">　</span><span style="letter-spacing: 0.25pt">RAID1</span><span style="font-family: 宋体">又称为</span>Mirror<span style="font-family: 宋体">或</span>Mirroring<span style="font-family: 宋体">，它的宗旨是最大限度的保证用户数据的可用性和可修复性。</span> RAID 1<span style="font-family: 宋体">的操作方式是把用户写入硬盘的数据百分之百地自动复制到另外一个硬盘上。</span></p>
<p><span style="font-family: 宋体">　　当读取数据时，系统先从</span>RAID 0<span style="font-family: 宋体">的源盘读取数据，如果读取数据成功，则系统不去管备份盘上的数据</span>;<span style="font-family: 宋体">如果读取源盘数据失败，则系统自动转而读取备份盘上的数据，不会造成用户工作任务的中断。当然，我们应当及时地更换损坏的硬盘并利用备份数据重新建立</span>Mirror<span style="font-family: 宋体">，避免备份盘在发生损坏时，造成不可挽回的数据损失。</span></p>
<p style="text-align: center; line-height: 160%" align="center"></p>
<p><span style="font-family: 宋体">　　由于对</span><span style="font-family: 宋体"><span>存储</span></span><span style="font-family: 宋体">的数据进行百分之百的备份，在所有</span>RAID<span style="font-family: 宋体">级别中，</span>RAID 1<span style="font-family: 宋体">提供最高的数据</span><span style="font-family: 宋体"><span>安全</span></span><span style="font-family: 宋体">保障。同样，由于数据的百分之百备份，备份数据占了总存储空间的一半，因而，</span>Mirror<span style="font-family: 宋体">的磁盘空间利用率低，存储成本高。</span></p>
<p><span style="font-family: 宋体">　　</span>Mirror<span style="font-family: 宋体">虽不能提高存储性能，但由于其具有的高数据安全性，使其尤其适用于存放重要数据，如</span><span style="font-family: 宋体"><span>服务器</span></span><span style="font-family: 宋体">和数据库存储等领域。</span></p>
<p>&nbsp;</p>
<h3>RAID 0+1</h3>
<p>RAID 0+1:<span style="font-family: 宋体">正如其名字一样</span>RAID 0+1<span style="font-family: 宋体">是</span>RAID 0<span style="font-family: 宋体">和</span>RAID 1<span style="font-family: 宋体">的组合形式，也称为</span>RAID 10<span style="font-family: 宋体">。</span></p>
<p><span style="font-family: 宋体">　　以四个磁盘组成的</span>RAID 0+1<span style="font-family: 宋体">为例，其数据</span><span style="font-family: 宋体"><span>存储</span></span><span style="font-family: 宋体">方式如图所示</span>:RAID 0+1<span style="font-family: 宋体">是存储性能和数据</span><span style="font-family: 宋体"><span>安全</span></span><span style="font-family: 宋体">兼顾的方案。它在提供与</span>RAID 1<span style="font-family: 宋体">一样的数据安全保障的同时，也提供了与</span>RAID 0<span style="font-family: 宋体">近似的存储性能。</span></p>
<p><span style="font-family: 宋体">　　由于</span>RAID 0+1<span style="font-family: 宋体">也通过数据的</span>100%<span style="font-family: 宋体">备份提供数据安全保障，因此</span>RAID 0+1<span style="font-family: 宋体">的磁盘空间利用率与</span>RAID 1<span style="font-family: 宋体">相同，存储成本高。</span></p>
<p style="text-align: center; line-height: 160%" align="center"></p>
<p>RAID 0+1<span style="font-family: 宋体">的特点使其特别适用于既有大量数据需要存取，同时又对数据安全性要求严格的领域，如银行、金融、商业超市、仓储库房、各种档案管理等。</span></p>
<h3><span style="letter-spacing: 0.25pt">RAID2</span><span style="font-family: 宋体; letter-spacing: 0.25pt">：带海明码校验</span></h3>
<p><span style="font-family: 宋体; letter-spacing: 0.25pt">　　</span> </p>
<p><span style="font-family: 宋体; letter-spacing: 0.25pt">从概念上讲，</span><span style="letter-spacing: 0.25pt">RAID 2 </span><span style="font-family: 宋体; letter-spacing: 0.25pt">同</span><span style="letter-spacing: 0.25pt">RAID 3</span><span style="font-family: 宋体; letter-spacing: 0.25pt">类似，</span> <span style="font-family: 宋体; letter-spacing: 0.25pt">两者都是将数据条块化分布于不同的硬盘上，</span> <span style="font-family: 宋体; letter-spacing: 0.25pt">条块单位为位或字节。然而</span><span style="letter-spacing: 0.25pt">RAID 2 </span><span style="font-family: 宋体; letter-spacing: 0.25pt">使用一定的编码技术来提供错误检查及恢复。这种编码技术需要多个磁盘存放检查及恢复信息，使得</span><span style="letter-spacing: 0.25pt">RAID 2</span><span style="font-family: 宋体; letter-spacing: 0.25pt">技术实施更复杂。因此，在商业环境中很少使用。下图左边的各个磁盘上是数据的各个位，由一个数据不同的位运算得到的海明校验码可以保存另一组磁盘上，具体情况请见下图。由于海明码的特点，它可以在数据发生错误的情况下将错误校正，以保证输出的正确。它的数据传送速率相当高，如果希望达到比较理想的速度，那最好提高保存校验码</span><span style="letter-spacing: 0.25pt">ECC</span><span style="font-family: 宋体; letter-spacing: 0.25pt">码的硬盘，对于控制器的设计来说，它又比</span><span style="letter-spacing: 0.25pt">RAID3</span><span style="font-family: 宋体; letter-spacing: 0.25pt">，</span><span style="letter-spacing: 0.25pt">4</span><span style="font-family: 宋体; letter-spacing: 0.25pt">或</span><span style="letter-spacing: 0.25pt">5</span><span style="font-family: 宋体; letter-spacing: 0.25pt">要简单。没有免费的午餐，这里也一样，要利用海明码，必须要付出数据冗余的代价。输出数据的速率与驱动器组中速度最慢的相等。</span></p>
<h3><span style="letter-spacing: 0.25pt">RAID3</span><span style="font-family: 宋体; letter-spacing: 0.25pt">：带奇偶校验码的并行传送</span></h3>
<p>&nbsp;</p>
<p style="text-indent: 25pt"><span style="font-family: 宋体; letter-spacing: 0.25pt; font-size: 12pt">这种校验码与RAID2不同，只能查错不能纠错。它访问数据时一次处理一个带区，这样可以提高读取和写入速度,它像RAID 0一样以并行的方式来存放数据，但速度没有RAID 0快。校验码在写入数据时产生并保存在另一个磁盘上。需要实现时用户必须要有三个以上的驱动器，写入速率与读出速率都很高，因为校验位比较少，因此计算时间相对而言比较少。用软件实现RAID控制将是十分困难的，控制器的实现也不是很容易。它主要用于图形（包括动画）等要求吞吐率比较高的场合。不同于RAID 2，RAID 3使用单块磁盘存放奇偶校验信息。如果一块磁盘失效，奇偶盘及其他数据盘可以重新产生数据。如果奇偶盘失效，则不影响数据使用。RAID 3对于大量的连续数据可提供很好的传输率，但对于随机数据，奇偶盘会成为写操作的瓶颈。利用单独的校验盘来保护数据虽然没有镜像的安全性高，但是硬盘利用率得到了很大的提高，为（n-1）/n。</span></p>
<h3><span style="letter-spacing: 0.25pt">RAID4</span><span style="font-family: 宋体; letter-spacing: 0.25pt">：带奇偶校验码的独立磁盘结构</span></h3>
<p><span style="font-family: 宋体">　　</span> </p>
<p style="text-indent: 26.25pt">RAID4<span style="font-family: 宋体">和</span>RAID3<span style="font-family: 宋体">很象，不同的是，它对数据的访问是按数据块进行的，也就是按磁盘进行的，每次是一个盘。在图上可以这么看，</span>RAID3<span style="font-family: 宋体">是一次一横条，而</span>RAID4<span style="font-family: 宋体">一次一竖条。它的特点的</span>RAID3<span style="font-family: 宋体">也挺象，不过在失败恢复时，它的难度可要比</span>RAID3<span style="font-family: 宋体">大得多了，控制器的设计难度也要大许多，而且访问数据的效率不怎么好。</span></p>
<h3><span style="letter-spacing: 0.25pt">RAID5</span><span style="font-family: 宋体; letter-spacing: 0.25pt">：分布式奇偶校验的独立磁盘结构</span></h3>
<p style="text-align: center; margin: 1.5pt 0cm 0pt;background: #f6f6f6; word-break: break-all" align="center"><span style="font-family: 宋体; letter-spacing: 0.25pt">　　</span> </p>
<p style="text-indent: 21pt"><span style="font-family: 宋体">从它的示意图上可以看到，它的奇偶校验码存在于所有磁盘上，其中的</span>p0<span style="font-family: 宋体">代表第</span>0<span style="font-family: 宋体">带区的奇偶校验值，其它的意思也相同。</span>RAID5<span style="font-family: 宋体">的读出效率很高，写入效率一般，块式的集体访问效率不错。因为奇偶校验码在不同的磁盘上，所以提高了可靠性，允许单个磁盘出错。</span>RAID 5<span style="font-family: 宋体">也是以数据的校验位来保证数据的安全，但它不是以单独硬盘来存放数据的校验位，而是将数据段的校验位交互存放于各个硬盘上。这样，任何一个硬盘损坏，都可以根据其它硬盘上的校验位来重建损坏的数据。硬盘的利用率为</span>n-1<span style="font-family: 宋体">。</span> <span style="font-family: 宋体">但是它对数据传输的并行性解决不好，而且控制器的设计也相当困难。</span>RAID 3 <span style="font-family: 宋体">与</span>RAID 5<span style="font-family: 宋体">相比，重要的区别在于</span>RAID 3<span style="font-family: 宋体">每进行一次数据传输，需涉及到所有的阵列盘。而对于</span>RAID 5<span style="font-family: 宋体">来说，大部分数据传输只对一块磁盘操作，可进行并行操作。在</span>RAID 5<span style="font-family: 宋体">中有</span>&#8220;<span style="font-family: 宋体">写损失</span>&#8221;<span style="font-family: 宋体">，即每一次写操作，将产生四个实际的读</span>/<span style="font-family: 宋体">写操作，其中两次读旧的数据及奇偶信息，两次写新的数据及奇偶信息。</span> RAID-5<span style="font-family: 宋体">的话，优点是提供了冗余性（支持一块盘掉线后仍然正常运行），磁盘空间利用率较高（</span>N-1/N<span style="font-family: 宋体">），读写速度较快（</span>N-1<span style="font-family: 宋体">倍）。</span>RAID5<span style="font-family: 宋体">最大的好处是在一块盘掉线的情况下，</span>RAID<span style="font-family: 宋体">照常工作，相对于</span>RAID0<span style="font-family: 宋体">必须每一块盘都正常才可以正常工作的状况容错性能好多了。因此</span>RAID5<span style="font-family: 宋体">是</span>RAID<span style="font-family: 宋体">级别中最常见的一个类型。</span>RAID5<span style="font-family: 宋体">校验位即</span>P<span style="font-family: 宋体">位是通过其它条带数据做异或</span>(xor)<span style="font-family: 宋体">求得的。计算公式为</span>P=D0xorD1xorD2&#8230;xorDn<span style="font-family: 宋体">，其中</span>p<span style="font-family: 宋体">代表校验块，</span>Dn<span style="font-family: 宋体">代表相应的数据块，</span>xor<span style="font-family: 宋体">是数学运算符号异或。</span> </p>
<p><span style="font-family: 宋体">　　</span>RAID5<span style="font-family: 宋体">校验位算法详解</span> </p>
<p><span style="font-family: 宋体">　　</span>P=D1 xor D2 xor D3 &#8230; xor Dn <span style="font-family: 宋体">（</span>D1,D2,D3 &#8230; Dn<span style="font-family: 宋体">为数据块，</span>P<span style="font-family: 宋体">为校验，</span>xor<span style="font-family: 宋体">为异或运算）</span> </p>
<p><span style="font-family: 宋体">　　</span>XOR(Exclusive OR)<span style="font-family: 宋体">的校验原理如下表：</span> </p>
<p><span style="font-family: 宋体">　　</span> </p>
<table style="border-bottom: #888888 1pt solid; border-left: #888888 1pt solid; border-top: #888888 1pt solid; border-right: #888888 1pt solid" border="1" cellpadding="0">
<tbody>
<tr>
<td style="border-bottom: #888888 1pt solid; border-left: #888888 1pt solid; padding-bottom: 1.5pt; background-color: transparent; padding-left: 5.05pt; width: 5cm; padding-right: 5.05pt; border-top: #888888 1pt solid; border-right: #888888 1pt solid; padding-top: 1.5pt" valign="top" width="189">
<p>A<span style="font-family: 宋体">值</span></p></td>
<td style="border-bottom: #888888 1pt solid; border-left: #888888 1pt solid; padding-bottom: 1.5pt; background-color: transparent; padding-left: 5.05pt; width: 5cm; padding-right: 5.05pt; border-top: #888888 1pt solid; border-right: #888888 1pt solid; padding-top: 1.5pt" valign="top" width="189">
<p>B<span style="font-family: 宋体">值</span></p></td>
<td style="border-bottom: #888888 1pt solid; border-left: #888888 1pt solid; padding-bottom: 1.5pt; background-color: transparent; padding-left: 5.05pt; width: 5cm; padding-right: 5.05pt; border-top: #888888 1pt solid; border-right: #888888 1pt solid; padding-top: 1.5pt" valign="top" width="189">
<p>Xor<span style="font-family: 宋体">结果</span></p></td></tr>
<tr>
<td style="border-bottom: #888888 1pt solid; border-left: #888888 1pt solid; padding-bottom: 1.5pt; background-color: transparent; padding-left: 5.05pt; width: 5cm; padding-right: 5.05pt; border-top: #888888 1pt solid; border-right: #888888 1pt solid; padding-top: 1.5pt" valign="top" width="189">
<p>0</p></td>
<td style="border-bottom: #888888 1pt solid; border-left: #888888 1pt solid; padding-bottom: 1.5pt; background-color: transparent; padding-left: 5.05pt; width: 5cm; padding-right: 5.05pt; border-top: #888888 1pt solid; border-right: #888888 1pt solid; padding-top: 1.5pt" valign="top" width="189">
<p>0</p></td>
<td style="border-bottom: #888888 1pt solid; border-left: #888888 1pt solid; padding-bottom: 1.5pt; background-color: transparent; padding-left: 5.05pt; width: 5cm; padding-right: 5.05pt; border-top: #888888 1pt solid; border-right: #888888 1pt solid; padding-top: 1.5pt" valign="top" width="189">
<p>0</p></td></tr>
<tr>
<td style="border-bottom: #888888 1pt solid; border-left: #888888 1pt solid; padding-bottom: 1.5pt; background-color: transparent; padding-left: 5.05pt; width: 5cm; padding-right: 5.05pt; border-top: #888888 1pt solid; border-right: #888888 1pt solid; padding-top: 1.5pt" valign="top" width="189">
<p>1</p></td>
<td style="border-bottom: #888888 1pt solid; border-left: #888888 1pt solid; padding-bottom: 1.5pt; background-color: transparent; padding-left: 5.05pt; width: 5cm; padding-right: 5.05pt; border-top: #888888 1pt solid; border-right: #888888 1pt solid; padding-top: 1.5pt" valign="top" width="189">
<p>0</p></td>
<td style="border-bottom: #888888 1pt solid; border-left: #888888 1pt solid; padding-bottom: 1.5pt; background-color: transparent; padding-left: 5.05pt; width: 5cm; padding-right: 5.05pt; border-top: #888888 1pt solid; border-right: #888888 1pt solid; padding-top: 1.5pt" valign="top" width="189">
<p>1</p></td></tr>
<tr>
<td style="border-bottom: #888888 1pt solid; border-left: #888888 1pt solid; padding-bottom: 1.5pt; background-color: transparent; padding-left: 5.05pt; width: 5cm; padding-right: 5.05pt; border-top: #888888 1pt solid; border-right: #888888 1pt solid; padding-top: 1.5pt" valign="top" width="189">
<p>0</p></td>
<td style="border-bottom: #888888 1pt solid; border-left: #888888 1pt solid; padding-bottom: 1.5pt; background-color: transparent; padding-left: 5.05pt; width: 5cm; padding-right: 5.05pt; border-top: #888888 1pt solid; border-right: #888888 1pt solid; padding-top: 1.5pt" valign="top" width="189">
<p>1</p></td>
<td style="border-bottom: #888888 1pt solid; border-left: #888888 1pt solid; padding-bottom: 1.5pt; background-color: transparent; padding-left: 5.05pt; width: 5cm; padding-right: 5.05pt; border-top: #888888 1pt solid; border-right: #888888 1pt solid; padding-top: 1.5pt" valign="top" width="189">
<p>1</p></td></tr>
<tr>
<td style="border-bottom: #888888 1pt solid; border-left: #888888 1pt solid; padding-bottom: 1.5pt; background-color: transparent; padding-left: 5.05pt; width: 5cm; padding-right: 5.05pt; border-top: #888888 1pt solid; border-right: #888888 1pt solid; padding-top: 1.5pt" valign="top" width="189">
<p>1</p></td>
<td style="border-bottom: #888888 1pt solid; border-left: #888888 1pt solid; padding-bottom: 1.5pt; background-color: transparent; padding-left: 5.05pt; width: 5cm; padding-right: 5.05pt; border-top: #888888 1pt solid; border-right: #888888 1pt solid; padding-top: 1.5pt" valign="top" width="189">
<p>1</p></td>
<td style="border-bottom: #888888 1pt solid; border-left: #888888 1pt solid; padding-bottom: 1.5pt; background-color: transparent; padding-left: 5.05pt; width: 5cm; padding-right: 5.05pt; border-top: #888888 1pt solid; border-right: #888888 1pt solid; padding-top: 1.5pt" valign="top" width="189">
<p>0</p></td></tr></tbody></table>
<p><span style="font-family: 宋体">　　这里的</span>A<span style="font-family: 宋体">与</span>B<span style="font-family: 宋体">值就代表了两个位，从中可以发现，</span>A<span style="font-family: 宋体">与</span>B<span style="font-family: 宋体">一样时，</span>XOR(<span style="font-family: 宋体">非或又称</span>"<span style="font-family: 宋体">非异或</span>")<span style="font-family: 宋体">结果为</span>0<span style="font-family: 宋体">，</span>A<span style="font-family: 宋体">与</span>B<span style="font-family: 宋体">不一样时，</span>XOR<span style="font-family: 宋体">结果就是</span>1<span style="font-family: 宋体">，如果知道</span>XOR<span style="font-family: 宋体">结果，</span>A<span style="font-family: 宋体">和</span>B<span style="font-family: 宋体">中的任何两个数值，就可以反推出剩下的一个数值。比如</span>A<span style="font-family: 宋体">为</span>1<span style="font-family: 宋体">，</span>XOR<span style="font-family: 宋体">结果为</span>1<span style="font-family: 宋体">，那么</span>B<span style="font-family: 宋体">肯定为</span>0<span style="font-family: 宋体">，如果</span>XOR<span style="font-family: 宋体">结果为</span>0<span style="font-family: 宋体">，那么</span>B<span style="font-family: 宋体">肯定为</span>1<span style="font-family: 宋体">。这就是</span>XOR<span style="font-family: 宋体">编码与校验的基本原理。</span></p>
<p style="text-indent: 26.25pt">RAID 5<span style="font-family: 宋体">是一种</span><span style="font-family: 宋体"><span>存储</span></span><span style="font-family: 宋体">性能、数据</span><span style="font-family: 宋体"><span>安全</span></span><span style="font-family: 宋体">和存储成本兼顾的存储解决方案。</span> <span style="font-family: 宋体">以四个硬盘组成的</span>RAID 5<span style="font-family: 宋体">为例，其数据存储方式如下图所示</span>:</p>
<p><span style="font-family: 宋体">　　</span></p>
<p style="text-align: center; line-height: 160%" align="center"></p>
<p style="text-align: center; line-height: 160%" align="center">图中，P0为D0，D1和D2的奇偶校验信息，其它以此类推。</p>
<p><span style="font-family: 宋体">　　由图中可以看出，</span>RAID 5<span style="font-family: 宋体">不对存储的数据进行备份，而是把数据和相对应的奇偶校验信息存储到组成</span>RAID5<span style="font-family: 宋体">的各个磁盘上，并且奇偶校验信息和相对应的数据分别存储于不同的磁盘上。当</span>RAID5<span style="font-family: 宋体">的一个磁盘数据发生损坏后，利用剩下的数据和相应的奇偶校验信息去恢复被损坏的数据。</span></p>
<p style="text-indent: 21pt">RAID 5<span style="font-family: 宋体">可以理解为是</span>RAID 0<span style="font-family: 宋体">和</span>RAID 1<span style="font-family: 宋体">的折衷方案。</span>RAID 5<span style="font-family: 宋体">可以为系统提供数据安全保障，但保障程度要比</span>Mirror<span style="font-family: 宋体">低而磁盘空间利用率要比</span>Mirror<span style="font-family: 宋体">高。</span>RAID 5<span style="font-family: 宋体">具有和</span>RAID 0<span style="font-family: 宋体">相近似的数据读取速度，只是多了一个奇偶校验信息，写入数据的速度比对单个磁盘进行写入操作稍慢。同时由于多个数据对应一个奇偶校验信息，</span>RAID 5<span style="font-family: 宋体">的磁盘空间利用率要比</span>RAID 1<span style="font-family: 宋体">高，存储成本相对较低。</span></p>
<h3><span style="font-family: 宋体">数据恢复</span></h3>
<p style="text-indent: 25pt"><span style="font-family: 宋体; letter-spacing: 0.25pt; font-size: 12pt">一旦RAID阵列出现故障，硬件服务商只能给客户重新初始化或者REBUILD，这样客户数据就会无法挽回。出现故障以后只要不对阵列作初始化操作，就有机会恢复出故障RAID磁盘阵列的数据。</span></p>
<p style="text-indent: 22pt"><span style="font-family: 宋体; letter-spacing: 0.25pt">由于</span><span style="letter-spacing: 0.25pt">RAID</span><span style="font-family: 宋体; letter-spacing: 0.25pt">数据恢复的复杂性和技术难度较高，在</span><span style="letter-spacing: 0.25pt">RAID</span><span style="font-family: 宋体; letter-spacing: 0.25pt">阵列出现故障时，一定要找有经验的专业数据恢复中心提供数据恢复帮助。判断专业数据恢复中心的标准包括数据恢复中心所使用的</span><span style="letter-spacing: 0.25pt">RAID</span><span style="font-family: 宋体; letter-spacing: 0.25pt">数据恢复工具、数据恢复工程师从业经验等。因为</span><span style="letter-spacing: 0.25pt">RAID</span><span style="font-family: 宋体; letter-spacing: 0.25pt">阵列中存储的数据一般都比较重要，一旦被彻底损坏，将造成无法挽回的损失。</span></p>
<p style="text-indent: 22pt"><span style="font-family: 宋体; letter-spacing: 0.25pt">目前常用的</span><span style="letter-spacing: 0.25pt">RAID</span><span style="font-family: 宋体; letter-spacing: 0.25pt">阵列数据恢复工具包括效率源</span><span style="letter-spacing: 0.25pt">HD Doctor</span><span style="font-family: 宋体; letter-spacing: 0.25pt">、数据恢复指南针</span><span style="letter-spacing: 0.25pt">Data Compass</span><span style="font-family: 宋体; letter-spacing: 0.25pt">、硬盘复制机</span><span style="letter-spacing: 0.25pt">Data Copy King</span><span style="font-family: 宋体; letter-spacing: 0.25pt">等。</span></p>
<p style="text-indent: 21pt">&nbsp;</p>
<p style="text-indent: 21pt"></p><img src ="http://www.blogjava.net/freeman1984/aggbug/352756.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2011-06-21 17:07 <a href="http://www.blogjava.net/freeman1984/archive/2011/06/21/352756.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Nginx tomcat负载配置</title><link>http://www.blogjava.net/freeman1984/archive/2011/02/15/344398.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Tue, 15 Feb 2011 15:08:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2011/02/15/344398.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/344398.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2011/02/15/344398.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/344398.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/344398.html</trackback:ping><description><![CDATA[<p><strong>Nginx.conf :</strong></p>
<p>user&nbsp; oschina;<br />
worker_processes&nbsp; 2;<br />
<br />
#error_log&nbsp; logs/error.log;<br />
#error_log&nbsp; logs/error.log&nbsp; notice;<br />
#error_log&nbsp; logs/error.log&nbsp; info;<br />
<br />
#pid&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; logs/nginx.pid;<br />
<br />
events {<br />
&nbsp;&nbsp;&nbsp; use epoll;<br />
&nbsp;&nbsp;&nbsp; worker_connections&nbsp; 2048;<br />
}<br />
<br />
http {<br />
&nbsp;&nbsp;&nbsp; include&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mime.types;<br />
&nbsp;&nbsp;&nbsp; default_type&nbsp; application/octet-stream;<br />
<br />
&nbsp;&nbsp;&nbsp; #log_format&nbsp; main&nbsp; '$remote_addr - $remote_user [$time_local] $request '<br />
&nbsp;&nbsp;&nbsp; #&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; '"$status" $body_bytes_sent "$http_referer" '<br />
&nbsp;&nbsp;&nbsp; #&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; '"$http_user_agent" "$http_x_forwarded_for"';<br />
<br />
&nbsp;&nbsp;&nbsp; #access_log&nbsp; off;<br />
&nbsp;&nbsp;&nbsp; access_log&nbsp; logs/access.log;<br />
<br />
&nbsp;&nbsp;&nbsp; client_header_timeout&nbsp; 3m;<br />
&nbsp;&nbsp;&nbsp; client_body_timeout&nbsp;&nbsp;&nbsp; 3m;<br />
&nbsp;&nbsp;&nbsp; send_timeout&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3m;<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp; client_header_buffer_size&nbsp;&nbsp;&nbsp; 1k;<br />
&nbsp;&nbsp;&nbsp; large_client_header_buffers&nbsp; 4 4k;<br />
<br />
&nbsp;&nbsp;&nbsp; sendfile&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; on;<br />
&nbsp;&nbsp;&nbsp; tcp_nopush&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; on;<br />
&nbsp;&nbsp;&nbsp; tcp_nodelay&nbsp;&nbsp;&nbsp;&nbsp; on;<br />
<br />
&nbsp;&nbsp;&nbsp; #keepalive_timeout&nbsp; 75 20;<br />
<br />
&nbsp;&nbsp;&nbsp; include&nbsp;&nbsp;&nbsp; gzip.conf;<br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; server {<br />
&nbsp;&nbsp;&nbsp; listen 80;<br />
&nbsp;&nbsp;&nbsp; server_name .oschina.net;<br />
&nbsp;&nbsp;&nbsp; location / {<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; rewrite (.*) <a href="http://www.test.net$1">http://www.<font color="#000000">test</font>.net$1</a> permanent;<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; }<br />
<br />
&nbsp;&nbsp;&nbsp; server {<br />
&nbsp;&nbsp;&nbsp; listen 80;<br />
&nbsp;&nbsp;&nbsp; server_name <a href="http://www.test.net">www.<font color="#000000">test</font>.net</a>;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; log_format&nbsp; oschina_log<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; '$remote_addr - $remote_user [$time_local] $request '<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; '"$status" $body_bytes_sent "$http_referer" '<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; '"$http_user_agent" "$http_x_forwarded_for"';<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; access_log&nbsp; logs/oschina.log;<br />
<br />
&nbsp;&nbsp;&nbsp; location ~ ^/(WEB-INF)/ {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; deny all;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; location ~ \.(apk|torrent|htm|html|asp|php|gif|jpg|jpeg|png|bmp|ico|rar|css|js|zip|java|jar|txt|flv|swf|mid|doc|ppt|xls|pdf|txt|mp3|wma)$ {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; root /data/oschina/webapp;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; access_log off;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; expires 24h;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; location ~ ^/uploads/ {<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; access_log off;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; root /data/test/webapp;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; expires 24h;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
<br />
&nbsp;&nbsp;&nbsp; location / {<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; proxy_pass http://localhost:8080;<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; include proxy.conf;<br />
&nbsp;&nbsp;&nbsp; }<br />
<br />
&nbsp;&nbsp;&nbsp; error_page 502 503 /502.html;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; error_page 404 /404.html;<br />
&nbsp;&nbsp;&nbsp; error_page 403 /403.html;<br />
&nbsp;&nbsp;&nbsp; }<br />
}</p>
<p><strong>gzip.conf:</strong></p>
<p>gzip&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; on;<br />
gzip_min_length&nbsp; &nbsp;&nbsp;&nbsp; 1000;<br />
gzip_types &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; text/plain text/css application/x-javascript;</p>
<p><strong>proxy.conf:</strong></p>
<p>proxy_redirect&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; off;<br />
proxy_set_header&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Host $host;<br />
proxy_set_header&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; X-Real-IP $remote_addr;<br />
proxy_set_header&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; X-Forwarded-For $proxy_add_x_forwarded_for;<br />
client_max_body_size&nbsp;&nbsp;&nbsp; 10m;<br />
client_body_buffer_size 128k;<br />
proxy_connect_timeout&nbsp;&nbsp; 300;<br />
proxy_send_timeout&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 300;<br />
proxy_read_timeout&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 300;<br />
proxy_buffer_size&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4k;<br />
proxy_buffers&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4 32k;<br />
proxy_busy_buffers_size 64k;<br />
proxy_temp_file_write_size 64k;</p>
<img src ="http://www.blogjava.net/freeman1984/aggbug/344398.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2011-02-15 23:08 <a href="http://www.blogjava.net/freeman1984/archive/2011/02/15/344398.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Tomcat中限制ip访问</title><link>http://www.blogjava.net/freeman1984/archive/2011/02/15/344326.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Tue, 15 Feb 2011 03:07:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2011/02/15/344326.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/344326.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2011/02/15/344326.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/344326.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/344326.html</trackback:ping><description><![CDATA[<div>Original URL: <a title="Tomcat中限制ip访问" href="http://www.miotour.com/2010/04/27/tomcat%e4%b8%ad%e9%99%90%e5%88%b6ip%e8%ae%bf%e9%97%ae/">http://www.miotour.com/2010/04/27/tomcat%e4%b8%ad%e9%99%90%e5%88%b6ip%e8%ae%bf%e9%97%ae/</a></div>
<div>Tomcat中限制ip访问是非常简单的，只需要编辑server.xml文件即可</div>
<br />
<div>vi server.xml</div>
<br />
<div>找到context区域，如</div>
<br />
<div>&lt;context path=&#8221;/joseph&#8221;&nbsp;<wbr> reloadable=&#8221;true&#8221; docBase=&#8221;/var/www/joseph&#8221;&gt;</div>
<br />
<div>&lt;value className=&#8221;org.apache.catalina.values.RemoteAddrValue&#8221; allow=&#8221;&#8221; deny=&#8221;127.0.0.1&#8243; /&gt;</div>
<br />
<div>&lt;/context&gt;</div>
<br />
<div>说明：只限制127.0.0.1访问</div>
<br />
<div>如要限制192.168.1.0-192.168.5.255和192.168.10.0-192.168.15.255</div>
<br />
<div>deny=&#8221;192.168.[1-5].*,192.168.[10-15].*&#8221;</div>
<img src ="http://www.blogjava.net/freeman1984/aggbug/344326.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2011-02-15 11:07 <a href="http://www.blogjava.net/freeman1984/archive/2011/02/15/344326.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>jkmount不转发部分</title><link>http://www.blogjava.net/freeman1984/archive/2011/02/15/344325.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Tue, 15 Feb 2011 02:53:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2011/02/15/344325.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/344325.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2011/02/15/344325.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/344325.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/344325.html</trackback:ping><description><![CDATA[<div>Original URL: <a title="jkmount不转发部分请求" href="http://www.miotour.com/2009/11/30/jkmount%e4%b8%8d%e8%bd%ac%e5%8f%91%e9%83%a8%e5%88%86%e8%af%b7%e6%b1%82/">http://www.miotour.com/2009/11/30/jkmount%e4%b8%8d%e8%bd%ac%e5%8f%91%e9%83%a8%e5%88%86%e8%af%b7%e6%b1%82/</a></div>
<p style="padding-bottom: 5px; line-height: 1.5; margin: 0px; padding-left: 0px; padding-right: 0px; font-family: 宋体; color: #114246; font-size: 14px; padding-top: 5px">第一种情形：部分静态页面需要apache处理，不转发给后端的tomcat<br />
</p>
<p style="padding-bottom: 5px; line-height: 1.5; margin: 0px; padding-left: 0px; padding-right: 0px; font-family: 宋体; color: #114246; font-size: 14px; padding-top: 5px"><span style="color: #ff0000">JkMount &nbsp;<wbr>/* &nbsp;<wbr> &nbsp;<wbr>router&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>###默认将所有请求转发给tomcat处理<br />
</span><span style="color: #ff0000">JKUnmount</span> <span style="color: #ff0000">/*.php &nbsp;<wbr> router&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>###php请求不交给tomcat处理<br />
JKUnmount /*.htm &nbsp;<wbr> router&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>###htm请求不交给tomcat处理<br />
JKUnmount /*.html &nbsp;<wbr>router</span> <span style="color: #ff0000">###html请求不交给tomcat处理</span><br />
</p>
<p style="padding-bottom: 5px; line-height: 1.5; margin: 0px; padding-left: 0px; padding-right: 0px; font-size: 14px; padding-top: 5px"><span style="color: #ff0000">JKUnmount &nbsp;<wbr> &nbsp;<wbr> /css/* &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> router&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>###css请求不交给tomcat处理<br />
JKUnmount &nbsp;<wbr> &nbsp;<wbr> /js/* &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> router&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr> ###js请求不交给tomcat处理</span><br />
</p>
<p style="padding-bottom: 5px; line-height: 1.5; margin: 0px; padding-left: 0px; padding-right: 0px; font-family: 宋体; color: #114246; font-size: 14px; padding-top: 5px"><span style="color: #ff0000">JKUnmount &nbsp;<wbr>/image/* &nbsp;<wbr> router&nbsp;<wbr>&nbsp;<wbr> &nbsp;<wbr>###image请求不交给tomcat</span><span style="color: #ff0000">处理</span><br />
</p>
<p style="padding-bottom: 5px; line-height: 1.5; margin: 0px; padding-left: 0px; padding-right: 0px; font-family: 宋体; color: #114246; font-size: 14px; padding-top: 5px">&nbsp;<wbr></p>
<p style="padding-bottom: 5px; line-height: 1.5; margin: 0px; padding-left: 0px; padding-right: 0px; font-family: 宋体; color: #114246; font-size: 14px; padding-top: 5px"><span style="color: #ff0000">第二种情形：将所有请求转发到后端tomcat之后，将不同路径定位给不同的tomcat</span><br />
</p>
<p style="padding-bottom: 5px; line-height: 1.5; margin: 0px; padding-left: 0px; padding-right: 0px; font-family: 宋体; color: #114246; font-size: 14px; padding-top: 5px"><span style="color: #ff0000">JkMount /* &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> router</span><br />
</p>
<p style="padding-bottom: 5px; line-height: 1.5; margin: 0px; padding-left: 0px; padding-right: 0px; font-family: 宋体; color: #114246; font-size: 14px; padding-top: 5px"><span style="color: #ff0000">JkMount /login/* &nbsp;<wbr> &nbsp;<wbr> tomcat1</span><br />
</p>
<p style="padding-bottom: 5px; line-height: 1.5; margin: 0px; padding-left: 0px; padding-right: 0px; font-family: 宋体; color: #114246; font-size: 14px; padding-top: 5px"><span style="color: #ff0000">JkMount /shop/* &nbsp;<wbr> &nbsp;<wbr> tomcat2</span><br />
</p>
<p style="padding-bottom: 5px; line-height: 1.5; margin: 0px; padding-left: 0px; padding-right: 0px; font-family: 宋体; color: #114246; font-size: 14px; padding-top: 5px"><span style="color: #ff0000">JkMount /buy/* &nbsp;<wbr> &nbsp;<wbr> &nbsp;<wbr> tomcat3</span><br />
</p>
<p style="padding-bottom: 5px; line-height: 1.5; margin: 0px; padding-left: 0px; padding-right: 0px; font-family: 宋体; color: #114246; font-size: 14px; padding-top: 5px">&nbsp;<wbr></p>
<p style="padding-bottom: 5px; line-height: 1.5; margin: 0px; padding-left: 0px; padding-right: 0px; font-family: 宋体; color: #114246; font-size: 14px; padding-top: 5px"><span style="color: #ff0000">注意，这种情形下，必须要有这样的处理：</span><br />
</p>
<p style="padding-bottom: 5px; line-height: 1.5; margin: 0px; padding-left: 0px; padding-right: 0px; font-family: 宋体; color: #114246; font-size: 14px; padding-top: 5px"><span style="color: #ff0000">worker.list=router,jkstatus,tomcat1,tomcat2,tomcat3</span><br />
</p>
<p style="padding-bottom: 5px; line-height: 1.5; margin: 0px; padding-left: 0px; padding-right: 0px; font-family: 宋体; color: #114246; font-size: 14px; padding-top: 5px"><span style="color: #ff0000">如果是第一种情形，tomcat1,tomcat2,tomcat3是不需要写在上面这个地方的</span><br />
</p>
<p style="padding-bottom: 5px; line-height: 1.5; margin: 0px; padding-left: 0px; padding-right: 0px; font-family: 宋体; color: #114246; font-size: 14px; padding-top: 5px"><span style="color: #ff0000">而是写在下面：</span><br />
</p>
<p style="padding-bottom: 5px; line-height: 1.5; margin: 0px; padding-left: 0px; padding-right: 0px; font-family: 宋体; color: #114246; font-size: 14px; padding-top: 5px"><span style="color: #ff0000">worker.router.balance_workers=tomcat1,tomcat2,tomcat3</span><br />
</p>
<p style="padding-bottom: 5px; line-height: 1.5; margin: 0px; padding-left: 0px; padding-right: 0px; font-family: 宋体; color: #114246; font-size: 14px; padding-top: 5px">实际使用中，应该是上述两种情形相结合使用的较多，将静态内容交给apache处理，然后将动态内容分布到不同的服务器上。<br />
</p>
<p style="padding-bottom: 5px; line-height: 1.5; margin: 0px; padding-left: 0px; padding-right: 0px; font-family: 宋体; color: #114246; font-size: 14px; padding-top: 5px"></p>
<p style="padding-bottom: 5px; line-height: 1.5; margin: 0px; padding-left: 0px; padding-right: 0px; font-family: 宋体; color: #114246; font-size: 14px; padding-top: 5px">&nbsp;</p>
<p style="padding-bottom: 5px; line-height: 1.5; margin: 0px; padding-left: 0px; padding-right: 0px; font-family: 宋体; color: #114246; font-size: 14px; padding-top: 5px"><wbr></p>
<p style="padding-bottom: 5px; line-height: 1.5; margin: 0px; padding-left: 0px; padding-right: 0px; font-family: 宋体; color: #114246; font-size: 14px; padding-top: 5px">&nbsp;<wbr></p>
<p style="padding-bottom: 5px; line-height: 1.5; margin: 0px; padding-left: 0px; padding-right: 0px; font-family: 宋体; color: #114246; font-size: 14px; padding-top: 5px">JkMount把匹配的转发到指定服务器.<br />
JkUnMount把匹配的不转发到指定服务器.<br />
<strong>JkUnMount选项的级别高于JkMount</strong>.<br />
单独有JkMount规则有效,但<strong>单独有JkUnMount无效</strong>,JkUnMount与JkMount要成对出现.<br />
</p>
<img src ="http://www.blogjava.net/freeman1984/aggbug/344325.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2011-02-15 10:53 <a href="http://www.blogjava.net/freeman1984/archive/2011/02/15/344325.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>apache 集群tomcat配置参数说明</title><link>http://www.blogjava.net/freeman1984/archive/2011/02/15/344322.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Tue, 15 Feb 2011 02:37:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2011/02/15/344322.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/344322.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2011/02/15/344322.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/344322.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/344322.html</trackback:ping><description><![CDATA[<p style="text-indent: 2em">Tomcat 集群配置<br />
打开Server.xml，shutdown, ajp, http这三个端口就不多说了，解开下面注释<br />
&lt;Engine name="Catalina" defaultHost="localhost" jvmRoute="jvm1"&gt; <br />
jvmRoute的值要根据apache的配置，不能冲突。<br />
接着是最重要的一点，tomcat默认集群配置（&lt;Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/&gt;）时，配置的细节实际上被省略了，对于大多数应用而言，使用默认配置已经足够，完整的默认配置应该是这样： </p>
<p style="text-indent: 2em">Xml代码 [url=http://tyler-zhou.javaeye.com/blog/507158]</a></p>
<br />
&lt;!--同步异步模式由channelSendOptions参数控制，默认值是8，为异步模式，4是同步模式。在异步模式下，可以通过加上拷贝确认（Acknowledge）来提高可靠性，此时channelSendOptions设为10。--&gt;&nbsp;&nbsp; <br />
&lt;Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"&nbsp;&nbsp;channelSendOptions="6"&gt;&nbsp;&nbsp; <br />
&lt;!---session 拷贝方式 BackupManager 只拷贝部署当前应用的服务器，DeltaManager 拷贝方式all to all--&gt;&nbsp;&nbsp; <br />
&nbsp; &nbsp; &lt;Manager className="org.apache.catalina.ha.session.BackupManager"&nbsp;&nbsp; <br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;expireSessionsOnShutdown="false"&nbsp;&nbsp; <br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;notifyListenersOnReplication="true"&nbsp;&nbsp; <br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;mapSendOptions="6"/&gt;&nbsp;&nbsp; <br />
&nbsp; &nbsp; &lt;!--&nbsp; &nbsp; <br />
&nbsp; &nbsp; &lt;Manager className="org.apache.catalina.ha.session.DeltaManager"&nbsp;&nbsp; <br />
&nbsp; &nbsp; expireSessionsOnShutdown="false"&nbsp;&nbsp; <br />
&nbsp; &nbsp; notifyListenersOnReplication="true"/&gt;&nbsp;&nbsp; <br />
&nbsp; &nbsp; --&gt;&nbsp;&nbsp; <br />
&nbsp; &nbsp; &lt;!--Channel负责对tomcat集群的IO层进行配置--&gt;&nbsp;&nbsp; <br />
&nbsp; &nbsp; &lt;Channel className="org.apache.catalina.tribes.group.GroupChannel"&gt;&nbsp;&nbsp; <br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&lt;!--Membership用于发现集群中的其他节点，这里的address用的是组播地址（Multicast address，了解更多组播地址详情请参见http://zyycaesar.javaeye.com/admin/blogs/296501），使用同一个组播地址和端口的多个节点同属一个子集群，因此通过自定义组播地址和端口就可将一个大的tomcat集群分成多个子集群--&gt;&nbsp;&nbsp; <br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&lt;Membership className="org.apache.catalina.tribes.membership.McastService"&nbsp;&nbsp; <br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;address="228.0.0.4"&nbsp;&nbsp; <br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;port="45564"&nbsp;&nbsp; <br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;frequency="500"&nbsp;&nbsp; <br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;dropTime="3000"/&gt;&nbsp;&nbsp; <br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&lt;!--Receiver用于各个节点接收其他节点发送的数据，在默认配置下tomcat会从4000-4100间依次选取一个可用的端口进行接收，自定义配置时，如果多个tomcat节点在一台物理服务器上注意要使用不同的端口--&gt;&nbsp;&nbsp; <br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&lt;Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver"&nbsp;&nbsp; <br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;address="auto"&nbsp;&nbsp; <br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;port="5001"&nbsp;&nbsp; <br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;selectorTimeout="100"&nbsp;&nbsp; <br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;maxThreads="6"/&gt;&nbsp;&nbsp; <br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&lt;!--Sender用于向其他节点发送数据，具体实现通过Transport配置，PooledParallelSender是从tcp连接池中获取连接，可以实现并行发送，即集群中的多个节点可以同时向其他所有节点发送数据而互不影响--&gt;&nbsp;&nbsp; <br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&lt;Sender className="org.apache.catalina.tribes.transport.ReplicationTransmitter"&gt;&nbsp;&nbsp; <br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&lt;Transport className="org.apache.catalina.tribes.transport.nio.PooledParallelSender"/&gt;&nbsp;&nbsp; <br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&lt;/Sender&gt;&nbsp;&nbsp; <br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&lt;!---Interceptor有点类似下面将要解释的Valve，起到一个阀门的作用，在数据到达目的节点前进行检测或其他操作，如TcpFailureDetector用于检测在数据的传输过程中是否发生了tcp错误。---&gt;&nbsp;&nbsp; <br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&lt;Interceptor className="org.apache.catalina.tribes.group.interceptors.TcpFailureDetector"/&gt;&nbsp;&nbsp; <br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&lt;Interceptor className="org.apache.catalina.tribes.group.interceptors.MessageDispatch15Interceptor"/&gt;&nbsp;&nbsp; <br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&lt;Interceptor className="org.apache.catalina.tribes.group.interceptors.ThroughputInterceptor"/&gt;&nbsp;&nbsp; <br />
&nbsp;&nbsp; <br />
&nbsp; &nbsp; &lt;/Channel&gt;&nbsp;&nbsp; <br />
&nbsp; &nbsp; &lt;!--Valve用于在节点向客户端响应前进行检测或进行某些操作，ReplicationValve就是用于用于检测当前的响应是否涉及Session数据的更新，如果是则启动Session拷贝操作，filter用于过滤请求，如客户端对图片，css，js的请求就不会涉及Session，因此不需检测，默认状态下不进行过滤，监测所有的响应.JvmRouteBinderValve会在前端的Apache mod_jk发生错误时保证同一客户端的请求发送到集群的同一个节点--&gt;&nbsp;&nbsp; <br />
&nbsp; &nbsp; &lt;Valve className="org.apache.catalina.ha.tcp.ReplicationValve"&nbsp;&nbsp; <br />
&nbsp; &nbsp; filter=".*\.gif;.*\.js;.*\.jpg;.*\.png;.*\.htm;.*\.html;.*\.css;.*\.txt;"/&gt;&nbsp;&nbsp; <br />
&nbsp; &nbsp; &lt;!--Deployer用于集群的farm功能，监控应用中文件的更新，以保证集群中所有节点应用的一致性，如某个用户上传文件到集群中某个节点的应用程序目录下，Deployer会监测到这一操作并把这一文件拷贝到集群中其他节点相同应用的对应目录下以保持所有应用的一致。这是一个相当强大的功能，不过很遗憾，tomcat集群目前并不能做到这一点，开发人员正在努力实现它，这里的配置只是预留了一个接口--&gt;&nbsp;&nbsp; <br />
&nbsp; &nbsp; &lt;Deployer className="org.apache.catalina.ha.deploy.FarmWarDeployer"&nbsp;&nbsp; <br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;tempDir="/tmp/war-temp/"&nbsp;&nbsp; <br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;deployDir="/tmp/war-deploy/"&nbsp;&nbsp; <br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;watchDir="/tmp/war-listen/"&nbsp;&nbsp; <br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;watchEnabled="false"/&gt;&nbsp;&nbsp; <br />
&nbsp;&nbsp; <br />
&nbsp; &nbsp; &lt;!--Listener用于跟踪集群中节点发出和收到的数据，也有点类似Valve的功能。--&gt;&nbsp;&nbsp; <br />
&nbsp; &nbsp; &lt;ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener"/&gt;&nbsp;&nbsp; <br />
&nbsp;&nbsp; <br />
&lt;/Cluster&gt;&nbsp;&nbsp;<br />
最后在Web.xml里面加上&lt;distributable/&gt;，官方文档没有这个，但我觉得还是应该加上，因为按照标准的tomcat启动，当Host对象被创建时，一个Cluster对象（默认配置下是SimpleTcpCluster）也同时被关联到这个Host对象。当某个应用在web.xml中设置了distributable时，Tomcat将为此应用的上下文环境创建一个DeltaManager。SimpleTcpCluster启动membership服务和Replication服务。<br />
<br />
---<br />
<p>extra/httpd-mpm.conf 模块 &nbsp;</p>
<p>上边一样的就不贴了，主要是下边的配置，因为我用了<span style="font-family: Arial, 宋体, sans-serif; -webkit-border-horizontal-spacing: 1px; -webkit-border-vertical-spacing: 1px">mod_security</span>模块，所以要做一些配置，这里不做解释了，写的很详细，我比较喜欢在配置文件里把容易忘记的地方写上文档。毕竟这东西配完了就不再动了，很容易忘记</p>
<p># WinNT MPM</p>
<p># ThreadsPerChild: constant number of worker threads in the server process</p>
<p># MaxRequestsPerChild: maximum &nbsp;number of requests a server process serves</p>
<p>#注意：ThreadLimit指令应当放在ThreadsPerChild之前，否则ThreadsPerChild指令生效后ThreadLimit会失效，而导致不必要的错误 ThreadLimit必须大于等于ThreadsPerChild</p>
<p>#对于mpm_winnt，ThreadLimit的默认值是1920；对于其他MPM这个值是64</p>
<p>#ThreadLimit 这个指令设置了每个子进程可配置的线程数ThreadsPerChild上限。任何在重启期间对这个指令的改变都将被忽略，但对ThreadsPerChild的修改却会生效。</p>
<p>#ThreadLimit 使用这个指令时要特别当心。如果将ThreadLimit设置成一个高出ThreadsPerChild实际需要很多的值，将会有过多的共享内存被分配。</p>
<p>#如果将ThreadLimit和ThreadsPerChild设置成超过系统的处理能力，Apache可能无法启动，或者系统将变得不稳定。该指令的值应当和ThreadsPerChild大致保持一致</p>
<p>#ThreadsPerChild 每个子进程建立的常驻的执行线程数。默认值是25。子进程在启动时建立这些线程后就不再建立新的线程了。</p>
<p>&lt;IfModule mpm_winnt_module&gt;</p>
<p>&nbsp;&nbsp; &nbsp;ThreadLimit &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;2000</p>
<p>&nbsp;&nbsp; &nbsp;ThreadsPerChild &nbsp; &nbsp; &nbsp; &nbsp;2000</p>
<p>&nbsp;&nbsp; &nbsp;MaxRequestsPerChild &nbsp; &nbsp;2000</p>
<p>&lt;/IfModule&gt;</p>
<img src ="http://www.blogjava.net/freeman1984/aggbug/344322.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2011-02-15 10:37 <a href="http://www.blogjava.net/freeman1984/archive/2011/02/15/344322.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>提高AJAX客户端响应速度(转载)</title><link>http://www.blogjava.net/freeman1984/archive/2011/02/11/344056.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Fri, 11 Feb 2011 07:23:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2011/02/11/344056.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/344056.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2011/02/11/344056.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/344056.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/344056.html</trackback:ping><description><![CDATA[&nbsp;
<h1 style="text-align: left" align="left"><span style="font-family: 宋体">提高</span><span style="font-family: 'Verdana', 'sans-serif'">AJAX</span><span style="font-family: 宋体">客户端响应速度</span></h1>
<p>(<span style="font-family: 宋体">文：包一磊</span>)</p>
<p style="text-align: left; margin: 15.6pt 0cm" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'">AJAX</span><span style="font-family: 宋体">的出现极大的改变了</span><span style="font-family: 'Verdana', 'sans-serif'">Web</span><span style="font-family: 宋体">应用客户端的操作模式，它使的用户可以在全心工作时不必频繁的忍受那令人厌恶的页面刷新。理论上</span><span style="font-family: 'Verdana', 'sans-serif'">AJAX</span><span style="font-family: 宋体">技术在很大的程度上可以减少用户操作的等待时间，同时节约网络上的数据流量。而然，实际情况却并不总是这样。用户时常会抱怨用了</span><span style="font-family: 'Verdana', 'sans-serif'">AJAX</span><span style="font-family: 宋体">的系统响应速度反而降低了。</span></p>
<p style="text-align: left; margin: 15.6pt 0cm" class="MsoNormal" align="left"><span style="font-family: 宋体">笔者从事</span><span style="font-family: 'Verdana', 'sans-serif'">AJAX</span><span style="font-family: 宋体">方面的研发多年，参与开发了目前国内较为成熟的</span><span style="font-family: 'Verdana', 'sans-serif'">AJAX</span><span style="font-family: 宋体">平台</span><span style="font-family: 'Verdana', 'sans-serif'">-dorado</span><span style="font-family: 宋体">。根据笔者的经验，导致这种结果的根本原因并不在</span><span style="font-family: 'Verdana', 'sans-serif'">AJAX</span><span style="font-family: 宋体">。很多时候系统响应速度的降低都是由不够合理的界面设计和不够高效的编程习惯造成的。下面我们就来分析几个</span><span style="font-family: 'Verdana', 'sans-serif'">AJAX</span><span style="font-family: 宋体">开发过程中需要时刻注意的环节。</span></p>
<p style="text-align: left; text-indent: -21pt; margin: 7.8pt 0cm 7.8pt 42pt; tab-stops: list 42.0pt" class="MsoNormal" align="left"><span style="font-family: Wingdings">n&nbsp;</span><span style="font-family: 宋体">合理的使用客户端编程和远程过程调用。</span></p>
<p style="text-align: left; margin: 7.8pt 0cm 7.8pt 42pt" class="MsoNormal" align="left"><span style="font-family: 宋体">客户端的编程主要都是基于</span><span style="font-family: 'Verdana', 'sans-serif'">JavaScript</span><span style="font-family: 宋体">的。而</span><span style="font-family: 'Verdana', 'sans-serif'">JavaScript</span><span style="font-family: 宋体">是一种解释型的编程语言，它的运行效率相对于</span><span style="font-family: 'Verdana', 'sans-serif'">Java</span><span style="font-family: 宋体">等都要稍逊一筹。同时</span><span style="font-family: 'Verdana', 'sans-serif'">JavaScript</span><span style="font-family: 宋体">又是运行在浏览器这样一个严格受限的环境当中。因此开发人员对于哪些逻辑可以在客户端执行应该有一个清醒的认识。</span></p>
<p style="text-align: left; margin: 7.8pt 0cm 7.8pt 42pt" class="MsoNormal" align="left"><span style="font-family: 宋体">在实际的应用中究竟应该怎样使用</span><span style="font-family: 宋体">客户端编程，这依赖于开发人员的经验判断。这里很多问题是只可意会的。由于篇幅有限，在这里我们大致归纳出下面这几个注意事项：</span></p>
<p style="text-align: left; text-indent: -21pt; margin: 7.8pt 0cm 7.8pt 63pt; tab-stops: list 63.0pt" class="MsoNormal" align="left"><span style="font-family: Wingdings">u&nbsp;</span><span style="font-family: 宋体">尽可能避免频繁的使用远程过程调用，例如避免在循环体中使用远程过程调用。</span></p>
<p style="text-align: left; text-indent: -21pt; margin: 7.8pt 0cm 7.8pt 63pt; tab-stops: list 63.0pt" class="MsoNormal" align="left"><span style="font-family: Wingdings">u&nbsp;</span><span style="font-family: 宋体">如果可能的话尽可能使用</span><span style="font-family: 'Verdana', 'sans-serif'">AJAX</span><span style="font-family: 宋体">方式的远程过程调用（异步方式的远程过程调用）。</span></p>
<p style="text-align: left; text-indent: -21pt; margin: 7.8pt 0cm 7.8pt 63pt; tab-stops: list 63.0pt" class="MsoNormal" align="left"><span style="font-family: Wingdings">u&nbsp;</span><span style="font-family: 宋体">避免将重量级的数据操作放置在</span><span style="font-family: 宋体">客户端。例如：大批量的数据复制操作、需要通过大量的数据遍历完成的计算等。</span></p>
<p style="text-align: left; text-indent: -21pt; margin: 7.8pt 0cm 7.8pt 42pt; tab-stops: list 42.0pt" class="MsoNormal" align="left"><span style="font-family: Wingdings">n&nbsp;</span><span style="font-family: 宋体">改进对</span><span style="font-family: 'Verdana', 'sans-serif'">DOM</span><span style="font-family: 宋体">对象的操作方式。</span></p>
<p style="text-align: left; margin: 7.8pt 0cm 7.8pt 42pt" class="MsoNormal" align="left"><span style="font-family: 宋体">客户端的编程中，对</span><span style="font-family: 'Verdana', 'sans-serif'">DOM</span><span style="font-family: 宋体">对象的操作往往是最容易占用</span><span style="font-family: 'Verdana', 'sans-serif'">CPU</span><span style="font-family: 宋体">时间的。而对于</span><span style="font-family: 'Verdana', 'sans-serif'">DOM</span><span style="font-family: 宋体">对象的操作，不同的编程方法之间的性能差异又往往是非常大的。</span></p>
<p style="text-align: left; margin: 7.8pt 0cm 7.8pt 42pt" class="MsoNormal" align="left"><span style="font-family: 宋体">以下是三段运行结果完全相同的代码，它们的作用是在网页中创建一个</span><span style="font-family: 'Verdana', 'sans-serif'">10x1000</span><span style="font-family: 宋体">的表格。然而它们的运行速度却有着天壤之别。</span></p>
<table style="border-bottom: medium none; border-left: medium none; border-collapse: collapse; background: #f3f3f3; border-top: medium none; border-right: medium none" class="MsoTableGrid" border="1" cellspacing="0" cellpadding="0">
    <tbody>
        <tr>
            <td style="border-bottom: medium none; border-left: medium none; padding-bottom: 0cm; padding-left: 5.4pt; width: 426.1pt; padding-right: 5.4pt; border-top: medium none; border-right: medium none; padding-top: 0cm" valign="top" width="568">
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">/* </span><span style="font-family: 宋体; font-size: 9pt">测试代码</span><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">1 - </span><span style="font-family: 宋体; font-size: 9pt">耗时</span><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">: 41</span><span style="font-family: 宋体; font-size: 9pt">秒</span><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">*/</span></p>
            </td>
        </tr>
        <tr>
            <td style="border-bottom: medium none; border-left: medium none; padding-bottom: 0cm; padding-left: 5.4pt; width: 426.1pt; padding-right: 5.4pt; border-top: medium none; border-right: medium none; padding-top: 0cm" valign="top" width="568">
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">var table = document.createElement("TABLE");</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">document.body.appendChild(table);</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">for(var i = 0; i &lt; 1000; i++){</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;var row = table.insertRow(-1);</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;for(var j = 0; j &lt; 10; j++){</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp; var cell = objRow.insertCell(-1);</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp; cell.innerText = "( " + i + " , " + j + " )";</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;}</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">}</span></p>
            </td>
        </tr>
    </tbody>
</table>
<table style="border-bottom: medium none; border-left: medium none; border-collapse: collapse; background: #f3f3f3; border-top: medium none; border-right: medium none" class="MsoTableGrid" border="1" cellspacing="0" cellpadding="0">
    <tbody>
        <tr>
            <td style="border-bottom: medium none; border-left: medium none; padding-bottom: 0cm; padding-left: 5.4pt; width: 426.1pt; padding-right: 5.4pt; border-top: medium none; border-right: medium none; padding-top: 0cm" valign="top" width="568">
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">/* </span><span style="font-family: 宋体; font-size: 9pt">测试代码</span><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">2 - </span><span style="font-family: 宋体; font-size: 9pt">耗时</span><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">: 7.6</span><span style="font-family: 宋体; font-size: 9pt">秒</span><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt"> */</span></p>
            </td>
        </tr>
        <tr>
            <td style="border-bottom: medium none; border-left: medium none; padding-bottom: 0cm; padding-left: 5.4pt; width: 426.1pt; padding-right: 5.4pt; border-top: medium none; border-right: medium none; padding-top: 0cm" valign="top" width="568">
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">var table = document.getElementById("TABLE");</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">document.body.appendChild(table);</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">var tbody = document.createElement("TBODY");</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">table.appendChild(tbody);</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">for(var i = 0; i &lt; 1000; i++){</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;var row = document.createElement("TR");</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;tbody.appendChild(row);</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;for(var j = 0; j &lt; 10; j++){</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp; var cell = document.createElement("TD");</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp; row.appendChild(cell);</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp; cell.innerText = "( " + i + " , " + j + " )";</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;}</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">}</span></p>
            </td>
        </tr>
    </tbody>
</table>
<table style="border-bottom: medium none; border-left: medium none; border-collapse: collapse; background: #f3f3f3; border-top: medium none; border-right: medium none" class="MsoTableGrid" border="1" cellspacing="0" cellpadding="0">
    <tbody>
        <tr>
            <td style="border-bottom: medium none; border-left: medium none; padding-bottom: 0cm; padding-left: 5.4pt; width: 426.1pt; padding-right: 5.4pt; border-top: medium none; border-right: medium none; padding-top: 0cm" valign="top" width="568">
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">/* </span><span style="font-family: 宋体; font-size: 9pt">测试代码</span><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">3 - </span><span style="font-family: 宋体; font-size: 9pt">耗时</span><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">: 1.26</span><span style="font-family: 宋体; font-size: 9pt">秒</span><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt"> */</span></p>
            </td>
        </tr>
        <tr>
            <td style="border-bottom: medium none; border-left: medium none; padding-bottom: 0cm; padding-left: 5.4pt; width: 426.1pt; padding-right: 5.4pt; border-top: medium none; border-right: medium none; padding-top: 0cm" valign="top" width="568">
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">var tbody = document.createElement("TBODY");</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">for(var i = 0; i &lt; 1000; i++){&nbsp;&nbsp; </span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;var row = document.createElement("TR");</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for(var j = 0; j &lt; 10; j++){</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp; var cell = document.createElement("TD");</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp; cell.innerText = "( " + i + " , " + j + " )";</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp; row.appendChild(cell);</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;}</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;tbody.appendChild(row);</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">}</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">var table = document.getElementById("TABLE");</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">table.appendChild(tbody); </span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">document.body.appendChild(table);</span></p>
            </td>
        </tr>
    </tbody>
</table>
<p style="text-align: left; margin: 7.8pt 0cm 7.8pt 42pt" class="MsoNormal" align="left"><span style="font-family: 宋体">这里的&#8220;测试代码</span><span style="font-family: 'Verdana', 'sans-serif'">1</span><span style="font-family: 宋体">&#8221;和&#8220;测试代码</span><span style="font-family: 'Verdana', 'sans-serif'">2</span><span style="font-family: 宋体">&#8221;之间的差别在于在创建表格单元时使用了不同的</span><span style="font-family: 'Verdana', 'sans-serif'">API</span><span style="font-family: 宋体">方法。而&#8220;测试代码</span><span style="font-family: 'Verdana', 'sans-serif'">2</span><span style="font-family: 宋体">&#8221;和&#8220;测试代码</span><span style="font-family: 'Verdana', 'sans-serif'">3</span><span style="font-family: 宋体">&#8221;</span><span style="font-family: 宋体">之间的差别在于处理顺序的略微不同。</span></p>
<p style="text-align: left; margin: 7.8pt 0cm 7.8pt 42pt" class="MsoNormal" align="left"><span style="font-family: 宋体">&#8220;测试代码</span><span style="font-family: 'Verdana', 'sans-serif'">1</span><span style="font-family: 宋体">&#8221;和&#8220;测试代码</span><span style="font-family: 'Verdana', 'sans-serif'">2</span><span style="font-family: 宋体">&#8221;之间如此大的性能差别我们无从分析，目前所知的是</span><span style="font-family: 'Verdana', 'sans-serif'">insertRow</span><span style="font-family: 宋体">和</span><span style="font-family: 'Verdana', 'sans-serif'">insertCell</span><span style="font-family: 宋体">是</span><span style="font-family: 'Verdana', 'sans-serif'">DHTML</span><span style="font-family: 宋体">中表格特有的</span><span style="font-family: 'Verdana', 'sans-serif'">API</span><span style="font-family: 宋体">，</span><span style="font-family: 'Verdana', 'sans-serif'">createElement</span><span style="font-family: 宋体">和</span><span style="font-family: 'Verdana', 'sans-serif'">appendChild</span><span style="font-family: 宋体">是</span><span style="font-family: 'Verdana', 'sans-serif'">W3C DOM</span><span style="font-family: 宋体">的原生</span><span style="font-family: 'Verdana', 'sans-serif'">API</span><span style="font-family: 宋体">。而前者应该是对后者的封装。不过，我们并不能因此而得出结论认为</span><span style="font-family: 'Verdana', 'sans-serif'">DOM</span><span style="font-family: 宋体">的原生</span><span style="font-family: 'Verdana', 'sans-serif'">API</span><span style="font-family: 宋体">总是优于对象特有的</span><span style="font-family: 'Verdana', 'sans-serif'">API</span><span style="font-family: 宋体">。建议大家在需要频繁调用某一</span><span style="font-family: 'Verdana', 'sans-serif'">API</span><span style="font-family: 宋体">时，对其性能表现做一些基本的测试。</span></p>
<p style="text-align: left; margin: 7.8pt 0cm 7.8pt 42pt" class="MsoNormal" align="left"><span style="font-family: 宋体">&#8220;测试代码</span><span style="font-family: 'Verdana', 'sans-serif'">2</span><span style="font-family: 宋体">&#8221;和&#8220;测试代码</span><span style="font-family: 'Verdana', 'sans-serif'">3</span><span style="font-family: 宋体">&#8221;之间的性能差异主要来自于他们的构建顺序不同。&#8220;测试代码</span><span style="font-family: 'Verdana', 'sans-serif'">2</span><span style="font-family: 宋体">&#8221;的做法是首先创建最外层的</span><span style="font-family: 'Verdana', 'sans-serif'">&lt;TABLE&gt;</span><span style="font-family: 宋体">对象，然后再在循环中依次创建</span><span style="font-family: 'Verdana', 'sans-serif'">&lt;TR&gt;</span><span style="font-family: 宋体">和</span><span style="font-family: 'Verdana', 'sans-serif'">&lt;TD&gt;</span><span style="font-family: 宋体">。而&#8220;测试代码</span><span style="font-family: 'Verdana', 'sans-serif'">3</span><span style="font-family: 宋体">&#8221;的做法是首先在内存中由内到外的构建好整个表格，最后再将它添加到网页中。这样做的目的是尽可能的减少浏览器重新计算页面布局的次数。每当我们将一个对象添加到网页中时，浏览器都会尝试对页面中的控件的布局进行重新计算。所以，<span style="color: blue">如果我们能够首先在内存中将整个要构造的对象全部创建好，然后再一次性的添加到网页中。那么，浏览器将只会做一次布局的重计算</span>。总结为一句话那就是越晚执行</span><span style="font-family: 'Verdana', 'sans-serif'">appendChild</span><span style="font-family: 宋体">越好。有时为了提高运行效率，我们甚至可以考虑先使用</span><span style="font-family: 'Verdana', 'sans-serif'">removeChild</span><span style="font-family: 宋体">将已存在的控件从页面中移除，然后构造完成后再重新将其放置回页面当中。</span></p>
<p style="text-align: left; text-indent: -21pt; margin: 7.8pt 0cm 7.8pt 42pt; tab-stops: list 42.0pt" class="MsoNormal" align="left"><span style="font-family: Wingdings">n&nbsp;</span><span style="font-family: 宋体">提高字符串累加的速度</span></p>
<p style="text-align: left; margin: 7.8pt 0cm 7.8pt 42pt" class="MsoNormal" align="left"><span style="font-family: 宋体">在使用</span><span style="font-family: 'Verdana', 'sans-serif'">AJAX</span><span style="font-family: 宋体">提交信息时，我可能常常需要拼装一些比较大的字符串通过</span><span style="font-family: 'Verdana', 'sans-serif'">XmlHttp</span><span style="font-family: 宋体">来完成</span><span style="font-family: 'Verdana', 'sans-serif'">POST</span><span style="font-family: 宋体">提交。尽管提交这样大的信息的做法看起来并不优雅，但有时我们可能不得不面对这样的需求。那么</span><span style="font-family: 'Verdana', 'sans-serif'">JavaScript</span><span style="font-family: 宋体">中对字符串的累加速度如何呢？我们先来做下面的这个实验。累加一个长度为</span><span style="font-family: 'Verdana', 'sans-serif'">30000</span><span style="font-family: 宋体">的字符串。</span></p>
<table style="border-bottom: medium none; border-left: medium none; border-collapse: collapse; background: #f3f3f3; border-top: medium none; border-right: medium none" class="MsoTableGrid" border="1" cellspacing="0" cellpadding="0">
    <tbody>
        <tr>
            <td style="border-bottom: medium none; border-left: medium none; padding-bottom: 0cm; padding-left: 5.4pt; width: 426.1pt; padding-right: 5.4pt; border-top: medium none; border-right: medium none; padding-top: 0cm" valign="top" width="568">
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">/* </span><span style="font-family: 宋体; font-size: 9pt">测试代码</span><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">1 - </span><span style="font-family: 宋体; font-size: 9pt">耗时</span><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">: 14.325</span><span style="font-family: 宋体; font-size: 9pt">秒</span><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt"> */</span></p>
            </td>
        </tr>
        <tr>
            <td style="border-bottom: medium none; border-left: medium none; padding-bottom: 0cm; padding-left: 5.4pt; width: 426.1pt; padding-right: 5.4pt; border-top: medium none; border-right: medium none; padding-top: 0cm" valign="top" width="568">
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">var str = "";</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">for (var i = 0; i &lt; 50000; i++) {</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; str += "xxxxxx";</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">}</span></p>
            </td>
        </tr>
    </tbody>
</table>
<p style="text-align: left; margin: 7.8pt 0cm 7.8pt 42pt" class="MsoNormal" align="left"><span style="font-family: 宋体">这段代码耗时</span><span style="font-family: 'Verdana', 'sans-serif'">14.325</span><span style="font-family: 宋体">秒，结果并不理想。现在我们将代码改为如下的形式：</span></p>
<table style="border-bottom: medium none; border-left: medium none; border-collapse: collapse; background: #f3f3f3; border-top: medium none; border-right: medium none" class="MsoTableGrid" border="1" cellspacing="0" cellpadding="0">
    <tbody>
        <tr>
            <td style="border-bottom: medium none; border-left: medium none; padding-bottom: 0cm; padding-left: 5.4pt; width: 426.1pt; padding-right: 5.4pt; border-top: medium none; border-right: medium none; padding-top: 0cm" valign="top" width="568">
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">/* </span><span style="font-family: 宋体; font-size: 9pt">测试代码</span><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">2 - </span><span style="font-family: 宋体; font-size: 9pt">耗时</span><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">: 0.359</span><span style="font-family: 宋体; font-size: 9pt">秒</span><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt"> */</span></p>
            </td>
        </tr>
        <tr>
            <td style="border-bottom: medium none; border-left: medium none; padding-bottom: 0cm; padding-left: 5.4pt; width: 426.1pt; padding-right: 5.4pt; border-top: medium none; border-right: medium none; padding-top: 0cm" valign="top" width="568">
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">var str = "";</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">for (var i = 0; i &lt; 100; i++) {</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var sub = "";</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (var j = 0; j &lt; 500; j++) {</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sub += "xxxxxx";</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; str += sub;</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">}</span></p>
            </td>
        </tr>
    </tbody>
</table>
<p style="text-align: left; margin: 7.8pt 0cm 7.8pt 42pt" class="MsoNormal" align="left"><span style="font-family: 宋体">这段代码耗时</span><span style="font-family: 'Verdana', 'sans-serif'">0.359</span><span style="font-family: 宋体">秒！同样的结果，我们做的只是首先拼装一些较小的字符串然后再组装成更大的字符串。这种做法可以有效的在字符串拼装的后期减小内存复制的数据量。知道了这一原理之后我们还可以把上面的代码进一步拆散以后进行测试。下面的代码仅耗时</span><span style="font-family: 'Verdana', 'sans-serif'">0.140</span><span style="font-family: 宋体">秒。</span></p>
<table style="border-bottom: medium none; border-left: medium none; border-collapse: collapse; background: #f3f3f3; border-top: medium none; border-right: medium none" class="MsoTableGrid" border="1" cellspacing="0" cellpadding="0">
    <tbody>
        <tr>
            <td style="border-bottom: medium none; border-left: medium none; padding-bottom: 0cm; padding-left: 5.4pt; width: 426.1pt; padding-right: 5.4pt; border-top: medium none; border-right: medium none; padding-top: 0cm" valign="top" width="568">
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">/* </span><span style="font-family: 宋体; font-size: 9pt">测试代码</span><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">3 - </span><span style="font-family: 宋体; font-size: 9pt">耗时</span><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">: 0.140</span><span style="font-family: 宋体; font-size: 9pt">秒</span><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt"> */</span></p>
            </td>
        </tr>
        <tr>
            <td style="border-bottom: medium none; border-left: medium none; padding-bottom: 0cm; padding-left: 5.4pt; width: 426.1pt; padding-right: 5.4pt; border-top: medium none; border-right: medium none; padding-top: 0cm" valign="top" width="568">
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">var str = "";&nbsp;</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">for (var i1 = 0; i1 &lt; 5; i1++) {</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var str1 = "";</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (var i2 = 0; i2 &lt; 10; i2++) {</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var str2 = "";</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (var i3 = 0; i3 &lt; 10; i3++) {</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var str3 = "";</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (var i4 = 0; i4 &lt; 10; i4++) {</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&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; var str4 = "";</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&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; for (var i5 = 0; i5 &lt; 10; i5++) {</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&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; str4 += "xxxxxx";</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&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; }</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&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; str3 += str4;</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; str2 += str3;</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; str1 += str2;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; str += str1;&nbsp;</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">}</span></p>
            </td>
        </tr>
    </tbody>
</table>
<p style="text-align: left; margin: 7.8pt 0cm 7.8pt 42pt" class="MsoNormal" align="left"><span style="font-family: 宋体">不过，上面这种做法也许并不是最好的！如果我们需要提交的信息是</span><span style="font-family: 'Verdana', 'sans-serif'">XML</span><span style="font-family: 宋体">格式的（其实绝大多数情况下，我们都可以设法将要提交的信息组装成</span><span style="font-family: 'Verdana', 'sans-serif'">XML</span><span style="font-family: 宋体">格式），我们还能找到更高效更优雅的方法</span>—<span style="font-family: 宋体">利用</span><span style="font-family: 'Verdana', 'sans-serif'">DOM</span><span style="font-family: 宋体">对象为我们组装字符串。下面这段代买组装一个长度为</span><span style="font-family: 'Verdana', 'sans-serif'">950015</span><span style="font-family: 宋体">的字符串仅须耗时</span><span style="font-family: 'Verdana', 'sans-serif'">0.890</span><span style="font-family: 宋体">秒。</span></p>
<table style="border-bottom: medium none; border-left: medium none; border-collapse: collapse; background: #f3f3f3; border-top: medium none; border-right: medium none" class="MsoTableGrid" border="1" cellspacing="0" cellpadding="0">
    <tbody>
        <tr>
            <td style="border-bottom: medium none; border-left: medium none; padding-bottom: 0cm; padding-left: 5.4pt; width: 426.1pt; padding-right: 5.4pt; border-top: medium none; border-right: medium none; padding-top: 0cm" valign="top" width="568">
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">/* </span><span style="font-family: 宋体; font-size: 9pt">利用</span><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">DOM</span><span style="font-family: 宋体; font-size: 9pt">对象组装信息</span><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt"> - </span><span style="font-family: 宋体; font-size: 9pt">耗时</span><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">: 0.890</span><span style="font-family: 宋体; font-size: 9pt">秒</span><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt"> */</span></p>
            </td>
        </tr>
        <tr>
            <td style="border-bottom: medium none; border-left: medium none; padding-bottom: 0cm; padding-left: 5.4pt; width: 426.1pt; padding-right: 5.4pt; border-top: medium none; border-right: medium none; padding-top: 0cm" valign="top" width="568">
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">var xmlDoc;&nbsp;</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">if (browserType == BROWSER_IE) {</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; xmlDoc = new ActiveXObject("Msxml.DOMDocument");</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">}</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">else {</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; xmlDoc = document.createElement("DOM");</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">}</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">var root = xmlDoc.createElement("root");</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">for (var i = 0; i &lt; 50000; i++) {</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var node = xmlDoc.createElement("data");</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (browserType == BROWSER_IE) {</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; node.text = "xxxxxx";</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else {</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; node.innerText = "xxxxxx";</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; root.appendChild(node);</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">}</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">xmlDoc.appendChild(root);</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">var str;</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">if (browserType == BROWSER_IE) {</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; str = xmlDoc.xml;</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">}</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">else {</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; str = xmlDoc.innerHTML;</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">}</span></p>
            </td>
        </tr>
    </tbody>
</table>
<p style="text-align: left; text-indent: -21pt; margin: 7.8pt 0cm 7.8pt 42pt; tab-stops: list 42.0pt" class="MsoNormal" align="left"><span style="font-family: Wingdings">n&nbsp;</span><span style="font-family: 宋体">避免</span><span style="font-family: 'Verdana', 'sans-serif'">DOM</span><span style="font-family: 宋体">对象的内存泄漏。</span></p>
<p style="text-align: left; margin: 7.8pt 0cm 7.8pt 42pt" class="MsoNormal" align="left"><span style="font-family: 宋体">关于</span><span style="font-family: 'Verdana', 'sans-serif'">IE</span><span style="font-family: 宋体">中</span><span style="font-family: 'Verdana', 'sans-serif'">DOM</span><span style="font-family: 宋体">对象的内存泄露是一个常常被开发人员忽略的问题。然而它带来的后果却是非常严重的！它会导致</span><span style="font-family: 'Verdana', 'sans-serif'">IE</span><span style="font-family: 宋体">的内存占用量持续上升，并且浏览器的整体运行速度明显下降。对于一些泄露比较严重的网页，甚至只要刷新几次，运行速度就会降低一倍。</span></p>
<p style="text-align: left; margin: 7.8pt 0cm 7.8pt 42pt" class="MsoNormal" align="left"><span style="font-family: 宋体">比较常见的内存泄漏的模型有&#8220;</span><span style="font-family: 'Verdana', 'sans-serif'"><a href="http://birdshome.cnblogs.com/archive/2006/05/28/IE_MemoryLeak.html"><span style="font-family: 宋体; color: windowtext; text-decoration: none; text-underline: none">循环引用</span></a></span><span style="font-family: 宋体">模型&#8221;、&#8220;</span><span style="font-family: 'Verdana', 'sans-serif'"><a href="http://birdshome.cnblogs.com/archive/2006/06/01/ClosureReferences.html"><span style="font-family: 宋体; color: windowtext; text-decoration: none; text-underline: none">闭包函数</span></a></span><span style="font-family: 宋体">模型&#8221;和&#8220;</span><span style="font-family: 'Verdana', 'sans-serif'">DOM</span><span style="font-family: 宋体">插入顺序模型&#8221;</span><span style="font-family: 'Verdana', 'sans-serif'">,</span><span style="font-family: 宋体">对于前两种泄漏模型，我们都可以通过在网页析构时解除引用的方式来避免。而对于&#8220;</span><span style="font-family: 'Verdana', 'sans-serif'">DOM</span><span style="font-family: 宋体">插入顺序模型&#8221;则需要通过改变一些惯有的编程习惯的方式来避免。</span></p>
<p style="text-align: left; margin: 7.8pt 0cm 7.8pt 42pt" class="MsoNormal" align="left"><span style="font-family: 宋体">有关内存泄漏的模型的更多介绍可以通过</span><span style="font-family: 'Verdana', 'sans-serif'">Google</span><span style="font-family: 宋体">很快的查到，本文不做过多的阐述。不过，这里我向您推荐一个可用于查找和分析网页内存泄露的小工具</span>—<span style="font-family: 'Verdana', 'sans-serif'">Drip</span><span style="font-family: 宋体">，目前的较新版本是</span><span style="font-family: 'Verdana', 'sans-serif'">0.5</span><span style="font-family: 宋体">，下载地址是</span><span style="font-family: 'Verdana', 'sans-serif'">http://outofhanwell.com/ieleak/index.php</span></p>
<p style="text-align: left; text-indent: -21pt; margin: 7.8pt 0cm 7.8pt 42pt; tab-stops: list 42.0pt" class="MsoNormal" align="left"><span style="font-family: Wingdings">n&nbsp;</span><span style="font-family: 宋体">复杂页面的分段装载和初始化</span></p>
<p style="text-align: left; margin: 7.8pt 0cm 7.8pt 42pt" class="MsoNormal" align="left"><span style="font-family: 宋体">对系统当中某些确实比较复杂而又不便使用</span><span style="font-family: 'Verdana', 'sans-serif'">IFrame</span><span style="font-family: 宋体">的界面，我们可以对其实施分段装载。例如对于多页标签的界面，我们可以首先下载和初始化多页标签的默认页，然后利用</span><span style="font-family: 'Verdana', 'sans-serif'">AJAH</span><span style="font-family: 宋体">（</span><span style="font-family: 'Verdana', 'sans-serif'">asynchronous JavaScript and HTML</span><span style="font-family: 宋体">）技术来异步的装载其他标签页中的内容。这样就能保证界面可以在第一时间首先展现给用户。把整个复杂界面的装载过程分散到用户的操作过程当中。</span></p>
<p style="text-align: left; text-indent: -21pt; margin: 7.8pt 0cm 7.8pt 42pt; tab-stops: list 42.0pt" class="MsoNormal" align="left"><span style="font-family: Wingdings">n&nbsp;</span><span style="font-family: 宋体">利用</span><span style="font-family: 'Verdana', 'sans-serif'">GZIP</span><span style="font-family: 宋体">压缩网络流量。</span></p>
<p style="text-align: left; margin: 7.8pt 0cm 7.8pt 42pt" class="MsoNormal" align="left"><span style="font-family: 宋体">除了上面提到的这些代码级的改良之外，我们还可以利用</span><span style="font-family: 'Verdana', 'sans-serif'">GZIP</span><span style="font-family: 宋体">来有效的降低网络流量。目前常见的主流浏览器已经全部支持</span><span style="font-family: 'Verdana', 'sans-serif'">GZIP</span><span style="font-family: 宋体">算法，我们往往只需要编写少量的代码就可以支持</span><span style="font-family: 'Verdana', 'sans-serif'">GZIP</span><span style="font-family: 宋体">了。例如在</span><span style="font-family: 'Verdana', 'sans-serif'">J2EE</span><span style="font-family: 宋体">中我们可以在</span><span style="font-family: 'Verdana', 'sans-serif'">Filter</span><span style="font-family: 宋体">中通过下面的代码来判断客户端浏览器是否支持</span><span style="font-family: 'Verdana', 'sans-serif'">GZIP</span><span style="font-family: 宋体">算法，然后根据需要利用</span><span style="font-family: 'Verdana', 'sans-serif'">java.util.zip.GZIPOutputStream</span><span style="font-family: 宋体">来实现</span><span style="font-family: 'Verdana', 'sans-serif'">GZIP</span><span style="font-family: 宋体">的输出。</span></p>
<table style="border-bottom: medium none; border-left: medium none; border-collapse: collapse; background: #f3f3f3; border-top: medium none; border-right: medium none" class="MsoTableGrid" border="1" cellspacing="0" cellpadding="0">
    <tbody>
        <tr>
            <td style="border-bottom: medium none; border-left: medium none; padding-bottom: 0cm; padding-left: 5.4pt; width: 426.1pt; padding-right: 5.4pt; border-top: medium none; border-right: medium none; padding-top: 0cm" valign="top" width="568">
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">/* </span><span style="font-family: 宋体; font-size: 9pt">判断浏览器对</span><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">GZIP</span><span style="font-family: 宋体; font-size: 9pt">支持方式的代码</span><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt"> */</span></p>
            </td>
        </tr>
        <tr>
            <td style="border-bottom: medium none; border-left: medium none; padding-bottom: 0cm; padding-left: 5.4pt; width: 426.1pt; padding-right: 5.4pt; border-top: medium none; border-right: medium none; padding-top: 0cm" valign="top" width="568">
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">private static String getGZIPEncoding(HttpServletRequest request) {</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;String acceptEncoding = request.getHeader("Accept-Encoding");</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;if (acceptEncoding == null) return null;</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;acceptEncoding = acceptEncoding.toLowerCase();</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;if (acceptEncoding.indexOf("x-gzip") &gt;= 0) return "x-gzip";</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;if (acceptEncoding.indexOf("gzip") &gt;= 0) return "gzip";</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;return null;</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">}</span></p>
            </td>
        </tr>
    </tbody>
</table>
<p style="text-align: left; margin: 7.8pt 0cm 7.8pt 42pt" class="MsoNormal" align="left"><span style="font-family: 宋体">一般而言，</span><span style="font-family: 'Verdana', 'sans-serif'">GZIP</span><span style="font-family: 宋体">对于</span><span style="font-family: 'Verdana', 'sans-serif'">HTML</span><span style="font-family: 宋体">、</span><span style="font-family: 'Verdana', 'sans-serif'">JSP</span><span style="font-family: 宋体">的压缩比可以达到</span><span style="font-family: 'Verdana', 'sans-serif'">80%</span><span style="font-family: 宋体">左右，而它造成的服务端和客户端的性能损耗几乎是可以忽略的。结合其他因素，支持</span><span style="font-family: 'Verdana', 'sans-serif'">GZIP</span><span style="font-family: 宋体">的网站有可能为我们节约</span><span style="font-family: 'Verdana', 'sans-serif'">50%</span><span style="font-family: 宋体">的网络流量。因此</span><span style="font-family: 'Verdana', 'sans-serif'">GZIP</span><span style="font-family: 宋体">的使用可以为那些网络环境不是特别好的应用带来显著的性能提升。使用</span><span style="font-family: 'Verdana', 'sans-serif'">Http</span><span style="font-family: 宋体">的监视工具</span><span style="font-family: 'Verdana', 'sans-serif'">Fiddler</span><span style="font-family: 宋体">可以方便的检测出网页在使用</span><span style="font-family: 'Verdana', 'sans-serif'">GZIP</span><span style="font-family: 宋体">前后的通讯数据量。</span><span style="font-family: 'Verdana', 'sans-serif'">Fiddler</span><span style="font-family: 宋体">的下载地址是</span><span style="font-family: 'Verdana', 'sans-serif'">http://www.fiddlertool.com/fiddler/</span></p>
<p style="text-align: left; margin: 15.6pt 0cm" class="MsoNormal" align="left"><span style="font-family: 宋体">关于</span><span style="font-family: 'Verdana', 'sans-serif'">Web</span><span style="font-family: 宋体">应用的性能优化其实是一个非常大的话题。本文由于篇幅有限，只能涉及其中的几个细节，并且也无法将这些细节的优化方式全面的展现给大家。期望本文能够引起大家对</span><span style="font-family: 'Verdana', 'sans-serif'">Web</span><span style="font-family: 宋体">应用尤其是客户端性能优化的充分重视。毕竟服务端编程技巧已为大家熟知多年，在服务端挖掘性能的潜力已经不大了。而在客户端的方法改进往往能够得到令人惊奇的性能提升。</span></p>
 <img src ="http://www.blogjava.net/freeman1984/aggbug/344056.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2011-02-11 15:23 <a href="http://www.blogjava.net/freeman1984/archive/2011/02/11/344056.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>架构永远都没有最好的，只有最合适的</title><link>http://www.blogjava.net/freeman1984/archive/2010/11/01/336688.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Mon, 01 Nov 2010 07:36:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2010/11/01/336688.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/336688.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2010/11/01/336688.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/336688.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/336688.html</trackback:ping><description><![CDATA[<div class="postText"><br />
&nbsp;&nbsp;&nbsp; 软件架构的选择和设计并不是很容易做出的，一个成功的软件架构取决于N多的因素，软件架构这个词向来就是最为模糊的一个词，个人认为软件架构实在是个很大的话题，业界一直采用的形象比喻就是建设房子时的房屋结构图，以软件的角度来说，软件架构应至少包括软件开发时使用什么语言、形成软件开发时可运行的核心基础框架、软件应用模块的设计（包括模块内聚的功能、对外提供的服务等）、软件测试的方法、软件部署的方法以及团队开发的方法，那么怎么来选择和设计软件架构呢，其衡量的因素是什么呢，个人认为其中质量和快速是衡量软件架构的选择和设计是否成功的两个最重要的因素。<br />
为什么说质量和快速是两个最重要的因素呢？首先来看看这里的质量和快速分别包含了什么内容：<br />
质量<br />
软件的质量是软件能否成功的非常非常重要的因素，就个人看来，软件质量应包括软件功能性需求的实现、软件非功能性需求的实现。<br />
软件功能性需求中最重要的就是要确定对于客户而言商业价值最高的部分是什么，这一项对于软件架构而言的影响是软件应用模块的设计上，而软件应用模块的设计呢，通常要取决于可运行的核心基础框架的设计和实现上；<br />
软件非功能性需求则通常会包含很多要素，像软件灵活性、可扩展性、高响应等，在这些众多的要素中同样要选择出对于目前软件最重要的要素是什么，这会影响到软件架构中的软件开发语言的选择、可运行的核心基础框架。<br />
软件的质量还有需要考虑的要素就是软件测试的方法了（这也会影响到选择什么语言来开发软件），这点对于软件质量而已，无疑是非常重要的一点。<br />
快速<br />
软件能否快速开发完成也已经成为了软件能否成功的重要因素，快速开发完成的意思非常容易理解，但它其实很大的程度影响到了软件架构的选择和设计，很明显的它将影响到软件开发使用什么语言、软件开发时可运行的核心基础框架、软件部署的方法以及团队开发的方法等等，团队中的人很大程度上决定了软件开发时使用什么语言（这个时候也要注意，其实什么语言会影响到开发的速度、开发的质量等，例如erLang的设计目标是为了可构建容错的系统、c则更适合从底层控制整个系统的交互、java具备丰富的基础库、业界资源和更适合复杂业务的需求），至于核心基础框架、部署的方法、团队开发的方法的设计都是为了快速这个目标的。<br />
从上面的两个因素我们可以看到，要使得软件高质量且快速的完成，软件架构在选择和设计上时非常重要的是寻找到一种平衡，所以软件架构要做到模式化其实并不容易。<br />
在这里多说下别的话，其实从上面所述能看出，去评论哪种语言会死是没有什么意义的，并不会有一种语言放在任何环境下都适合，就像在互联网网站的建设上，我想可能很多人都会选择php+c或类似的语言体系，但大家其实可以仔细去想想，是不是网站的建设上一定要这样的两种语言才能承担互联网的高并发等需求呢，或许你更应该做的是从该网站最重要的非功能性需求、团队等等因素来考虑，就像如果你的团队是java性质的团队，而网站最重要的非功能性需求又是支持业务的灵活性的话，那么我会觉得c这样的过程化语言绝对不是这种情况下的最佳选择，而java却是这种情况下的最佳选择，可能很多人会说java太慢呀，什么的，其实并不尽然，很多时候靠硬件以及优秀的架构完全可以弥补掉java比c这样的程序运行相对更慢的毛病，:)，这也算是给java的一个平反吧，呵呵，毕竟java相对c而言还有更大的好处那就是java程序的开发无论从质量还是快速开发上肯定强于c，我这样说并不是说一定要选择java，我只是想说明应该根据什么样的情况来选择和设计什么样的架构，那才是最合理的，所以架构永远都没有最好的，只有最合适的，而这也是架构师最难做的原因，架构师在做架构的设计和选择时遵循的出发点就是保证软件高质量且快速的完成。&nbsp;&nbsp;<br />
<br />
<br />
&nbsp;转载自：http://www.blogjava.net/BlueDavy/archive/2007/10/11/151907.html</div>
<img src ="http://www.blogjava.net/freeman1984/aggbug/336688.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2010-11-01 15:36 <a href="http://www.blogjava.net/freeman1984/archive/2010/11/01/336688.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Comet：基于 HTTP 长连接的“服务器推”技术</title><link>http://www.blogjava.net/freeman1984/archive/2010/10/17/335394.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Sun, 17 Oct 2010 15:45:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2010/10/17/335394.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/335394.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2010/10/17/335394.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/335394.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/335394.html</trackback:ping><description><![CDATA[<p>Comet：基于 HTTP 长连接的&#8220;服务器推&#8221;技术<br />
2008-06-30 21:31<br />
别： 中级 <br />
周 婷 (zhouting@cn.ibm.com), 软件工程师, IBM 中国软件开发技术实验室</p>
<p>2007 年 8 月 31 日</p>
<p>很多应用譬如监控、即时通信、即时报价系统都需要将后台发生的变化实时传送到客户端而无须客户端不停地刷新、发送请求。本文首先介绍、比较了常用的&#8220;服务器推&#8221;方案，着重介绍了 Comet － 使用 HTTP 长连接、无须浏览器安装插件的两种&#8220;服务器推&#8221;方案：基于 AJAX 的长轮询方式；基于 iframe 及 htmlfile 的流方式。最后分析了开发 Comet 应用需要注意的一些问题，以及如何借助开源的 Comet 框架－pushlet 构建自己的&#8220;服务器推&#8221;应用。<br />
&#8220;服务器推&#8221;技术的应用</p>
<p>&nbsp;请访问 Ajax 技术资源中心，这是有关 Ajax 编程模型信息的一站式中心，包括很多文档、教程、论坛、blog、wiki 和新闻。任何 Ajax 的新信息都能在这里找到。&nbsp; <br />
&nbsp;&nbsp; 订阅 Ajax 相关文章和教程的 RSS 提要 <br />
&nbsp;</p>
<p>&nbsp;<br />
&nbsp;<br />
传统模式的 Web 系统以客户端发出请求、服务器端响应的方式工作。这种方式并不能满足很多现实应用的需求，譬如：</p>
<p>监控系统：后台硬件热插拔、LED、温度、电压发生变化； <br />
即时通信系统：其它用户登录、发送信息； <br />
即时报价系统：后台数据库内容发生变化； <br />
这些应用都需要服务器能实时地将更新的信息传送到客户端，而无须客户端发出请求。&#8220;服务器推&#8221;技术在现实应用中有一些解决方案，本文将这些解决方案分为两类：一类需要在浏览器端安装插件，基于套接口传送信息，或是使用 RMI、CORBA 进行远程调用；而另一类则无须浏览器安装任何插件、基于 HTTP 长连接。</p>
<p>将&#8220;服务器推&#8221;应用在 Web 程序中，首先考虑的是如何在功能有限的浏览器端接收、处理信息：</p>
<p>客户端如何接收、处理信息，是否需要使用套接口或是使用远程调用。客户端呈现给用户的是 HTML 页面还是 Java applet 或 Flash 窗口。如果使用套接口和远程调用，怎么和 JavaScript 结合修改 HTML 的显示。 <br />
客户与服务器端通信的信息格式，采取怎样的出错处理机制。 <br />
客户端是否需要支持不同类型的浏览器如 IE、Firefox，是否需要同时支持 Windows 和 Linux 平台。 <br />
&nbsp; <br />
&nbsp; 回页首 <br />
&nbsp;<br />
基于客户端套接口的&#8220;服务器推&#8221;技术</p>
<p>Flash XMLSocket</p>
<p>如果 Web 应用的用户接受应用只有在安装了 Flash 播放器才能正常运行， 那么使用 Flash 的 XMLSocket 也是一个可行的方案。</p>
<p>这种方案实现的基础是：</p>
<p>Flash 提供了 XMLSocket 类。 <br />
JavaScript 和 Flash 的紧密结合：在 JavaScript 可以直接调用 Flash 程序提供的接口。 <br />
具体实现方法：在 HTML 页面中内嵌入一个使用了 XMLSocket 类的 Flash 程序。JavaScript 通过调用此 Flash 程序提供的套接口接口与服务器端的套接口进行通信。JavaScript 在收到服务器端以 XML 格式传送的信息后可以很容易地控制 HTML 页面的内容显示。</p>
<p>关于如何去构建充当了 JavaScript 与 Flash XMLSocket 桥梁的 Flash 程序，以及如何在 JavaScript 里调用 Flash 提供的接口，我们可以参考 AFLAX（Asynchronous Flash and XML）项目提供的 Socket Demo 以及 SocketJS（请参见 参考资源）。</p>
<p>Javascript 与 Flash 的紧密结合，极大增强了客户端的处理能力。从 Flash 播放器 V7.0.19 开始，已经取消了 XMLSocket 的端口必须大于 1023 的限制。Linux 平台也支持 Flash XMLSocket 方案。但此方案的缺点在于：</p>
<p>客户端必须安装 Flash 播放器； <br />
因为 XMLSocket 没有 HTTP 隧道功能，XMLSocket 类不能自动穿过防火墙； <br />
因为是使用套接口，需要设置一个通信端口，防火墙、代理服务器也可能对非 HTTP 通道端口进行限制； <br />
不过这种方案在一些网络聊天室，网络互动游戏中已得到广泛使用。</p>
<p>Java Applet 套接口 </p>
<p>在客户端使用 Java Applet，通过 java.net.Socket 或 java.net.DatagramSocket 或 java.net.MulticastSocket 建立与服务器端的套接口连接，从而实现&#8220;服务器推&#8221;。</p>
<p>这种方案最大的不足在于 Java applet 在收到服务器端返回的信息后，无法通过 JavaScript 去更新 HTML 页面的内容。</p>
<p>&nbsp; <br />
&nbsp; 回页首 <br />
&nbsp;<br />
基于 HTTP 长连接的&#8220;服务器推&#8221;技术</p>
<p>Comet 简介</p>
<p>浏览器作为 Web 应用的前台，自身的处理功能比较有限。浏览器的发展需要客户端升级软件，同时由于客户端浏览器软件的多样性，在某种意义上，也影响了浏览器新技术的推广。在 Web 应用中，浏览器的主要工作是发送请求、解析服务器返回的信息以不同的风格显示。AJAX 是浏览器技术发展的成果，通过在浏览器端发送异步请求，提高了单用户操作的响应性。但 Web 本质上是一个多用户的系统，对任何用户来说，可以认为服务器是另外一个用户。现有 AJAX 技术的发展并不能解决在一个多用户的 Web 应用中，将更新的信息实时传送给客户端，从而用户可能在&#8220;过时&#8221;的信息下进行操作。而 AJAX 的应用又使后台数据更新更加频繁成为可能。</p>
<p>图 1. 传统的 Web 应用模型与基于 AJAX 的模型之比较&nbsp; <br />
&#8220;服务器推&#8221;是一种很早就存在的技术，以前在实现上主要是通过客户端的套接口，或是服务器端的远程调用。因为浏览器技术的发展比较缓慢，没有为&#8220;服务器推&#8221;的实现提供很好的支持，在纯浏览器的应用中很难有一个完善的方案去实现&#8220;服务器推&#8221;并用于商业程序。最近几年，因为 AJAX 技术的普及，以及把 IFrame 嵌在&#8220;htmlfile&#8220;的 ActiveX 组件中可以解决 IE 的加载显示问题，一些受欢迎的应用如 meebo，gmail+gtalk 在实现中使用了这些新技术；同时&#8220;服务器推&#8221;在现实应用中确实存在很多需求。因为这些原因，基于纯浏览器的&#8220;服务器推&#8221;技术开始受到较多关注，Alex Russell（Dojo Toolkit 的项目 Lead）称这种基于 HTTP 长连接、无须在浏览器端安装插件的&#8220;服务器推&#8221;技术为&#8220;Comet&#8221;。目前已经出现了一些成熟的 Comet 应用以及各种开源框架；一些 Web 服务器如 Jetty 也在为支持大量并发的长连接进行了很多改进。关于 Comet 技术最新的发展状况请参考关于 Comet 的 wiki。</p>
<p>下面将介绍两种 Comet 应用的实现模型。</p>
<p>基于 AJAX 的长轮询（long-polling）方式</p>
<p>如 图 1 所示，AJAX 的出现使得 JavaScript 可以调用 XMLHttpRequest 对象发出 HTTP 请求，JavaScript 响应处理函数根据服务器返回的信息对 HTML 页面的显示进行更新。使用 AJAX 实现&#8220;服务器推&#8221;与传统的 AJAX 应用不同之处在于：</p>
<p>服务器端会阻塞请求直到有数据传递或超时才返回。 <br />
客户端 JavaScript 响应处理函数会在处理完服务器返回的信息后，再次发出请求，重新建立连接。 <br />
当客户端处理接收的数据、重新建立连接时，服务器端可能有新的数据到达；这些信息会被服务器端保存直到客户端重新建立连接，客户端会一次把当前服务器端所有的信息取回。 <br />
图 2. 基于长轮询的服务器推模型&nbsp; <br />
一些应用及示例如 &#8220;Meebo&#8221;, &#8220;Pushlet Chat&#8221; 都采用了这种长轮询的方式。相对于&#8220;轮询&#8221;（poll），这种长轮询方式也可以称为&#8220;拉&#8221;（pull）。因为这种方案基于 AJAX，具有以下一些优点：请求异步发出；无须安装插件；IE、Mozilla FireFox 都支持 AJAX。</p>
<p>在这种长轮询方式下，客户端是在 XMLHttpRequest 的 readystate 为 4（即数据传输结束）时调用回调函数，进行信息处理。当 readystate 为 4 时，数据传输结束，连接已经关闭。Mozilla Firefox 提供了对 Streaming AJAX 的支持， 即 readystate 为 3 时（数据仍在传输中），客户端可以读取数据，从而无须关闭连接，就能读取处理服务器端返回的信息。IE 在 readystate 为 3 时，不能读取服务器返回的数据，目前 IE 不支持基于 Streaming AJAX。</p>
<p>基于 Iframe 及 htmlfile 的流（streaming）方式</p>
<p>iframe 是很早就存在的一种 HTML 标记， 通过在 HTML 页面里嵌入一个隐蔵帧，然后将这个隐蔵帧的 SRC 属性设为对一个长连接的请求，服务器端就能源源不断地往客户端输入数据。</p>
<p>图 3. 基于流方式的服务器推模型&nbsp; <br />
上节提到的 AJAX 方案是在 JavaScript 里处理 XMLHttpRequest 从服务器取回的数据，然后 Javascript 可以很方便的去控制 HTML 页面的显示。同样的思路用在 iframe 方案的客户端，iframe 服务器端并不返回直接显示在页面的数据，而是返回对客户端 Javascript 函数的调用，如&#8220;&lt;script type="text/javascript"&gt;js_func(&#8220;data from server &#8221;)&lt;/script&gt;&#8221;。服务器端将返回的数据作为客户端 JavaScript 函数的参数传递；客户端浏览器的 Javascript 引擎在收到服务器返回的 JavaScript 调用时就会去执行代码。</p>
<p>从 图 3 可以看到，每次数据传送不会关闭连接，连接只会在通信出现错误时，或是连接重建时关闭（一些防火墙常被设置为丢弃过长的连接， 服务器端可以设置一个超时时间， 超时后通知客户端重新建立连接，并关闭原来的连接）。</p>
<p>使用 iframe 请求一个长连接有一个很明显的不足之处：IE、Morzilla Firefox 下端的进度栏都会显示加载没有完成，而且 IE 上方的图标会不停的转动，表示加载正在进行。Google 的天才们使用一个称为&#8220;htmlfile&#8221;的 ActiveX 解决了在 IE 中的加载显示问题，并将这种方法用到了 gmail+gtalk 产品中。Alex Russell 在 &#8220;What else is burried down in the depth's of Google's amazing JavaScript?&#8221;文章中介绍了这种方法。Zeitoun 网站提供的 comet-iframe.tar.gz，封装了一个基于 iframe 和 htmlfile 的 JavaScript comet 对象，支持 IE、Mozilla Firefox 浏览器，可以作为参考。（请参见 参考资源）</p>
<p>&nbsp; <br />
&nbsp; 回页首 <br />
&nbsp;<br />
使用 Comet 模型开发自己的应用</p>
<p>上面介绍了两种基于 HTTP 长连接的&#8220;服务器推&#8221;架构，更多描述了客户端处理长连接的技术。对于一个实际的应用而言，系统的稳定性和性能是非常重要的。将 HTTP 长连接用于实际应用，很多细节需要考虑。</p>
<p>不要在同一客户端同时使用超过两个的 HTTP 长连接</p>
<p>我们使用 IE 下载文件时会有这样的体验，从同一个 Web 服务器下载文件，最多只能有两个文件同时被下载。第三个文件的下载会被阻塞，直到前面下载的文件下载完毕。这是因为 HTTP 1.1 规范中规定，客户端不应该与服务器端建立超过两个的 HTTP 连接， 新的连接会被阻塞。而 IE 在实现中严格遵守了这种规定。</p>
<p>HTTP 1.1 对两个长连接的限制，会对使用了长连接的 Web 应用带来如下现象：在客户端如果打开超过两个的 IE 窗口去访问同一个使用了长连接的 Web 服务器，第三个 IE 窗口的 HTTP 请求被前两个窗口的长连接阻塞。</p>
<p>所以在开发长连接的应用时， 必须注意在使用了多个 frame 的页面中，不要为每个 frame 的页面都建立一个 HTTP 长连接，这样会阻塞其它的 HTTP 请求，在设计上考虑让多个 frame 的更新共用一个长连接。</p>
<p>服务器端的性能和可扩展性</p>
<p>一般 Web 服务器会为每个连接创建一个线程，如果在大型的商业应用中使用 Comet，服务器端需要维护大量并发的长连接。在这种应用背景下，服务器端需要考虑负载均衡和集群技术；或是在服务器端为长连接作一些改进。</p>
<p>应用和技术的发展总是带来新的需求，从而推动新技术的发展。HTTP 1.1 与 1.0 规范有一个很大的不同：1.0 规范下服务器在处理完每个 Get/Post 请求后会关闭套接口连接； 而 1.1 规范下服务器会保持这个连接，在处理两个请求的间隔时间里，这个连接处于空闲状态。 Java 1.4 引入了支持异步 IO 的 java.nio 包。当连接处于空闲时，为这个连接分配的线程资源会返还到线程池，可以供新的连接使用；当原来处于空闲的连接的客户发出新的请求，会从线程池里分配一个线程资源处理这个请求。 这种技术在连接处于空闲的机率较高、并发连接数目很多的场景下对于降低服务器的资源负载非常有效。</p>
<p>但是 AJAX 的应用使请求的出现变得频繁，而 Comet 则会长时间占用一个连接，上述的服务器模型在新的应用背景下会变得非常低效，线程池里有限的线程数甚至可能会阻塞新的连接。Jetty 6 Web 服务器针对 AJAX、Comet 应用的特点进行了很多创新的改进，请参考文章&#8220;AJAX，Comet and Jetty&#8221;（请参见 参考资源）。</p>
<p>控制信息与数据信息使用不同的 HTTP 连接</p>
<p>使用长连接时，存在一个很常见的场景：客户端网页需要关闭，而服务器端还处在读取数据的堵塞状态，客户端需要及时通知服务器端关闭数据连接。服务器在收到关闭请求后首先要从读取数据的阻塞状态唤醒，然后释放为这个客户端分配的资源，再关闭连接。</p>
<p>所以在设计上，我们需要使客户端的控制请求和数据请求使用不同的 HTTP 连接，才能使控制请求不会被阻塞。</p>
<p>在实现上，如果是基于 iframe 流方式的长连接，客户端页面需要使用两个 iframe，一个是控制帧，用于往服务器端发送控制请求，控制请求能很快收到响应，不会被堵塞；一个是显示帧，用于往服务器端发送长连接请求。如果是基于 AJAX 的长轮询方式，客户端可以异步地发出一个 XMLHttpRequest 请求，通知服务器端关闭数据连接。</p>
<p>在客户和服务器之间保持&#8220;心跳&#8221;信息</p>
<p>在浏览器与服务器之间维持一个长连接会为通信带来一些不确定性：因为数据传输是随机的，客户端不知道何时服务器才有数据传送。服务器端需要确保当客户端不再工作时，释放为这个客户端分配的资源，防止内存泄漏。因此需要一种机制使双方知道大家都在正常运行。在实现上：</p>
<p>服务器端在阻塞读时会设置一个时限，超时后阻塞读调用会返回，同时发给客户端没有新数据到达的心跳信息。此时如果客户端已经关闭，服务器往通道写数据会出现异常，服务器端就会及时释放为这个客户端分配的资源。 <br />
如果客户端使用的是基于 AJAX 的长轮询方式；服务器端返回数据、关闭连接后，经过某个时限没有收到客户端的再次请求，会认为客户端不能正常工作，会释放为这个客户端分配、维护的资源。 <br />
当服务器处理信息出现异常情况，需要发送错误信息通知客户端，同时释放资源、关闭连接。 <br />
Pushlet - 开源 Comet 框架</p>
<p>Pushlet 是一个开源的 Comet 框架，在设计上有很多值得借鉴的地方，对于开发轻量级的 Comet 应用很有参考价值。</p>
<p>观察者模型</p>
<p>Pushlet 使用了观察者模型：客户端发送请求，订阅感兴趣的事件；服务器端为每个客户端分配一个会话 ID 作为标记，事件源会把新产生的事件以多播的方式发送到订阅者的事件队列里。</p>
<p>客户端 JavaScript 库</p>
<p>pushlet 提供了基于 AJAX 的 JavaScript 库文件用于实现长轮询方式的&#8220;服务器推&#8221;；还提供了基于 iframe 的 JavaScript 库文件用于实现流方式的&#8220;服务器推&#8221;。</p>
<p>JavaScript 库做了很多封装工作：</p>
<p>定义客户端的通信状态：STATE_ERROR、STATE_ABORT、STATE_NULL、STATE_READY、STATE_JOINED、STATE_LISTENING； <br />
保存服务器分配的会话 ID，在建立连接之后的每次请求中会附上会话 ID 表明身份； <br />
提供了 join()、leave()、subscribe()、 unsubsribe()、listen() 等 API 供页面调用； <br />
提供了处理响应的 JavaScript 函数接口 onData()、onEvent()&#8230; <br />
网页可以很方便地使用这两个 JavaScript 库文件封装的 API 与服务器进行通信。</p>
<p>客户端与服务器端通信信息格式</p>
<p>pushlet 定义了一套客户与服务器通信的信息格式，使用 XML 格式。定义了客户端发送请求的类型：join、leave、subscribe、unsubscribe、listen、refresh；以及响应的事件类型：data、join_ack、listen_ack、refresh、heartbeat、error、abort、subscribe_ack、unsubscribe_ack。</p>
<p>服务器端事件队列管理</p>
<p>pushlet 在服务器端使用 Java Servlet 实现，其数据结构的设计框架仍可适用于 PHP、C 编写的后台客户端。</p>
<p>Pushlet 支持客户端自己选择使用流、拉（长轮询）、轮询方式。服务器端根据客户选择的方式在读取事件队列（fetchEvents）时进行不同的处理。&#8220;轮询&#8221;模式下 fetchEvents() 会马上返回。&#8221;流&#8220;和&#8221;拉&#8220;模式使用阻塞的方式读事件，如果超时，会发给客户端发送一个没有新信息收到的&#8220;heartbeat&#8220;事件，如果是&#8220;拉&#8221;模式，会把&#8220;heartbeat&#8221;与&#8220;refresh&#8221;事件一起传给客户端，通知客户端重新发出请求、建立连接。</p>
<p>客户服务器之间的会话管理</p>
<p>服务端在客户端发送 join 请求时，会为客户端分配一个会话 ID， 并传给客户端，然后客户端就通过此会话 ID 标明身份发出 subscribe 和 listen 请求。服务器端会为每个会话维护一个订阅的主题集合、事件队列。</p>
<p>服务器端的事件源会把新产生的事件以多播的方式发送到每个会话（即订阅者）的事件队列里。</p>
<p>&nbsp; <br />
&nbsp; 回页首 <br />
&nbsp;<br />
小结</p>
<p>本文介绍了如何在现有的技术基础上选择合适的方案开发一个&#8220;服务器推&#8221;的应用，最优的方案还是取决于应用需求的本身。相对于传统的 Web 应用， 目前开发 Comet 应用还是具有一定的挑战性。</p>
<p>&#8220;服务器推&#8221;存在广泛的应用需求，为了使 Comet 模型适用于大规模的商业应用，以及方便用户构建 Comet 应用，最近几年，无论是服务器还是浏览器都出现了很多新技术，同时也出现了很多开源的 Comet 框架、协议。需求推动技术的发展，相信 Comet 的应用会变得和 AJAX 一样普及。</p>
<p>参考资料 </p>
<p>学习 <br />
developerWorks 文章&#8220; 面向 Java 开发人员的 Ajax: 使用 Jetty 和 Direct Web Remoting 编写可扩展的 Comet 应用程序&#8221;：受异步服务器端事件驱动的 Ajax 应用程序实现较为困难，本文介绍了一种结合使用 Comet 模式和 Jetty 6 Continuations API 的解决方法。 <br />
&#8220;Comet: Low Latency Data for the Browser&#8221;：Alex Russell 是 Dojo Toolkit 的项目主管和 Dojo Foundation 的主席，他在这篇博客文章中提出了 Comet 这个术语。 <br />
&#8220;What else is burried down in the depth&#8217;s of Google&#8217;s amazing JavaScript?&#8221;（Alex Russel，2006 年 2 月）：Alex 在这篇文章里介绍了如何使用&#8220;htmlfile&#8221;ActiveX 控件解决 iframe 请求长连接时 IE 的加载显示问题。 <br />
Comet wiki：提供了很多开源 Comet 框架的链接。 <br />
Jetty：Jetty 是一种开源的基于标准的 Web 服务器，完全使用 Java 语言实现。 <br />
&#8220;Ajax, Comet and Jetty&#8221;（Greg Wilkins，Webtide，2006 年 1 月）：Wilkins 的这份白皮书讨论了扩展 Ajax 连接的 Jetty 架构方法。 <br />
Continuations：了解更多关于 Jetty 的 Continuations 特性的信息。 <br />
&#8220;pushlet&#8221;：开源 comet 框架，使用了观察者模型。浏览器端提供了基于 AJAX 和 iframe 的 JavaScript 库，服务器端使用 Java Servlet。 <br />
&#8220;How to implement COMET with PHP&#8221;：提供的 comet-iframe.tar.gz 使用 iframe/htmlfile 封装了一个 JavaScript comet 对象，支持 IE、Mozilla Firefox 浏览器。 <br />
&#8220;AFLAX&#8221;：Asynchronous Flash and XML，提供了强大的 Flash、Javascript 库和很多范例。 <br />
developerWorks Ajax 技术资源中心：能找到更多关于 Ajax 技术的文章和教程。 <br />
developerWorks Web 开发技术专区：提供了关于 Web 开发和架构方面的大量文章。 <br />
developerWorks Java 技术专区：提供了关于 Java 编程各个方面的数百篇文章。 <br />
浏览 技术书店，查阅有关本文所述主题以及其他技术主题的书籍。&nbsp; </p>
<p><br />
&nbsp;</p>
<img src ="http://www.blogjava.net/freeman1984/aggbug/335394.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2010-10-17 23:45 <a href="http://www.blogjava.net/freeman1984/archive/2010/10/17/335394.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Oracle 10g SQL 优化再学习</title><link>http://www.blogjava.net/freeman1984/archive/2010/10/10/334235.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Sun, 10 Oct 2010 15:52:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2010/10/10/334235.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/334235.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2010/10/10/334235.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/334235.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/334235.html</trackback:ping><description><![CDATA[<p>&nbsp;</p>
<p>从8i到10g，Oracle不断进化自己的SQL Tuning智能，一些秘籍级的优化口诀已经失效。<br />
&nbsp;&nbsp; 但我喜欢失效，不用记口诀，操个Toad for Oracle Xpert ，按照大方向舒舒服服的调优才是爱做的事情。</p>
<p>1.Excution Plan<br />
&nbsp;&nbsp;&nbsp;&nbsp; Excution Plan是最基本的调优概念，不管你的调优吹得如何天花乱堕，结果还是要由Excution plan来显示Oracle 最终用什么索引、按什么顺序连接各表，Full Table Scan还是Access by Rowid Index，瓶颈在什么地方。如果没有它的指导，一切调优都是蒙的。</p>
<p><br />
2.Toad for Oracle Xpert<br />
&nbsp;&nbsp;&nbsp; 用它来调优在真的好舒服。Quest 吞并了Lecco后，将它整合到了Toad 的SQL Tunning里面：最清晰的执行计划显示，自动生成N条等价SQL、给出优化建议，不同SQL执行计划的对比，还有实际执行的逻辑读、物理读数据等等一目了然。</p>
<p><br />
3.索引<br />
&nbsp;&nbsp; 大部分的性能问题其实都是索引应用的问题，Where子句、Order By、Group By 都要用到索引。<br />
&nbsp;&nbsp; 一般开发人员认为将索引建全了就可以下班回家了，实则还有颇多的思量和陷阱。</p>
<p>3.1 索引列上不要进行计算<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 这是最最普遍的失效陷阱，比如where trunc(order_date)=trunc(sysdate), i+2&gt;4。索引失效的原因也简单，索引是针对原值建的二叉树，你将列值*3/4+2折腾一番后，原来的二叉树当然就用不上了。解决的方法:<br />
　 1.　换成等价语法，比如trunc(order_date) 换成</p>
<p>where order_date&gt;trunc(sysdate)-1 and order_date&lt;trunc(sysdate)+1　 2.&nbsp;&nbsp;&nbsp; 特别为计算建立函数索引</p>
<p>create index Ｉ_XXXX on shop_order(trunc(order_date))&nbsp;&nbsp;&nbsp; 3.&nbsp;&nbsp;&nbsp; 将计算从等号左边移到右边<br />
　这是针对某些无心之失的纠正，把a*2&gt;4　改为a&gt;4/2；把TO_CHAR(zip) = '94002' 改为zip = TO_NUMBER('94002');</p>
<p>3.2 CBO与索引选择性<br />
&nbsp;&nbsp;&nbsp;&nbsp; 建了索引也不一定会被Oracle用的，就像个挑食的孩子。基于成本的优化器(CBO, Cost-Based Optimizer)，会先看看表的大小，还有索引的重复度，再决定用还是不用。表中有100 条记录而其中有80 个不重复的索引键值. 这个索引的选择性就是80/100 = 0.8，留意Toad里显示索引的Selective和Cardinailty。实在不听话时，就要用hints来调教。<br />
&nbsp;&nbsp;&nbsp;&nbsp; 另外，where语句存在多条索引可用时，只会选择其中一条。所以索引也不是越多越好：）</p>
<p>3.3 索引重建<br />
&nbsp;&nbsp;&nbsp;&nbsp; 传说中数据更新频繁导致有20%的碎片时，Oracle就会放弃这个索引。宁可信其有之下，应该时常alter index &lt;INDEXNAME&gt; rebuild一下。</p>
<p>3.4 其他要注意的地方<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 不要使用Not，如goods_no != 2，要改为</p>
<p>where goods_no&gt;2 or goods_no&lt;2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 不要使用is null , 如WHERE DEPT_CODE IS NOT NULL 要改为</p>
<p>WHERE DEPT_CODE &gt;=0;3.5 select 的列如果全是索引列时<br />
&nbsp;&nbsp; 又如果没有where 条件，或者where条件全部是索引列时，Oracle 将直接从索引里获取数据而不去读真实的数据表，这样子理论上会快很多，比如</p>
<p>select order_no,order_time from shop_order where shop_no=4当order_no,order_time,shop_no 这三列全为索引列时，你将看到一个和平时完全不同的执行计划。</p>
<p>3.6 位图索引<br />
&nbsp;&nbsp;&nbsp;&nbsp; 传说中当数据值较少，比如某些表示分类、状态的列，应该建位图索引而不是普通的二叉树索引，否则效率低下。不过看执行计划，这些位图索引鲜有被Oracle临幸的。<br />
&nbsp; </p>
<p><br />
4.减少查询往返和查询的表<br />
这也是很简单的大道理，程序与Oracle交互的成本极高，所以一个查询能完成的不要分开两次查，如果一个循环执行１万条查询的，怎么都快不到哪里去了。</p>
<p>4.1 封装PL/SQL存储过程<br />
　 最高级的做法是把循环的操作封装到PL/SQL写的存储过程里，因为存储过程都在服务端执行，所以没有数据往返的消耗。</p>
<p><br />
4.2 封装PL/SQL内部函数<br />
&nbsp; 有机会，将一些查询封装到函数里，而在普通SQL里使用这些函数，同样是很有效的优化。</p>
<p>4.3 Decode/Case<br />
　 但存储过程也麻烦，所以有case/decode把几条条件基本相同的重复查询合并为一条的用法：</p>
<p>SELECT<br />
&nbsp;COUNT(CASE WHEN price &lt; 13 THEN 1 ELSE null END) low,<br />
&nbsp;COUNT(CASE WHEN price BETWEEN 13 AND 15 THEN 1 ELSE null END) med,<br />
&nbsp;COUNT(CASE WHEN price &gt; 15 THEN 1 ELSE null END) high<br />
FROM products;4.4 一种Where/Update语法</p>
<p>SELECT TAB_NAME　FROM TABLES<br />
WHERE (TAB_NAME,DB_VER) = （( SELECT TAB_NAME,DB_VER)<br />
FROM TAB_COLUMNS WHERE VERSION = 604)</p>
<p>UPDATE EMP<br />
SET (EMP_CAT, SAL_RANGE)<br />
= (SELECT MAX(CATEGORY)FROM EMP_CATEGORIES)<br />
5.其他优化<br />
5.1RowID和ROWNUM<br />
&nbsp;&nbsp;&nbsp;&nbsp; 连Hibernate 新版也支持ROWID了，证明它非常有用。比如号称删除重复数据的最快写法：</p>
<p>DELETE FROM EMP E<br />
WHERE E.ROWID &gt; (SELECT MIN(X.ROWID)<br />
FROM EMP X<br />
WHERE X.EMP_NO = E.EMP_NO);6.终极秘技 - Hints<br />
&nbsp;&nbsp; 这是Oracle DBA的玩具，也是终极武器，比如Oracle在CBO,RBO中所做的选择总不合自己心水时，可以用它来强力调教一下Oracle，结果经常让人喜出望外。<br />
&nbsp;&nbsp; 如果开发人员没那么多时间来专门学习它，可以依靠Toad SQL opmitzer 来自动生成这些提示，然后对比一下各种提示的实际效果。不过随着10g智能的进化，hints的惊喜少了。</p>
<p>7. 找出要优化的Top SQL<br />
&nbsp;&nbsp;&nbsp; 磨了这么久的枪，如果找不到敌人是件郁闷的事情。<br />
&nbsp;&nbsp;&nbsp; 幸亏10g这方面做得非常好。进入Web管理界面，就能看到当前或者任意一天的SQL列表，按性能排序。<br />
&nbsp;&nbsp;&nbsp; 有了它，SQL Trace和TKPROF都可以不用了。</p>
<p><br />
本文来自CSDN博客，转载请标明出处：http://blog.csdn.net/calvinxiu/archive/2005/11/15/529756.aspx</p>
<img src ="http://www.blogjava.net/freeman1984/aggbug/334235.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2010-10-10 23:52 <a href="http://www.blogjava.net/freeman1984/archive/2010/10/10/334235.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>软件构架师的特点</title><link>http://www.blogjava.net/freeman1984/archive/2010/10/10/334233.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Sun, 10 Oct 2010 15:45:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2010/10/10/334233.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/334233.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2010/10/10/334233.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/334233.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/334233.html</trackback:ping><description><![CDATA[<blockquote>来自于 Rational Edge：在电影制作术语中，软件项目经理被称作制作人，因为他们决定需要做什么事情。而软件构架师就是导演，他来决定所作的事情是否正确，并且他要保证产品符合投资人的要求。下面这篇文章就是描述软件构架师的。</blockquote><!--start RESERVED FOR FUTURE USE INCLUDE FILES--><!-- include java script once we verify teams wants to use this and it will work on dbcs and cyrillic characters --><!--end RESERVED FOR FUTURE USE INCLUDE FILES-->
<p>&nbsp;<em>这篇文章是关于软件构架的系列文章（共四篇）中的第二篇。上个月，<a href="http://www.ibm.com/developerworks/rational/library/feb06/eeles/index.html?S_TACT=105AGX52&amp;S_CMP=cn-a-r" target="_blank">这个系列文章中的第一篇</a>给构架作了一个定义。因此现在我们可以把注意力集中到创建构架的人员——构架师身上。软件构架师被证明是软件开发项目过程中最具挑战性的角色。软件构架师是项目的技术领袖，并且从技术角度来讲，他承担了项目成败的责任。</em> </p>
<p><em>下面是电气及电子工程师协会给&#8220;构架师&#8221;做的定义：</em> </p>
<blockquote>[构架师是]负责系统构架的人，团队或者组织。<a href="#notes"> <sup>1</sup> </a></blockquote>
<p><em>作为项目的技术主管，构架师的技术需要非常的广泛，这比技术深度更加重要（当然构架师在特定的领域需要一定的技术深度）。</em> </p>
<p><a name="N1006C"><span class="atitle">软件构架师是技术主管</span></a></p>
<p>首先，软件构架师是技术主管，这意味着除了他要有技术上的技能外，还要有很好的领导才能。构架师的领导能力在团队中和项目质量控制中起着十分重要的作用。</p>
<p>在团队中，构架师是项目的技术总管，他需要有丰富的知识背景，以便作出技术上的决定。相对于构架师来说，项目经理是来管理项目的资源，时间进度和花费的。使用电影制作来做类比的话，项目经理就是制片人（他要确定工作被完成了），而构架师是导演（他需要确定工作被正确的完成）。由于他们在项目中所处的位置，构架师和项目经理是公众人物，在一个团队中，他们是整个项目所涉及的所有人员的联系枢纽。构架师应该为建立软件构架争取投资，并且要明确建立软件构架能给组织带来的价值。</p>
<p>构架师还要把团队组织在构架周围，并且要积极地投入到计划活动上，因为要把构架转化成为完成任务的先后顺序，这样才能及时地确定在什么位置需要什么技术。有一点需要注意，由于构架师能否成功与团队的整体水平有很大关系，所以构架师应该参与团队新成员录用的面试。</p>
<p>根据构架师所拥有的能力，他可以同时参与其他团队的工作。构架师需要根据具体的实例情况来做领导决定，并且在决定过程中要展现出足够的自信。一个成功的构架师是以人为导向的，并且像一个教练一样给他的团队安排工作时间。这对于小组的成员来说是有好处的，他们可以及时得到帮助。这是整个团队的一个巨大财富。</p>
<p>构架师还要把精力放在切实工作的交付上，他是技术方面的推进力量。构架师需要做决定（经常需要在压力下做决定），并且要保证这些决定是经过成员之间的交流的，并且确保它能够执行。</p>
<p><a name="N10082"><span class="atitle">架构师可能是有一个小组来完成的</span></a></p>
<p>下面介绍一个人和一个角色的区别。一个人可以扮演很多角色（例如，Mary是一个开发人员，同时也是一个测试人员），同时，一个角色可以有很多的人扮演（例如，Mary和John都是测试人员）。构架师的角色需要非常广泛的技术，这就为什么构架师的角色经常是很多人同时担当。这样可以使技术知识在小组中传播开来，每一个人都把他的或者她的经验带到工作中。特别是当某种技术同时被商业部门和技术小组理解的时候，这项技术就会最大程度的传播开来。小组所作的结果，需要被"平衡。" 贯穿整个文章的术语"构架师"，是指的一个人或者整个小组的成员。</p>
<blockquote><em>[一个小组]是一些拥有各种技术的人的集合，他们之间有共同需要完成的目标，并且之间相互负责任。</em> <a href="#notes"><sup>2</sup> </a></blockquote>
<p>如果一个小组来担当构架师的角色，那么就需要有一个人作为这些构架师的领导，他要拥有整体的前景，并且需要调节构架师小组之间的问题。如果没有这种调节，构架师小组成员之间就会存在危险，他们可能不会建立出一个紧密地构架或者决策不会被成功的完成。</p>
<p>现在有一个新的概念在构架师小组中被提出：为了使成员之间达到共同的目的和目标，团队为构架师小组建立并发布了一个章程。<a href="#notes"> <sup>3</sup> </a></p>
<p>好的构架师知道自己的强项和弱点在哪里。无论构架师的角色被一个人还是一个小组担当，他们背后都有"值得信赖的顾问"的支持。他们可以通过和其他构架师协同工作来弥补自身在某些技术方面的不足。最好的构架通常是被一个构架师小组建立的，而不是一个人。原因很简单，一个小组的力量总要比一个人的知识丰富的多。</p>
<p>构架师小组的概念有一个缺陷，他们有时被团队中的其他人认为是在"象牙塔"里工作，因为他们的产品经常是很有智慧的但却没有使用价值。这种误解可以从开始就把它减到最小：1)确保所有的涉众都能积极地协商，2)不断的交流构架和它的价值，3)在执行过程中要有组织策略的意识。</p>
<p><a name="N100AC"><span class="atitle">构架师应该理解软件开发过程</span></a></p>
<p>构架师应该对软件开发过程有正确的估计，因为这个过程确保小组中的所有成员使用同等的方式工作。一个好的过程需要定义各个角色的工作承担责任， 产品的建立，不同角色之间的协同工作等等。由于构架师每天的工作都需要和很多小组成员打交道，所以对于他们来说了解工作的职责是非常重要的。在每天的工作中，开发小组经常要找到构架师，了解该做什么工作以及怎么去做。这就是软件构架师和项目经理之间的细微差别。</p>
<p><a name="N100B6"><span class="atitle">软件构架师需要有商业领域的知识</span></a></p>
<p>尽管拥有了丰富的软件开发经验，但是我们还期望（或者是要求）构架师拥有一定商业领域的知识。</p>
<blockquote><em>[一个领域]是在一个范围内工作的从业人员使用一系列特定的概念和术语来表达这个领域内的知识。</em> <a href="#notes"><sup>4</sup> </a></blockquote>
<p>这种知识将会使构架师更好的理解系统的需求，并把精力投身于其中，确保系统的需求是合适的——例如，从构架师领域的角度出发，需求是要被准确捕获的。经常会出现这样的情况，一个特定系列的构架样式可以被应用到与它相联系的一个特定的领域中。如果构架师知道这种映射关系，那么对他的工作将是很大的帮助。</p>
<p>因此，一个好的构架师将会在软件开发和商业领域的知识上面做出权衡。如果一个构架师具有很好的软件开发经验但是不了解商业领域，那么他的解决方案可能不会解决实际的问题，而仅仅只能反映出构架师是多么精通他的专业。</p>
<p>另外一个构架师需要精通商业领域知识的原因是，构架师要能够预见软件构架随时可能出现的变化。由于软件构架受它被配置的环境的影响非常大，所以对商业领域有正确理解的构架师，可以从软件构架的角度，对不断变化的情况做出更有远见的决策。例如，如果构架师发觉哪种新的标准在未来很可能成为主流，那么他将会使自己的软件构架在可用寿命内符合这种标准。</p>
<p><a name="N100D6"><span class="atitle">软件构架师应该拥有技术知识</span></a></p>
<p>软件构架的一个特定方面需要有一定的专业知识，因此一个构架师必须具备这个水平的知识才能够胜任他的工作。可是构架师不必成为技术专家，这体现了这篇文章第一部分的思想——构架师宏观上的决策。因此，构架师只需要了解宏观上的问题，而不必关心细节化的事情。由于技术的变化过于频繁，所以构架师要随时与这些变化保持同步。</p>
<p><a name="N100E0"><span class="atitle">软件构架师应该拥有很好的设计技巧</span></a></p>
<p>虽然软件构架并不仅仅是设计，但是设计无疑是很重要的一个组成部分。构架师应该拥有很好的设计技巧，因为软件的构架包含整个软件的关键性设计决策。这种决定包括软件主要结构的设计决策，特定部分的选择以及指导的说明文档等等。为了确保系统构架的完整性，上面那些要素都要被特别的应用到设计中，这对整个系统的成功完成有很大的作用。因此这些要素需要有固定的拥有设计技巧的人来负责——这个人就是构架师。</p>
<p><a name="N100EA"><span class="atitle">软件构架师需要拥有很好的程序设计技巧</span></a></p>
<p>开发人员是整个项目开发过程中最重要的一个小组之一，构架师要随时和他们保持联系。毕竟他们要确保软件在最后交付使用的时候能够成功的执行。如果构架师认为开发人员的工作是十分有价值的，那么他们之间的交流将会很有效用。因此，软件构架师需要拥有一定的程序设计技术，即使不需要他们编写程序。</p>
<p>大多数成功的构架师，在一些场合中都是核心程序员，这些场合通常是他们的职业方向。即使是技术发展了，有新的程序语言出现，一个好的构架师可以把以前学过的设计语言的概念和新的语言联系起来，以达到对新语言更加深入的了解。没有这种知识，软件构架师就不能对需要执行的构架的重要元素做出完美的决策，例如执行的组织和程序标准的采用。这会使的软件构架师和开发人员之间产生沟通上的障碍。</p>
<p><a name="N100F7"><span class="atitle">构架师是一个很好的沟通员</span></a></p>
<p>和以上提到的几种技术比起来，构架师的沟通能力是最重要的。构架师需要精通所有的沟通手段，特别是需要有一定的语言能力，包括说，写和演讲能力。交流是双向的，所以构架师还需要是一个很好的聆听者与观察者。</p>
<p>小组成员之间有效的沟通是项目成功的基本条件。为了更好的理解投资人的需求，与他们的沟通显得尤为重要，同时还能够让所有的投资人在软件构架上达成共识。与项目小组的沟通同时也很重要，因为构架师的职责不单单是把信息传达给小组，同时还要激励他们工作。构架师还要负责把系统的构想传达给小组成员，使得它们让全组人员了解，而不仅仅是构架师自己理解。</p>
<p><a name="N10104"><span class="atitle">构架师需要做出决策</span></a></p>
<p>构架师不能在自己不了解的环境中做出决策，然而项目的开发周期也没有给他提供充足的时间去探索所有的环境，所以在很大的压力下做的决策不太可能成功。这种环境是被期望的，成功的构架师非常满意这种环境，而不愿去改变它。因此构架师需要是厚脸皮的，因为他们很可能在项目开发过程中更正自己的决定，并且按原路返回查找问题。正如Philippe Kruchten所说的：&#8220;软件构架师的一生是一个漫长的，在黑暗中不断摸索并不断改进自己的决定的过程&#8221;。<a href="#notes"> <sup>5</sup> </a></p>
<p>一个糟糕的决策很可能毁掉一个项目。项目小组中的其他成员会对构架师失去信心，这时项目经理就要参与进来，因为等待构架的完善不会让项目有所进展。最危险的情况是：如果构架师没有把自己的决策文档化，那么小组的其它成员可能会自己制定决策，而这种决定很可能是错误的。</p>
<p><a name="N10118"><span class="atitle">软件构架师需要觉察组织的政策</span></a></p>
<p>一个成功的构架师不会只关心技术问题，他们还会关心组织的权力动向，时刻了解团队的决定权在哪里。这可以保证他们正在和正确的人讨论项目的决策问题。忽略团队的权力是天真的想法。现实往往是这样的：团队经常会强迫项目小组在规定时间交付系统，这需要构架师正确的评估到这个时间。</p>
<p><a name="N10122"><span class="atitle">软件构架师是一个谈判代表</span></a></p>
<p>为了了解软件构架的很多尺度问题，构架师需要随时和投资人沟通。这种沟通常常需要谈判技巧。例如，构架师需要特别注意的一件事是：最小化项目中可能出现的风险，因为这直接关系到系统构架的稳定性。由于风险是和需求紧密相连的，所以可以通过移除或者减小这方面的需求来降低风险。因此把这种需求取消，需要构架师和投资人达成共识的。这就需要构架师是一个有效的谈判人员，来权衡这些问题。</p>
<p><a name="N1012C"><span class="atitle">总结 </span></a></p>
<p>这篇文章介绍了软件构架师的一些工作。这个系列中的下几篇将介绍软件构架过程的特性，以及把软件构架作为IT资产的基础处理的好处。</p>
<p><a name="N10136"><span class="atitle">鸣谢 </span></a></p>
<p>这篇文章来源于下面这本书，书名暂定为：&#8220;软件构架构建的过程&#8221;；下面我要感谢为这篇文章中作注释的人员：Grady Booch，Dave Braines，Alan Brown，Mark Dickson，Luan Doan-Minh，Holger Heuss，Kelli Houston，Philippe Kruchten，Nick Rozanski，Dave Williams以及Eoin Woods。<br />
<br />
文章来自：<a href="http://www.ibm.com/developerworks/cn/rational/rationaledge/content/apr06/eeles/">http://www.ibm.com/developerworks/cn/rational/rationaledge/content/apr06/eeles/</a></p>
<img src ="http://www.blogjava.net/freeman1984/aggbug/334233.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2010-10-10 23:45 <a href="http://www.blogjava.net/freeman1984/archive/2010/10/10/334233.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>