﻿<?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-Tin's Blog-随笔分类-Spring相关</title><link>http://www.blogjava.net/iamtin/category/7426.html</link><description>You are coming a long way, baby~Thinking, feeling, memory...</description><language>zh-cn</language><lastBuildDate>Mon, 17 Sep 2007 18:34:30 GMT</lastBuildDate><pubDate>Mon, 17 Sep 2007 18:34:30 GMT</pubDate><ttl>60</ttl><item><title>大型Java Web项目的架构和部署调优问题</title><link>http://www.blogjava.net/iamtin/archive/2007/09/17/java_web_architecture_and_performance_turnning.html</link><dc:creator>Tin</dc:creator><author>Tin</author><pubDate>Mon, 17 Sep 2007 14:48:00 GMT</pubDate><guid>http://www.blogjava.net/iamtin/archive/2007/09/17/java_web_architecture_and_performance_turnning.html</guid><wfw:comment>http://www.blogjava.net/iamtin/comments/146003.html</wfw:comment><comments>http://www.blogjava.net/iamtin/archive/2007/09/17/java_web_architecture_and_performance_turnning.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/iamtin/comments/commentRss/146003.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/iamtin/services/trackbacks/146003.html</trackback:ping><description><![CDATA[<img height="44" alt="" src="http://www.infoq.com/styles/cn/i/logo.gif" width="140" border="0" /> 本文已经发表于InfoQ中文站，（<a href="http://www.infoq.com/cn/news/2007/09/java_web_architecture_turnning">大型Java Web项目的架构和部署问题</a>）<br />
<style>
blockquote {background:#eee;font-size:12px;}
</style>
<p>一位ID是jackson1225的网友在javaeye询问了<a title="一个大型Web系统的架构和部署选型问题" href="http://www.javaeye.com/topic/117564?page=1" target="_blank">一个大型Web系统的架构和部署选型问题</a>，希望能提高现有的基于Java的Web应用的服务能力。由于架构模式和部署调优一直是Java社区的热门话题，这个问题引发了很多热心网友的讨论，其中一些意见对其它大型Web项目也有很好的指导意义。在讨论之初jackson1225这样描述了当前的应用的架构和部署方案：</p>
<blockquote>
<p>目前系统架构如下:</p>
<ol>
    <li>web层采用struts+tomcat实现，整个系统采用20多台web服务器，其负载均衡采用硬件F5来实现；
    <li>中间层采用无状态会话Bean+DAO+helper类来实现，共3台weblogic服务器，部署有多个EJB，其负载均衡也采用F5来实现；
    <li>数据库层的操作是自己写的通用类实现的，两台ORACLE数据库服务器，分别存放用户信息和业务数据；一台SQL SERVER数据库，是第三方的业务数据信息； </li>
</ol>
<p>web层调用EJB远程接口来访问中间件层。web层首先通过一个XML配置文件中配置的EJB接口信息来调用相应的EJB远程接口；</p>
<p>该系统中一次操作涉及到两个ORACLE库以及一个SQL SERVER库的访问和操作，即有三个数据库连接，在一个事务中完成。</p>
</blockquote>
<p>这样的架构其实很多公司都在使用，因为Struts和Tomcat分别是最流行的Java Web MVC框架和Servlet容器，而F5公司的负载均衡是横向扩展常见的解决方案（例如配置session sticky方案）。由于这个系统中有跨数据源的事务，所以使用Weblogic Server EJB容器和支持两阶段提交的数据库驱动就可以保证跨数据源的事物完整性（当然，容器管理的分布式事务并非是唯一和最优的解决方案）。</p>
<p>但是随着Rod Johnson重量级的著作《J2EE Development without EJB》和其中的Spring框架的流行，轻量级框架和轻量级容器的概念已经深入人心。所以对于jackson1225提出的这个场景，大多数网友都提出了置疑，认为这个系统滥用了技术，完全是在浪费钱。网友们大都认为SLSB（无状态会话Bean）完全没有必要出现在这个场景中，认为SLSB通过远程接口访问本地资源会有很大的性能开销，这种观点也是Rod johnson在without EJB中批判EJB 2.x中的一大反模式。</p>
<p>由于JavaEE是一个以模式见长的解决方案，模式和架构在JavaEE中占有很重要的地位，所以很多业内专家也都警惕&#8220;反模式（Anti-patterns）&#8221;的出现。对于上面所述的方案是否是反模式，jackson1225马上站出来申辩：</p>
<blockquote>
<p>我们项目就是把EJB作为一个Facade，只是提供给WEB层调用的远程接口，而且只用了无状态会话Bean，所以性能上还可以的。</p>
</blockquote>
<p>这个解释很快得到了一些网友的认可，但是大家很快意识到架构的好坏决定于是否能够满足用户的需求，davexin（可能是jackson1225的同事）描述了这个系统的用户和并发情况：</p>
<blockquote>
<p>现在有用户4000万，马上要和另一个公司的会员系统合并，加起来一共有9000万用户。数据量单表中有一亿条以上的数据。这是基本的情况，其实我觉得现在的架构还是可以的，现在支持的并发大概5000并发用户左右，接下来会进行系统改造，目标支持1万个并发用户。</p>
</blockquote>
<p>具体的并发量公布后又有网友置疑这个数据，认为这个系统的Servlet容器支持的并发数太小，怀疑是否配置不够优化。davexin又补充了该项目的服务器配置：</p>
<blockquote>
<p>系统前端tomcat都是用的刀片，配置在2G内存，cpu大概在2.0G，每台机器也就支持250-400个并发，再多的话，就会相应时间非常的常，超过20秒，失去了意义 ，所以我们才得出这样的结论的。</p>
</blockquote>
<p>一位ID是cauherk的网友提出了比较中肯的意见，他没有从Web容器单纯的并发支持能力上提出改进方案，而是提出了对于类似的应用的<a title="一些通用的改进提示" href="http://www.javaeye.com/topic/117564?page=4#368432" target="_blank">一些通用的改进提示</a>，这里摘要一下：</p>
<blockquote>
<ol>
    <li>数据库压力问题
    <p>可以按照业务、区域等等特性对数据库进行配置，可以考虑分库、使用rac、分区、分表等等策略，确保数据库能正常的进行交易。</p>
    <li>事务问题
    <p>要在两个数据库中操作，那么必须考虑到分布式事务。你应该仔细的设计你的系统，来避免使用分布式事务，以避免分布式事务带来更多的数据库压力和其它问题。推荐你采用延迟提交的策略(并不保证数据的完整)，来避免分布式事务的问题，毕竟commit失败的几率很低。</p>
    <li>web的优化
    <p>将静态、图片独立使用不同的服务器，对于常态的静态文件，采用E-TAG或者客户端缓存， google很多就是这样干的。对于热点的功能，考虑使用完全装载到内存，保证绝对的响应速度，对于需要频繁访问的热点数据，采用集中缓存(多个可以采用负载均衡)，减轻数据库的压力。</p>
    <p>对于几乎除二进制文件，都应该在L4上配置基于硬件的压缩方案，减少网络的流量。提高用户使用的感知。</p>
    <li>网络问题
    <p>可以考虑采用镜像、多路网络接入、基于DNS的负载均衡。如果有足够的投资，可以采用CDN(内容分发网)，减轻你的服务器压力。</p>
    </li>
</ol>
</blockquote>
<p>cauherk的这个分析比较到位，其中ETags的方案是最近的一个热点，InfoQ的&#8220;<a title="使用ETags减少Web应用带宽和负载" href="http://www.infoq.com/cn/articles/etags" target="_blank">使用ETags减少Web应用带宽和负载</a>&#8221;里面对这种方案有很详细的介绍。一般以数据库为中心的Web应用的性能瓶颈都在数据库上，所以cauherk把数据库和事务问题放到了前两位来讨论。但是davexin解释在所讨论的这个项目中数据库并非瓶颈：</p>
<blockquote>
<p>我们的压力不在数据库层，在web层和F5。 当高峰的时候 ，F5也被点死了，就是每秒点击超过30万，web动态部分根本承受不了。根据我们程序记录，20台web最多承受5000个并发，如果再多，tomcat就不响应了。就像死了一样。</p>
</blockquote>
<p>这个回复让接下来的讨论都集中于Web容器的性能优化，但是<a title="JavaEye站长robbin发表了自己的意见" href="http://www.javaeye.com/topic/117564?page=5#369868" target="_blank">JavaEye站长robbin发表了自己的意见</a>，将话题引回了这个项目的架构本身：</p>
<blockquote>
<p><strong>performance tuning最重要的就是定位瓶颈在哪里，以及瓶颈是怎么产生的。</strong></p>
<p><strong>我的推测是瓶颈还是出在EJB远程方法调用上！</strong></p>
<p>tomcat上面的java应用要通过EJB远程方法调用，来访问weblogic上面的无状态SessionBean，这样的远程方法调用一般都在100ms~500ms级别，或者更多。而如果没有远程方法调用，即使大量采用spring的动态反射，一次完整的web请求处理在本地JVM内部的完成时间一般也不过20ms而已。一次web请求需要过长的执行时间，就会导致servlet线程被占用更多的时间，从而无法及时响应更多的后续请求。</p>
<p>如果这个推测是成立的话，那么我的建议就是既然你没有用到分布式事务，那么就干脆去掉EJB。weblogic也可以全部撤掉，业务层使用spring取代EJB，不要搞分布式架构，在每个tomcat实例上面部署一个完整的分层结构。</p>
<p>另外在高并发情况下，apache处理静态资源也很耗内存和CPU，可以考虑用轻量级web server如lighttpd/litespeed/nginx取代之。</p>
</blockquote>
<p>robbin的推断得到了网友们的支持，davexin也认同robbin的看法，但是他解释说<a title="公司认为放弃SLSB存在风险" href="http://www.javaeye.com/topic/117564?page=6#370089" target="_blank">公司认为放弃SLSB存在风险</a>，所以公司倾向于通过将Tomcat替换为Weblogic Server 10来提升系统的用户支撑能力。<a title="robbin则马上批评了这种做法" href="http://www.javaeye.com/topic/117564?page=6#370107" target="_blank">robbin则马上批评了这种做法</a>：</p>
<blockquote>
<p>坦白说我还从来没有听说过大规模互联网应用使用EJB的先例。为什么大规模互联网应用不能用EJB，其实就是因为EJB性能太差，用了EJB几乎必然出现性能障碍。</p>
<p>web容器的性能说到底无非就是Servlet线程调度能力而已，Tomcat不像WebLogic那样附加n多管理功能，跑得快很正常。对比测试一下WebLogic的数据库连接池和C3P0连接池的性能也会发现类似的结论，C3P0可要比WebLogic的连接池快好几倍了。这不是说WebLogic性能不好，只不过weblogic要实现更多的功能，所以在单一的速度方面就会牺牲很多东西。</p>
<p>以我的经验来判断，使用tomcat5.5以上的版本，配置apr支持，进行必要的tuning，使用BEA JRockit JVM的话，在你们目前的刀片上面，支撑500个并发完全是可以做到的。结合你们目前20个刀片的硬件，那么达到1万并发是没问题的。当然这样做的前提是必须扔掉EJB，并置web层和业务层在同一个JVM内部。</p>
</blockquote>
<p>接下来robbin还针对davexin对话题中的应用分别在tomcat和weblogic上的测试数据进行了分析：</p>
<blockquote>引用：
<blockquote>
<p>2。1台weblogic10 Express（相当于1台tomcat，用于发布jsp应用）加1台weblogic10（发布ejb应用），能支持1000个并发用户......<br />
......<br />
4。1台tomcat4.1加1台weblogic8，只能支持350个并发用户，tomcat就连结超时，说明此种结构瓶颈在tomcat。 </p>
</blockquote>
<p>这说明瓶颈还不在EJB远程调用上，但是问题已经逐渐清楚了。为什么weblogic充当web容器发起远程EJB调用的时候可以支撑1000个并发，但是tomcat只能到350个？只有两个可能的原因：</p>
<p>
<ol>
    <li>你的tomcat没有配置好，严重影响了性能表现
    <li>tomcat和weblogic之间的接口出了问题 </li>
</ol>
<p>&nbsp;</p>
</blockquote>
<p>接着springside项目发起者江南白衣也提出了一个总体的优化指导：</p>
<blockquote>
<p>1.基础配置优化</p>
<p>tomcat 6？ tomcat参数调优?<br />
JRockit JVM? JVM参数调优？<br />
Apache+Squid 处理静态内容？ </p>
<p>2.业务层优化</p>
<p>部分功能本地化，而不调remote session bean?<br />
异步提交操作,JMS？<br />
cache热点数据？ </p>
<p>3.展示层优化</p>
<p>动态页面发布为静态页面？<br />
Cache部分动态页面内容？ </p>
</blockquote>
<p>davexin在调整了Tomcat配置后应验了robbin对tomcat配置问题的质疑，davexin这样描述经过配置优化以后的测试结果：</p>
<blockquote>
<p>经过测试，并发人数是可以达到像robbin所说的一样，能够在600人左右，如果压到并发700人，就有15%左右的失败，虽然在调整上面参数之后，并发人数上去了，但是在同样的时间内所完成的事务数量下降了10%左右，并且响应时间延迟了1秒左右，但从整体上来说，牺牲一点事务吞吐量和响应时间，并发人数能够提高500，觉得还是值得的。</p>
</blockquote>
<p>至此这个话题有了一个比较好的结果。这个话题并非完全针对一个具体的项目才有意义，更重要的是在分析和讨论问题的过程中网友们解决问题的思路，尤其是cauherk、robbin、江南白衣等几位网友提出的意见可以让广大Java Web项目开发者了解到中、大型项目所需要考虑的架构和部署所需要考虑的关键问题，也消除了很多人对轻量Servlet容器与EJB容器性能的一些误解。</p>
<p>在讨论中还有一些小插曲，如davexin和江南白衣讨论了<a title="JRocket的实时（Realtime）版本是否可以提升Servlet容器的相应能力" href="http://www.javaeye.com/topic/117564?page=8#371197" target="_blank">JRocket的实时（Realtime）版本是否可以提升Servlet容器的相应能力</a>，答案是不可以。还有ID为mfc42d的网友从Servlet容器的并发支持能力引申到了<a title="Java的线程调度能力和NIO对Servelet容器的意义" href="http://www.javaeye.com/topic/117564?page=8#377459" target="_blank">Java的线程调度能力和NIO对Servelet容器的意义</a>，他推荐了自己的两篇不错的blog&#8220;<a title="java的线程实现" href="http://blogger.org.cn/blog/more.asp?name=hongrui&amp;id=25175" target="_blank">java的线程实现</a>&#8221;和&#8220;<a title="java进程使用的最大内存的数值" href="http://blogger.org.cn/blog/more.asp?name=hongrui&amp;id=23973" target="_blank">java进程使用的最大内存的数值</a>&#8221;，blog文章里面从JVM源码级别分析了Java的线程支持能力，面临JVM性能调优问题的网友可以认真阅读一下。</p>
<img src ="http://www.blogjava.net/iamtin/aggbug/146003.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/iamtin/" target="_blank">Tin</a> 2007-09-17 22:48 <a href="http://www.blogjava.net/iamtin/archive/2007/09/17/java_web_architecture_and_performance_turnning.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Spring与EJB 3对比读后感</title><link>http://www.blogjava.net/iamtin/archive/2006/09/04/67672.html</link><dc:creator>Tin</dc:creator><author>Tin</author><pubDate>Mon, 04 Sep 2006 12:45:00 GMT</pubDate><guid>http://www.blogjava.net/iamtin/archive/2006/09/04/67672.html</guid><wfw:comment>http://www.blogjava.net/iamtin/comments/67672.html</wfw:comment><comments>http://www.blogjava.net/iamtin/archive/2006/09/04/67672.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/iamtin/comments/commentRss/67672.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/iamtin/services/trackbacks/67672.html</trackback:ping><description><![CDATA[今天TSS和InfoQ都转了一篇Spring与EJB3的读后感，我就看了下，标题和介绍满吸引人的。内容嘛其实有点不过瘾，但是先记录下来吧。<br /><a href="http://www.devx.com/Java/Article/32314/0/page/1">http://www.devx.com/Java/Article/32314/0/page/1</a><br /><br />总的来看Spring+Hibernate与JPA很相似，它们都是基于pojo的持久化。<br />Hibernate Session和JPA Entity Manager基本上等价，但是要记住他们的两个重要区别。Hibernate session是一个实体缓存也是一个ORM引擎的接口。而JPA中这两个概念是分开的。Persistence context作为缓存而entity manager则作为ORM引擎的接口。<br />当然还有显而易见的区别，Spring+Hibernate偏向使用XML配置映射，而JPA偏向使用Annotation，虽然两者都有XML和注释两种实现。<br />还有，JPA是一个标准，而Spring是对不同实现的抽象，两者的方向是不同的。JPA的方式更彻底，Java传统中都是这样的。<br />JPA的主要商业实现有Hibernate、Kodo、Toplink，被巨鳄们看好。<br />后面，说到了关于Cache和Transaction管理的问题，由于Spring的草根特性，为了兼容实现，它使用Tread local这种编程式的方式。而EJB 3.0则由容器自动完成这些过程。而且EJB 3.0提供了不同的persistence context范畴，可以比较方便的管理持久数据的生命周期。不过，这个观点很难说，因为如果你把Spring也看成一种容器，那么这Thread local对于你来说也是透明的，可以认为差不多。<br />关于EJB 3.0对生命周期的规定，让持久化的概念更清楚了，如果这些东西能够通过声明而不是编码来实现应该是惬意的，可是，问题就是很多程序员一般就喜欢自己控制，不喜欢那么透明，所以EJB一直以来兴建的这些漂亮模型总是只有少数人使用，不是么？<br />在事务方面，由于两者都支持生命性事务，所以程序本身看起来基本一样。<br />区别在于配置。Spring还是偏向XML，并且事务作为Spring对AOP应用的经典样例，transaction完全作为附加语义，可以通过配置替换各种事务实现，从JDBC、Hibernate到JTA，显然这是从编程者角度考虑的，门槛很低。<br />而EJB 3.0则只支持JTA，这就需要容器的支持，当然跨多资源的事务往往是企业级项目的特性，所以这种思路可以理解。而且现在也有很多开源的JTA实现了，它们完全可以让你的应用在商业EJB容器外运行。还要提一点，EJB3默认是配置上事务的，需要声明才可覆盖，这说明了EJB3对于企业应用的态度。<br />在JTA事务可以通过声明就以横切关注点的形势注入的时候，JTA的成本已经下降了，所以一开始就用这种API完全可行。<br />这篇文章中关于状态的地方我有点不太理解，里面说Spring的prototype等价于EJB的SFSBs，实现stateful。<br />EJB 3.0在这方面无疑是强大的，因为本身在这方面它就是个容器规范，Java EE容器都会提供这种高级的生命周期管理，并且把生命周期作为变成模型中非常重要的一部分。所以结果就是EJB 3.0在这方面领先于Spring，声名简单，并且从实现的方式上来说，EJB 3.0在性能上和可伸缩性上有明显的优势。Spring在性能伸缩或者说分布部署的时候应该说是捉襟见肘的，Terracotta也许可以解决些，但还……<br />应该说，实际上Spring提供的prototype就是new的另外一种实现，只不过它会经过Spring装配，所以它叫做prototype，也就是“原型”，Spring每次回new出一个新的，按你的要求。当然，由于是类似new，所以Spring通过代理的方式管理起生命周期，也就能模拟出session、request、global session的statefull，不过这些功能显然不算强项，在Spring 2.0中加强了（以前只有singleton和prototype），但依然不支持事务范畴，这就明显不如EJB 3.0了。但是，回想Spring的编程哲学，它不要解决这种问题，这种问题留给容器解决:D<br />文章最后的总结比较官腔，基本上就是在说Spring灵活，EJB 3.0强大简单，它们各有优缺点，所以应该结合起来使用，具体大家可以看看原文。<img src ="http://www.blogjava.net/iamtin/aggbug/67672.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/iamtin/" target="_blank">Tin</a> 2006-09-04 20:45 <a href="http://www.blogjava.net/iamtin/archive/2006/09/04/67672.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Webwork 2.2的Action是否使用Spring的prototype­获取的性能对比</title><link>http://www.blogjava.net/iamtin/archive/2006/02/14/30699.html</link><dc:creator>Tin</dc:creator><author>Tin</author><pubDate>Tue, 14 Feb 2006 13:48:00 GMT</pubDate><guid>http://www.blogjava.net/iamtin/archive/2006/02/14/30699.html</guid><wfw:comment>http://www.blogjava.net/iamtin/comments/30699.html</wfw:comment><comments>http://www.blogjava.net/iamtin/archive/2006/02/14/30699.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/iamtin/comments/commentRss/30699.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/iamtin/services/trackbacks/30699.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 本文在060216进行了修改，因为发现了测试中的错误！注意5.5和7的内容。1、引子：其实是ajoo的这篇“Nuts和Spring 1.2.6 效率对比”和“IoC容器的prototype性能测试 ”，他们在Javaeye上详细讨论了Spring的prototype的缺陷。Spring的prototype指的就是singleton="false"的bean，具体可以看Spring参考手册“3.2....&nbsp;&nbsp;<a href='http://www.blogjava.net/iamtin/archive/2006/02/14/30699.html'>阅读全文</a><img src ="http://www.blogjava.net/iamtin/aggbug/30699.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/iamtin/" target="_blank">Tin</a> 2006-02-14 21:48 <a href="http://www.blogjava.net/iamtin/archive/2006/02/14/30699.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>