<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
  <channel>
    <title>tianshi0253</title>
    <description></description>
    <link>http://tianshi0253.javaeye.com</link>
    <language>UTF-8</language>
    <copyright>Copyright 2003-2008, JavaEye.com</copyright>
    <docs>http://blogs.law.harvard.edu/tech/rss</docs>
    <generator>JavaEye - 做最棒的软件开发交流社区</generator>
      <item>
        <title>一个switch判断的问题</title>
        <author>tianshi0253</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://tianshi0253.javaeye.com">tianshi0253</a>&nbsp;
          链接：<a href="http://tianshi0253.javaeye.com/blog/230186" style="color:red;">http://tianshi0253.javaeye.com/blog/230186</a>&nbsp;
          发表时间: 2008年08月19日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <pre name="code" class="js">var msg="\nswitch流程控制语句 : \n\n";

//响应按钮的onclick事件处理程序
function Test()
{
  var army ;
  var year=window. prompt("请输入您的军龄(整数值,0表示未参军) :",25);
  
  switch(parseInt(year))
  {
    case 0:
    	
      army="平民";
      //alert(army);
      break;
    case 1:
      army="列兵";
      break;
    case 2:
      army="上等兵";
      break;
    case 3:
    case 4:
    case 5:
      army="一级士官";
      break;
    case 6:
    case 7:
    case 8:
      army="二级士官";
      break;
    default:
      if (year&gt;8)
        army="中高级士官";
  }
  msg+="军龄 : "+year+"年\n";
  msg+="结论 : "+army+"\n";
  alert(msg);
}</pre>
<p><strong><span style="font-size: medium; color: #ff0000;">&nbsp;其中，year在使用时应转换为整型。</span></strong></p>
          <br/>
          <span style="color:red;">
            <a href="http://tianshi0253.javaeye.com/blog/230186#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Tue, 19 Aug 2008 16:14:50 +0800</pubDate>
        <link>http://tianshi0253.javaeye.com/blog/230186</link>
        <guid>http://tianshi0253.javaeye.com/blog/230186</guid>
      </item>
      <item>
        <title>一个23设计模式的搞笑解释</title>
        <author>tianshi0253</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://tianshi0253.javaeye.com">tianshi0253</a>&nbsp;
          链接：<a href="http://tianshi0253.javaeye.com/blog/230088" style="color:red;">http://tianshi0253.javaeye.com/blog/230088</a>&nbsp;
          发表时间: 2008年08月19日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p><strong>创建型模式 <br /><br />1、FACTORY </strong>&mdash;追MM少不了请吃饭了，麦当劳的鸡翅和肯德基的鸡翅都是MM爱吃的东西，虽然口味有所不同，但不管你带MM去麦当劳或肯德基，只管向服务员说&ldquo;来四个鸡翅&rdquo;就行了。麦当劳和肯德基就是生产鸡翅的Factory <br /><br /><strong>工厂模式</strong>：客户类和工厂类分开。消费者任何时候需要某种产品，只需向工厂请求即可。消费者无须修改就可以接纳新产品。缺点是当产品修改时，工厂类也要做相应的修改。如：如何创建及如何向客户端提供。 <br /><br /><strong>2</strong><strong>、BUILDER&nbsp;&nbsp;</strong>&mdash;MM最爱听的就是&ldquo;我爱你&rdquo;这句话了，见到不同地方的MM,要能够用她们的方言跟她说这句话哦，我有一个多种语言翻译机，上面每种语言都有一个按键，见到MM我只要按对应的键，它就能够用相应的语言说出&ldquo;我爱你&rdquo;这句话了，国外的MM也可以轻松搞掂，这就是我的&ldquo;我爱你&rdquo;builder。（这一定比美军在伊拉克用的翻译机好卖） <br /><br /><strong>建造模式</strong>：将产品的内部表象和产品的生成过程分割开来，从而使一个建造过程生成具有不同的内部表象的产品对象。建造模式使得产品内部表象可以独立的变化，客户不必知道产品内部组成的细节。建造模式可以强制实行一种分步骤进行的建造过程。 <br /><br /><strong>3</strong><strong>、FACTORY METHOD</strong> &mdash;请MM去麦当劳吃汉堡，不同的MM有不同的口味，要每个都记住是一件烦人的事情，我一般采用Factory Method模式，带着MM到服务员那儿，说&ldquo;要一个汉堡&rdquo;，具体要什么样的汉堡呢，让MM直接跟服务员说就行了。 <br /><br /><strong>工厂方法模式</strong>：核心工厂类不再负责所有产品的创建，而是将具体创建的工作交给子类去做，成为一个抽象工厂角色，仅负责给出具体工厂类必须实现的接口，而不接触哪一个产品类应当被实例化这种细节。 <br /><br /><strong>4</strong><strong>、PROTOTYPE</strong> &mdash;跟MM用QQ聊天，一定要说些深情的话语了，我搜集了好多肉麻的情话，需要时只要copy出来放到QQ里面就行了，这就是我的情话prototype了。（100块钱一份，你要不要） <br /><br /><strong>原始模型模式</strong>：通过给出一个原型对象来指明所要创建的对象的类型，然后用复制这个原型对象的方法创建出更多同类型的对象。原始模型模式允许动态的增加或减少产品类，产品类不需要非得有任何事先确定的等级结构，原始模型模式适用于任何的等级结构。缺点是每一个类都必须配备一个克隆方法。 <br /><br /><strong>5</strong><strong>、SINGLETON</strong> &mdash;俺有6个漂亮的老婆，她们的老公都是我，我就是我们家里的老公Sigleton，她们只要说道&ldquo;老公&rdquo;，都是指的同一个人，那就是我(刚才做了个梦啦，哪有这么好的事) <br /><br /><strong>单例模式</strong>：单例模式确保某一个类只有一个实例，而且自行实例化并向整个系统提供这个实例单例模式。单例模式只应在有真正的&ldquo;单一实例&rdquo;的需求时才可使用。 <br /><br /><strong>结构型模式 </strong><br /><br /><strong>6</strong><strong>、ADAPTER</strong> &mdash;在朋友聚会上碰到了一个美女Sarah，从香港来的，可我不会说粤语，她不会说普通话，只好求助于我的朋友kent了，他作为我和Sarah之间的Adapter，让我和Sarah可以相互交谈了(也不知道他会不会耍我) <br /><br /><strong>适配器模式</strong>：把一个类的接口变换成客户端所期待的另一种接口，从而使原本因接口原因不匹配而无法一起工作的两个类能够一起工作。适配类可以根据参数返还一个合适的实例给客户端。 <br /><br /><strong>7</strong><strong>、BRIDGE </strong>&mdash;早上碰到MM，要说早上好，晚上碰到MM，要说晚上好；碰到MM穿了件新衣服，要说你的衣服好漂亮哦，碰到MM新做的发型，要说你的头发好漂亮哦。不要问我&ldquo;早上碰到MM新做了个发型怎么说&rdquo;这种问题，自己用BRIDGE组合一下不就行了 <br /><br /><strong>桥梁模式</strong>：将抽象化与实现化脱耦，使得二者可以独立的变化，也就是说将他们之间的强关联变成弱关联，也就是指在一个软件系统的抽象化和实现化之间使用组合/聚合关系而不是继承关系，从而使两者可以独立的变化。 <br /><br /><strong>8</strong><strong>、COMPOSITE</strong> &mdash;Mary今天过生日。&ldquo;我过生日，你要送我一件礼物。&rdquo;&ldquo;嗯，好吧，去商店，你自己挑。&rdquo;&ldquo;这件T恤挺漂亮，买，这条裙子好看，买，这个包也不错，买。&rdquo;&ldquo;喂，买了三件了呀，我只答应送一件礼物的哦。&rdquo;&ldquo;什么呀，T恤加裙子加包包，正好配成一套呀，小姐，麻烦你包起来。&rdquo;&ldquo;&hellip;&hellip;&rdquo;，MM都会用Composite模式了，你会了没有？ <br /><br /><strong>合成模式</strong>：合成模式将对象组织到树结构中，可以用来描述整体与部分的关系。合成模式就是一个处理对象的树结构的模式。合成模式把部分与整体的关系用树结构表示出来。合成模式使得客户端把一个个单独的成分对象和由他们复合而成的合成对象同等看待。 <br /><br /><strong>9</strong><strong>、DECORATOR </strong>&mdash;Mary过完轮到Sarly过生日，还是不要叫她自己挑了，不然这个月伙食费肯定玩完，拿出我去年在华山顶上照的照片，在背面写上&ldquo;最好的的礼物，就是爱你的Fita&rdquo;，再到街上礼品店买了个像框（卖礼品的MM也很漂亮哦），再找隔壁搞美术设计的Mike设计了一个漂亮的盒子装起来&hellip;&hellip;，我们都是Decorator，最终都在修饰我这个人呀，怎么样，看懂了吗？ <br /><br /><strong>装饰模式</strong>：装饰模式以对客户端透明的方式扩展对象的功能，是继承关系的一个替代方案，提供比继承更多的灵活性。动态给一个对象增加功能，这些功能可以再动态的撤消。增加由一些基本功能的排列组合而产生的非常大量的功能。 <br /><br /><strong>10</strong><strong>、FA&Ccedil;ADE</strong> &mdash;我有一个专业的Nikon相机，我就喜欢自己手动调光圈、快门，这样照出来的照片才专业，但MM可不懂这些，教了半天也不会。幸好相机有Facade设计模式，把相机调整到自动档，只要对准目标按快门就行了，一切由相机自动调整，这样MM也可以用这个相机给我拍张照片了。 <br /><br /><strong>门面模式</strong>：外部与一个子系统的通信必须通过一个统一的门面对象进行。门面模式提供一个高层次的接口，使得子系统更易于使用。每一个子系统只有一个门面类，而且此门面类只有一个实例，也就是说它是一个单例模式。但整个系统可以有多个门面类。 <br /><br /><strong>11</strong><strong>、FLYWEIGHT</strong> &mdash;每天跟MM发短信，手指都累死了，最近买了个新手机，可以把一些常用的句子存在手机里，要用的时候，直接拿出来，在前面加上MM的名字就可以发送了，再不用一个字一个字敲了。共享的句子就是Flyweight，MM的名字就是提取出来的外部特征，根据上下文情况使用。 <br /><br /><strong>享元模式</strong>：FLYWEIGHT在拳击比赛中指最轻量级。享元模式以共享的方式高效的支持大量的细粒度对象。享元模式能做到共享的关键是区分内蕴状态和外蕴状态。内蕴状态存储在享元内部，不会随环境的改变而有所不同。外蕴状态是随环境的改变而改变的。外蕴状态不能影响内蕴状态，它们是相互独立的。将可以共享的状态和不可以共享的状态从常规类中区分开来，将不可以共享的状态从类里剔除出去。客户端不可以直接创建被共享的对象，而应当使用一个工厂对象负责创建被共享的对象。享元模式大幅度的降低内存中对象的数量。 <br /><br /><strong>12</strong><strong>、PROXY </strong>&mdash;跟MM在网上聊天，一开头总是&ldquo;hi,你好&rdquo;,&ldquo;你从哪儿来呀？&rdquo;&ldquo;你多大了？&rdquo;&ldquo;身高多少呀？&rdquo;这些话，真烦人，写个程序做为我的Proxy吧，凡是接收到这些话都设置好了自动的回答，接收到其他的话时再通知我回答，怎么样，酷吧。 <br /><br /><strong>代理模式</strong>：代理模式给某一个对象提供一个代理对象，并由代理对象控制对源对象的引用。代理就是一个人或一个机构代表另一个人或者一个机构采取行动。某些情况下，客户不想或者不能够直接引用一个对象，代理对象可以在客户和目标对象直接起到中介的作用。客户端分辨不出代理主题对象与真实主题对象。代理模式可以并不知道真正的被代理对象，而仅仅持有一个被代理对象的接口，这时候代理对象不能够创建被代理对象，被代理对象必须有系统的其他角色代为创建并传入。 <br /><br /><strong>行为模式 </strong><strong><br /></strong><br /><strong>13</strong><strong>、CHAIN OF RESPONSIBLEITY</strong> &mdash;晚上去上英语课，为了好开溜坐到了最后一排，哇，前面坐了好几个漂亮的MM哎，找张纸条，写上&ldquo;Hi,可以做我的女朋友吗？如果不愿意请向前传&rdquo;，纸条就一个接一个的传上去了，糟糕，传到第一排的MM把纸条传给老师了，听说是个老处女呀，快跑! <br /><br /><strong>责任链模式</strong>：在责任链模式中，很多对象由每一个对象对其下家的引用而接起来形成一条链。请求在这个链上传递，直到链上的某一个对象决定处理此请求。客户并不知道链上的哪一个对象最终处理这个请求，系统可以在不影响客户端的情况下动态的重新组织链和分配责任。处理者有两个选择：承担责任或者把责任推给下家。一个请求可以最终不被任何接收端对象所接受。 <br /><br /><strong>14</strong><strong>、COMMAND</strong> &mdash;俺有一个MM家里管得特别严，没法见面，只好借助于她弟弟在我们俩之间传送信息，她对我有什么指示，就写一张纸条让她弟弟带给我。这不，她弟弟又传送过来一个COMMAND，为了感谢他，我请他吃了碗杂酱面，哪知道他说：&ldquo;我同时给我姐姐三个男朋友送COMMAND，就数你最小气，才请我吃面。&rdquo;， <br /><br /><strong>命令模式</strong>：命令模式把一个请求或者操作封装到一个对象中。命令模式把发出命令的责任和执行命令的责任分割开，委派给不同的对象。命令模式允许请求的一方和发送的一方独立开来，使得请求的一方不必知道接收请求的一方的接口，更不必知道请求是怎么被接收，以及操作是否执行，何时被执行以及是怎么被执行的。系统支持命令的撤消。 <br /><br /><strong>15</strong><strong>、INTERPRETER</strong> &mdash;俺有一个《泡MM真经》，上面有各种泡MM的攻略，比如说去吃西餐的步骤、去看电影的方法等等，跟MM约会时，只要做一个Interpreter，照着上面的脚本执行就可以了。 <br /><br /><strong>解释器模式</strong>：给定一个语言后，解释器模式可以定义出其文法的一种表示，并同时提供一个解释器。客户端可以使用这个解释器来解释这个语言中的句子。解释器模式将描述怎样在有了一个简单的文法后，使用模式设计解释这些语句。在解释器模式里面提到的语言是指任何解释器对象能够解释的任何组合。在解释器模式中需要定义一个代表文法的命令类的等级结构，也就是一系列的组合规则。每一个命令对象都有一个解释方法，代表对命令对象的解释。命令对象的等级结构中的对象的任何排列组合都是一个语言。 <br /><br /><strong>16</strong><strong>、ITERATOR</strong> &mdash;我爱上了Mary，不顾一切的向她求婚。 <br />&nbsp;&nbsp; Mary：&ldquo;想要我跟你结婚，得答应我的条件&rdquo; <br />&nbsp;&nbsp; 我：&ldquo;什么条件我都答应，你说吧&rdquo; <br />&nbsp;&nbsp; Mary：&ldquo;我看上了那个一克拉的钻石&rdquo; <br />&nbsp;&nbsp; 我：&ldquo;我买，我买，还有吗？&rdquo; <br />&nbsp;&nbsp; Mary：&ldquo;我看上了湖边的那栋别墅&rdquo; <br />&nbsp;&nbsp; 我：&ldquo;我买，我买，还有吗？&rdquo; <br />&nbsp;&nbsp; Mary：&ldquo;你的小弟弟必须要有50cm长&rdquo; <br />&nbsp;&nbsp; 我脑袋嗡的一声，坐在椅子上，一咬牙：&ldquo;我剪，我剪，还有吗？&rdquo; <br />&nbsp;&nbsp; &hellip;&hellip; <br /><br /><strong>迭代子模式</strong>：迭代子模式可以顺序访问一个聚集中的元素而不必暴露聚集的内部表象。多个对象聚在一起形成的总体称之为聚集，聚集对象是能够包容一组对象的容器对象。迭代子模式将迭代逻辑封装到一个独立的子对象中，从而与聚集本身隔开。迭代子模式简化了聚集的界面。每一个聚集对象都可以有一个或一个以上的迭代子对象，每一个迭代子的迭代状态可以是彼此独立的。迭代算法可以独立于聚集角色变化。 <br /><br /><strong>17</strong><strong>、MEDIATOR</strong><strong> </strong>&mdash;四个MM打麻将，相互之间谁应该给谁多少钱算不清楚了，幸亏当时我在旁边，按照各自的筹码数算钱，赚了钱的从我这里拿，赔了钱的也付给我，一切就OK啦，俺得到了四个MM的电话。 <br /><br /><strong>调停者模式</strong>：调停者模式包装了一系列对象相互作用的方式，使得这些对象不必相互明显作用。从而使他们可以松散偶合。当某些对象之间的作用发生改变时，不会立即影响其他的一些对象之间的作用。保证这些作用可以彼此独立的变化。调停者模式将多对多的相互作用转化为一对多的相互作用。调停者模式将对象的行为和协作抽象化，把对象在小尺度的行为上与其他对象的相互作用分开处理。 <br /><br /><strong>18</strong><strong>、MEMENTO</strong> &mdash;同时跟几个MM聊天时，一定要记清楚刚才跟MM说了些什么话，不然MM发现了会不高兴的哦，幸亏我有个备忘录，刚才与哪个MM说了什么话我都拷贝一份放到备忘录里面保存，这样可以随时察看以前的记录啦。 <br /><br /><strong>备忘录模式</strong>：备忘录对象是一个用来存储另外一个对象内部状态的快照的对象。备忘录模式的用意是在不破坏封装的条件下，将一个对象的状态捉住，并外部化，存储起来，从而可以在将来合适的时候把这个对象还原到存储起来的状态。 <br /><br /><strong>19</strong><strong>、OBSERVER</strong>&nbsp;&nbsp; &mdash;想知道咱们公司最新MM情报吗？加入公司的MM情报邮件组就行了，tom负责搜集情报，他发现的新情报不用一个一个通知我们，直接发布给邮件组，我们作为订阅者（观察者）就可以及时收到情报啦 <br /><br /><strong>观察者模式</strong>：观察者模式定义了一种一队多的依赖关系，让多个观察者对象同时监听某一个主题对象。这个主题对象在状态上发生变化时，会通知所有观察者对象，使他们能够自动更新自己。 <br /><br /><strong>20</strong><strong>、STATE</strong> &mdash;跟MM交往时，一定要注意她的状态哦，在不同的状态时她的行为会有不同，比如你约她今天晚上去看电影，对你没兴趣的MM就会说&ldquo;有事情啦&rdquo;，对你不讨厌但还没喜欢上的MM就会说&ldquo;好啊，不过可以带上我同事么？&rdquo;，已经喜欢上你的MM就会说&ldquo;几点钟？看完电影再去泡吧怎么样？&rdquo;，当然你看电影过程中表现良好的话，也可以把MM的状态从不讨厌不喜欢变成喜欢哦。 <br /><br /><strong>状态模式</strong>：状态模式允许一个对象在其内部状态改变的时候改变行为。这个对象看上去象是改变了它的类一样。状态模式把所研究的对象的行为包装在不同的状态对象里，每一个状态对象都属于一个抽象状态类的一个子类。状态模式的意图是让一个对象在其内部状态改变的时候，其行为也随之改变。状态模式需要对每一个系统可能取得的状态创立一个状态类的子类。当系统的状态变化时，系统便改变所选的子类。 <br /><br /><strong>21</strong><strong>、STRATEGY</strong> &mdash;跟不同类型的MM约会，要用不同的策略，有的请电影比较好，有的则去吃小吃效果不错，有的去海边浪漫最合适，单目的都是为了得到MM的芳心，我的追MM锦囊中有好多Strategy哦。 <br /><br /><strong>策略模式</strong>：策略模式针对一组算法，将每一个算法封装到具有共同接口的独立的类中，从而使得它们可以相互替换。策略模式使得算法可以在不影响到客户端的情况下发生变化。策略模式把行为和环境分开。环境类负责维持和查询行为类，各种算法在具体的策略类中提供。由于算法和环境独立开来，算法的增减，修改都不会影响到环境和客户端。 <br /><br /><strong>22</strong><strong>、TEMPLATE METHOD</strong> &mdash;&mdash;看过《如何说服女生上床》这部经典文章吗？女生从认识到上床的不变的步骤分为巧遇、打破僵局、展开追求、接吻、前戏、动手、爱抚、进去八大步骤(Template method)，但每个步骤针对不同的情况，都有不一样的做法，这就要看你随机应变啦(具体实现)； <br /><br /><strong>模板方法模式</strong>：模板方法模式准备一个抽象类，将部分逻辑以具体方法以及具体构造子的形式实现，然后声明一些抽象方法来迫使子类实现剩余的逻辑。不同的子类可以以不同的方式实现这些抽象方法，从而对剩余的逻辑有不同的实现。先制定一个顶级逻辑框架，而将逻辑的细节留给具体的子类去实现。 <br /><br /><strong>23</strong><strong>、VISITOR</strong> &mdash;情人节到了，要给每个MM送一束鲜花和一张卡片，可是每个MM送的花都要针对她个人的特点，每张卡片也要根据个人的特点来挑，我一个人哪搞得清楚，还是找花店老板和礼品店老板做一下Visitor，让花店老板根据MM的特点选一束花，让礼品店老板也根据每个人特点选一张卡，这样就轻松多了； <br /><br /><strong>访问者模式</strong>：访问者模式的目的是封装一些施加于某种数据结构元素之上的操作。一旦这些操作需要修改的话，接受这个操作的数据结构可以保持不变。访问者模式适用于数据结构相对未定的系统，它把数据结构和作用于结构上的操作之间的耦合解脱开，使得操作集合可以相对自由的演化。访问者模式使得增加新的操作变的很容易，就是增加一个新的访问者类。访问者模式将有关的行为集中到一个访问者对象中，而不是分散到一个个的节点类中。当使用访问者模式时，要将尽可能多的对象浏览逻辑放在访问者类中，而不是放到它的子类中。访问者模式可以跨过几个类的等级结构访问属于不同的等级结构的成员类。 </p>
          <br/>
          <span style="color:red;">
            <a href="http://tianshi0253.javaeye.com/blog/230088#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Tue, 19 Aug 2008 11:42:11 +0800</pubDate>
        <link>http://tianshi0253.javaeye.com/blog/230088</link>
        <guid>http://tianshi0253.javaeye.com/blog/230088</guid>
      </item>
      <item>
        <title>iframe高度自适应</title>
        <author>tianshi0253</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://tianshi0253.javaeye.com">tianshi0253</a>&nbsp;
          链接：<a href="http://tianshi0253.javaeye.com/blog/230019" style="color:red;">http://tianshi0253.javaeye.com/blog/230019</a>&nbsp;
          发表时间: 2008年08月19日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <pre name="code" class="html">&lt;iframe src="http://www.baidu.com" width="100%" height="100%"  onload="this.style.height=this.document.body.scrollHeight;this.style.width=this.document.body.scrollWidth" &gt;&lt;/iframe&gt;</pre>
<p>&nbsp;</p>
          <br/>
          <span style="color:red;">
            <a href="http://tianshi0253.javaeye.com/blog/230019#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Tue, 19 Aug 2008 08:48:43 +0800</pubDate>
        <link>http://tianshi0253.javaeye.com/blog/230019</link>
        <guid>http://tianshi0253.javaeye.com/blog/230019</guid>
      </item>
      <item>
        <title>在对路径操作时，兼容路径中的中文字符</title>
        <author>tianshi0253</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://tianshi0253.javaeye.com">tianshi0253</a>&nbsp;
          链接：<a href="http://tianshi0253.javaeye.com/blog/229911" style="color:red;">http://tianshi0253.javaeye.com/blog/229911</a>&nbsp;
          发表时间: 2008年08月18日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>在controller里设置一个before_filter</p>
<p>例：</p>
<pre name="code" class="ruby">before_filter :set_charset
def set_charset
  @headers["Content-Type"] = "text/html; charset=UTF-8"
end</pre>
<p>&nbsp;</p>
          <br/>
          <span style="color:red;">
            <a href="http://tianshi0253.javaeye.com/blog/229911#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 18 Aug 2008 19:10:20 +0800</pubDate>
        <link>http://tianshi0253.javaeye.com/blog/229911</link>
        <guid>http://tianshi0253.javaeye.com/blog/229911</guid>
      </item>
      <item>
        <title>纯CSS打造的导航菜单</title>
        <author>tianshi0253</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://tianshi0253.javaeye.com">tianshi0253</a>&nbsp;
          链接：<a href="http://tianshi0253.javaeye.com/blog/229215" style="color:red;">http://tianshi0253.javaeye.com/blog/229215</a>&nbsp;
          发表时间: 2008年08月18日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <pre name="code" class="html">&lt;!DOCTYPE
html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&gt;
&lt;html xmlns="http://www.w3.org/1999/xhtml"&gt;
&lt;head&gt;
&lt;meta http-equiv="Content-Type" content="text/html; charset=utf-8"
/&gt;
&lt;title&gt;¶�pdownµ¯³�¥--A CROSS BROWSER DROP DOWN CASCADING
VALIDATING MENU&lt;/title&gt;
&lt;style type="text/css"&gt;
/* common styling */
/* set up the overall width of the menu div, the font and the margins
*/
.menu {
font-family: arial, sans-serif; width:750px; margin:0; margin:0px 0;
}
/* remove the bullets and set the margin and padding to zero for the
unordered list */
.menu ul {
padding:0; margin:0;
list-style-type: none;
}
/* float the list so that the items are in a line and their position
relative so that the drop down list will appear in the right place
underneath each list item */
.menu ul li {
float:left; position:relative;
}
/* style the links to be 104px wide by 30px high with a top and right
border 1px solid white. Set the background color and the font size. */
.menu ul li a, .menu ul li a:visited {
display:block; text-align:center; text-decoration:none; width:104px;
height:30px; color:#000; border:1px solid #fff;
border-width:1px 1px 0 0;
background:#c9c9a7; line-height:30px; font-size:11px;
}
/* make the dropdown ul invisible */
.menu ul li ul {
display: none;
}
/* specific to non IE browsers */
/* set the background and foreground color of the main menu li on hover
*/
.menu ul li:hover a {
color:#fff; background:#b3ab79;
}
/* make the sub menu ul visible and position it beneath the main menu
list item */
.menu ul li:hover ul {
display:block; position:absolute; top:31px; left:0; width:105px;
}
/* style the background and foreground color of the submenu links */
.menu ul li:hover ul li a {
display:block; background:#faeec7; color:#000;
}
/* style the background and forground colors of the links on hover */
.menu ul li:hover ul li a:hover {
background:#dfc184; color:#000;
}
.testing{width:800px; height:30px;line-height:30px;text-align:left;background-color:Green;}
.redBorder{border:1px solid Red;}
&lt;/style&gt;
&lt;!--[if lte IE 6]&gt;
&lt;style type="text/css"&gt;
/* styling specific to Internet Explorer IE5.5 and IE6. Yet to see if
IE7 handles li:hover */
/* Get rid of any default table style */
table {
border-collapse:collapse;
margin:0; padding:0;
}
/* ignore the link used by 'other browsers' */
.menu ul li a.hide, .menu ul li a:visited.hide {
display:none;
}
/* set the background and foreground color of the main menu link on
hover */
.menu ul li a:hover {
color:#fff; background:#b3ab79;
}
/* make the sub menu ul visible and position it beneath the main menu
list item */
.menu ul li a:hover ul {
display:block; position:absolute; top:32px; left:0; width:105px;
}
/* style the background and foreground color of the submenu links */
.menu ul li a:hover ul li a {
background:#faeec7; color:#000;
}
/* style the background and forground colors of the links on hover */
.menu ul li a:hover ul li a:hover {
background:#dfc184; color:#000;
}
&lt;/style&gt;
&lt;![endif]--&gt;
&lt;/head&gt;
&lt;body&gt;
	&lt;div class="testing"&gt;hello-----------testing&lt;/div&gt;
&lt;div class="menu redBorder"&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="hide"
href="../menu/index.html"&gt;DEMOS&lt;/a&gt;
&lt;!--[if lte IE 6]&gt;
&lt;a href="../menu/index.html"&gt;DEMOS
&lt;table&gt;&lt;tr&gt;&lt;td&gt;
&lt;![endif]--&gt; &lt;ul&gt; &lt;li&gt;&lt;a
href="../menu/zero_dollars.html" title="The zero dollar ads
page"&gt;zero dollars&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a
href="../menu/embed.html" title="Wrapping text around
images"&gt;wrapping text&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a
href="../menu/form.html" title="Styling forms"&gt;styled
form&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href="../menu/nodots.html"
title="Removing active/focus borders"&gt;active
focus&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a
href="../menu/shadow_boxing.html" title="Multi-position drop
shadow"&gt;shadow boxing&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a
href="../menu/old_master.html" title="Image Map for detailed
information"&gt;image map&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a
href="../menu/bodies.html" title="fun with background images"&gt;fun
backgrounds&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a
href="../menu/fade_scroll.html" title="fade-out scrolling"&gt;fade
scrolling&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a
href="../menu/em_images.html" title="em size images compared"&gt;em
sized images&lt;/a&gt;&lt;/li&gt; &lt;/ul&gt;
&lt;!--[if lte IE 6]&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/a&gt;
&lt;![endif]--&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a class="hide" href="index.html"&gt;MENUS&lt;/a&gt;

&lt;!--[if lte IE 6]&gt;
&lt;a href="index.html"&gt;MENUS
&lt;table&gt;&lt;tr&gt;&lt;td&gt;
&lt;![endif]--&gt;

    &lt;ul&gt;
    &lt;li&gt;&lt;a href="spies.html" title="a coded list of spies"&gt;spies menu&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="vertical.html" title="a horizontal vertical menu"&gt;vertical menu&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="expand.html" title="an enlarging unordered list"&gt;enlarging list&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="enlarge.html" title="an unordered list with link images"&gt;link images&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="cross.html" title="non-rectangular links"&gt;non-rectangular&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="jigsaw.html" title="jigsaw links"&gt;jigsaw links&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="circles.html" title="circular links"&gt;circular links&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;

&lt;!--[if lte IE 6]&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/a&gt;
&lt;![endif]--&gt;

&lt;/li&gt;

&lt;li&gt;&lt;a class="hide" href="../layouts/index.html"&gt;LAYOUTS&lt;/a&gt;

&lt;!--[if lte IE 6]&gt;
&lt;a href="../layouts/index.html"&gt;LAYOUTS
&lt;table&gt;&lt;tr&gt;&lt;td&gt;
&lt;![endif]--&gt;

    &lt;ul&gt;
    &lt;li&gt;&lt;a href="../layouts/bodyfix.html" title="Cross browser fixed layout"&gt;Fixed 1&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="../layouts/body2.html" title="Cross browser fixed layout"&gt;Fixed 2&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="../layouts/body4.html" title="Cross browser fixed layout"&gt;Fixed 3&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="../layouts/body5.html" title="Cross browser fixed layout"&gt;Fixed 4&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="../layouts/minimum.html" title="A simple minimum width layout"&gt;minimum width&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;

&lt;!--[if lte IE 6]&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/a&gt;
&lt;![endif]--&gt;

&lt;/li&gt;

&lt;li&gt;&lt;a class="hide" href="../boxes/index.html"&gt;BOXES&lt;/a&gt;

&lt;!--[if lte IE 6]&gt;
&lt;a href="../boxes/index.html"&gt;BOXES
&lt;table&gt;&lt;tr&gt;&lt;td&gt;
&lt;![endif]--&gt;

    &lt;ul&gt;
    &lt;li&gt;&lt;a href="spies.html" title="a coded list of spies"&gt;spies menu&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="vertical.html" title="a horizontal vertical menu"&gt;vertical menu&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="expand.html" title="an enlarging unordered list"&gt;enlarging list&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="enlarge.html" title="an unordered list with link images"&gt;link images&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="cross.html" title="non-rectangular links"&gt;non-rectangular&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="jigsaw.html" title="jigsaw links"&gt;jigsaw links&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="circles.html" title="circular links"&gt;circular links&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;

&lt;!--[if lte IE 6]&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/a&gt;
&lt;![endif]--&gt;

&lt;/li&gt;

&lt;li&gt;&lt;a class="hide" href="../mozilla/index.html"&gt;MOZILLA&lt;/a&gt;

&lt;!--[if lte IE 6]&gt;
&lt;a href="../mozilla/index.html"&gt;MOZILLA
&lt;table&gt;&lt;tr&gt;&lt;td&gt;
&lt;![endif]--&gt;

    &lt;ul&gt;
    &lt;li&gt;&lt;a href="../mozilla/dropdown.html" title="A drop down menu"&gt;drop down menu&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="../mozilla/cascade.html" title="A cascading menu"&gt;cascading menu&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="../mozilla/content.html" title="Using content:"&gt;content:&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="../mozilla/moxbox.html" title=":hover applied to a div"&gt;mozzie box&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="../mozilla/rainbow.html" title="I can build a rainbow"&gt;rainbow box&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="../mozilla/snooker.html" title="Snooker cue"&gt;snooker cue&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="../mozilla/target.html" title="Target Practise"&gt;target practise&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="../mozilla/splittext.html" title="Two tone headings"&gt;two tone headings&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="../mozilla/shadow_text.html" title="Shadow text"&gt;shadow text&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;

&lt;!--[if lte IE 6]&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/a&gt;
&lt;![endif]--&gt;

&lt;/li&gt;

&lt;li&gt;&lt;a class="hide" href="../ie/index.html"&gt;EXPLORER&lt;/a&gt;

&lt;!--[if lte IE 6]&gt;
&lt;a href="../ie/index.html"&gt;EXPLORER
&lt;table&gt;&lt;tr&gt;&lt;td&gt;
&lt;![endif]--&gt;

    &lt;ul&gt;
    &lt;li&gt;&lt;a href="../ie/exampleone.html" title="Example one"&gt;example one&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="../ie/weft.html" title="Weft fonts"&gt;weft fonts&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="../ie/exampletwo.html" title="Vertical align"&gt;vertical align&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;

&lt;!--[if lte IE 6]&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/a&gt;
&lt;![endif]--&gt;

&lt;/li&gt;

&lt;li&gt;&lt;a class="hide" href="../opacity/index.html"&gt;OPACITY&lt;/a&gt;

&lt;!--[if lte IE 6]&gt;
&lt;a href="../opacity/index.html"&gt;OPACITY
&lt;table&gt;&lt;tr&gt;&lt;td&gt;
&lt;![endif]--&gt;

    &lt;ul&gt;
    &lt;li&gt;&lt;a href="../opacity/colours.html" title="colour wheel"&gt;opaque colours&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="../opacity/picturemenu.html" title="a menu using opacity"&gt;opaque menu&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="../opacity/png.html" title="partial opacity"&gt;partial opacity&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="../opacity/png2.html" title="partial opacity II"&gt;partial opacity II&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;

&lt;!--[if lte IE 6]&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/a&gt;
&lt;![endif]--&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;!-- clear the floats if required --&gt;
&lt;div class="clear"&gt; &lt;/div&gt;

&lt;/div&gt;
&lt;/body&gt;
&lt;/html&gt;
&lt;div class="testing"&gt;hello-----------testing&lt;/div&gt;</pre>
<p>&nbsp;</p>
          <br/>
          <span style="color:red;">
            <a href="http://tianshi0253.javaeye.com/blog/229215#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 18 Aug 2008 15:04:20 +0800</pubDate>
        <link>http://tianshi0253.javaeye.com/blog/229215</link>
        <guid>http://tianshi0253.javaeye.com/blog/229215</guid>
      </item>
      <item>
        <title>在Windows平台使用Apache2.2和Mongrel运行Ruby on Rails</title>
        <author>tianshi0253</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://tianshi0253.javaeye.com">tianshi0253</a>&nbsp;
          链接：<a href="http://tianshi0253.javaeye.com/blog/229174" style="color:red;">http://tianshi0253.javaeye.com/blog/229174</a>&nbsp;
          发表时间: 2008年08月18日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <div class="postTitle">在Windows平台使用Apache2.2和Mongrel运行Ruby on Rails</div>
<div class="postText">
<p>一、安装Ruby、rails、mongrel和Apache2.2</p>
<div>从<a href="http://rubyforge.org/" target="_blank">rubyforge</a>网站下载One-Click Ruby Install，运行安装程序，就安装好了ruby和rubygems。</div>
<div>运行命令：</div>
<div><span>gem install rails<br /></span></div>
<div><span>gem install mongrel<br /><br />//出现选择窗口时，选择2:mongrel 1.1.5(x86-msvin32-60)<br /><br /></span></div>
<div><span>gem install mongrel_service<br /></span><span>//出现选择窗口时，一直选择1</span></div>
<div>安装好了rails和mongrel<br /><br />
<h2><span style="color: #3366ff;">手动安装mongrel方法</span></h2>
<span style="color: #3366ff;">手动下载以下安装包<br />gem_plugin-0.2.1.gem<br />win32-service-0.5.0-mswin32.gem<br />mongrel-0.3.13.3-mswin32.gem<br />mongrel_service-0.1.gem<br />下载到 rubyforge.org 搜索<br /><br />编写 批处理 安装，由于有依赖关系，必须按照顺序<br />call gem install gem_plugin-0.2.1.gem<br />call gem install win32-service-0.5.0-mswin32.gem<br />call gem install mongrel-0.3.13.3-mswin32.gem<br />call gem install mongrel_service-0.1.gem<br /><br />运行批处理文件即可,也可详细写上地址：<br />call gem install D:\ruby_server\rake-0.7.1.gem<br />call gem install D:\ruby_server\gem_plugin-0.2.1.gem <br />call gem install D:\ruby_server\win32-service-0.5.2-mswin32.gem <br />call gem install D:\ruby_server\mongrel-0.3.13.3-mswin32.gem <br />call gem install D:\ruby_server\mongrel_service-0.1.gem <br /><br />路径自定，存成bat</span></div>
<div>从Apache网站下载Windows版本的Apache2.2，运行安装程序，就安装好了Apache2.2。</div>
<div>二、把Mongrel作为Services启动</div>
<div><span>mongrel_rails service::install -N depot -c "E:\server\human" -p 1234 &ndash;e production<br /><br /></span></div>
<div>-N指明服务名称，-d指明rails应用的目录，-p是mongrel监听的tcp端口，-e是启动模式为生产模式</div>
<div>这样打开控制面版|管理工具|服务，就可以发现增加了一项名为&ldquo;depot&rdquo;的服务，就可以通过控制面版来管理服务了。如果需要命令行启动和关闭该服务，那么：</div>
<div><span>mongrel_rails service::start -N depot</span></div>
<div><span>mongrel_rails service::stop -N depot</span></div>
<div>如果需要从服务中注销该项服务，那么：</div>
<div><span>mongrel_rails service::remove -N depot</span></div>
<div>如果需要安装多个mongrel实例，那么可以这样：</div>
<div><span>mongrel_rails service::install -N depot0 -c d:\Rubyproject\depot -p 3000 &ndash;e production</span></div>
<div><span>mongrel_rails service::install -N depot1 -c d:\Rubyproject\depot -p 3001 &ndash;e production</span></div>
<div>诸如此类。</div>
<div>三、配置Apache2.2</div>
<div>用编辑工具打开Apache2.2目录下面的conf/httpd.conf，需要取消如下模块的注释：</div>
<div><span>LoadModule proxy_module modules/mod_proxy.so</span></div>
<div><span>LoadModule proxy_balancer_module modules/mod_proxy_balancer.so</span></div>
<div><span>LoadModule proxy_http_module modules/mod_proxy_http.so</span></div>
<div>如果你希望对页面输出使用压缩，也需要取消如下模块的注释：</div>
<div><span>LoadModule deflate_module modules/mod_deflate.so</span></div>
<div>然后按如下内容配置基于HTTP代理的负载均衡：</div>
<div>
<div class="code_title"><span>xml 代码</span></div>
<div class="dp-highlighter"><ol class="dp-xml"><span>
<li class="alt"><span><span>ProxyRequests Off &nbsp;&nbsp;</span></span> </li>
<li><span class="tag">&lt;</span><span class="tag-name">Proxy</span><span> balancer://myCluster</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span> </li>
<li class="alt"><span>&nbsp;&nbsp; BalancerMember http://localhost:3000 &nbsp;&nbsp;</span> </li>
<li><span>&nbsp;&nbsp; BalancerMember http://localhost:3001 &nbsp;&nbsp;</span> </li>
<li class="alt"><span class="tag"><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span> </span></li>
<li><span>&nbsp;&nbsp;</span> </li>
<li class="alt"><span class="tag">&lt;</span><span class="tag-name">VirtualHost</span><span> *:80</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span> </li>
<li><span>&nbsp;&nbsp; ServerName www.xxx.com &nbsp;&nbsp;</span> </li>
<li class="alt"><span>&nbsp;&nbsp; DocumentRoot d:/rubyproject/depot/public &nbsp;&nbsp;</span> </li>
<li><span>&nbsp;&nbsp; ProxyPass /images ! &nbsp;&nbsp;</span> </li>
<li class="alt"><span>&nbsp;&nbsp; ProxyPass /stylesheets ! &nbsp;&nbsp;</span> </li>
<li><span>&nbsp;&nbsp; ProxyPass /javascripts ! &nbsp;&nbsp;</span> </li>
<li class="alt"><span>&nbsp;&nbsp; ProxyPass / balancer://myCluster/ &nbsp;&nbsp;</span> </li>
<li><span>&nbsp;&nbsp; ProxyPassReverse / balancer://myCluster/ &nbsp;&nbsp;</span> </li>
<li class="alt"><span>&nbsp;&nbsp; ProxyPreserveHost on &nbsp;&nbsp;</span> </li>
<font>
<li><span class="tag"><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span> </span></li>
</font></span></ol></div>
</div>
<div>myCluster定义了群集中的每个mongrel应用服务器节点。ProxyPass /images !指明该URL开始的请求不代理给Mongrel群集，而由Apache自己处理。重起Apache，然后打开浏览器访问www.xxx.com，检查配置是否正确。</div>
<div>至此，在Windows Server上面一个具备良好稳定性和性能的Ruby on rails生产环境就搭建好了。</div>
<div>对于页面输出，还可以使用mod_deflate进行输出内容压缩，以提高页面下载速度，这个就留给大家自己配置了。</div>
<p class="poweredbyperformancing">Powered by ScribeFire.</p>
</div>
          <br/>
          <span style="color:red;">
            <a href="http://tianshi0253.javaeye.com/blog/229174#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 18 Aug 2008 13:40:41 +0800</pubDate>
        <link>http://tianshi0253.javaeye.com/blog/229174</link>
        <guid>http://tianshi0253.javaeye.com/blog/229174</guid>
      </item>
      <item>
        <title>浅析Ruby on Rails部署方案(三)</title>
        <author>tianshi0253</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://tianshi0253.javaeye.com">tianshi0253</a>&nbsp;
          链接：<a href="http://tianshi0253.javaeye.com/blog/229173" style="color:red;">http://tianshi0253.javaeye.com/blog/229173</a>&nbsp;
          发表时间: 2008年08月18日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <h2><span><strong>测试结果</strong></span></h2>
<p>HAproxy和Lighttpd的测试需要调整很多参数，我们先看看无需调整参数的几种方案的测试结果，我同样除了原始数据的折线图，还会给出B样条的图以更清晰地看到结果：<br /><a href="http://docs.google.com/File?id=ddcvzh74_31gqhk57hc_b" target="_blank"><img src="http://docs.google.com/File?id=ddcvzh74_31gqhk57hc_b" alt="" style="float: left; margin: 1em 1em 0pt 0pt; width: 320px; height: 240px;" /></a></p>
<div style="padding-right: 0pt; padding-left: 0pt; padding-bottom: 1em; padding-top: 1em; text-align: left;"><a href="http://docs.google.com/File?id=ddcvzh74_32fn4pq4cm_b" target="_blank"><img src="http://docs.google.com/File?id=ddcvzh74_32fn4pq4cm_b" alt="" style="width: 320px; height: 240px;" /></a></div>
<p>从图上我们看到Nginx+Mongrel的方式性能很稳定，但在并发量小于150的情况下与其他方案相比还是差很多的。<br />Nginx+Thin/Evented Mongrel两种方式的性能则相差不大，毕竟都是使用的EventMachine。<br />Swiftiply的两种方式都体现出了很高的性能，尤其是Swiftiply+Swiftiplied Mongrel令人影响深刻，即使在500的并发量左右，性能依然保持稳定。<br />Apache+Passenger模式在低并发（&lt;=300）的情况下效率很高，但随着并发量上升，Apache的两种工作模式本身的效率下降得就很快，Prefork模式在大于450的情况下降到了0（我认为是出现了TCP错误导致AB测试中断）。<br />这个测试中，除了Nginx，其他的搭配方式Swiftiply和Passenger，应该每次都只给后端一个请求，同时也应该是建立的持久链接。<br /><span><strong>HAproxy/Mongrel的测试结果</strong></span><br /><br /><a href="http://docs.google.com/File?id=ddcvzh74_33fm39f9fh_b" target="_blank"><img src="http://docs.google.com/File?id=ddcvzh74_33fm39f9fh_b" alt="" style="float: left; margin: 1em 1em 0pt 0pt; width: 320px; height: 240px;" /></a><a href="http://docs.google.com/File?id=ddcvzh74_34gcqv44df_b" target="_blank"><img src="http://docs.google.com/File?id=ddcvzh74_34gcqv44df_b" alt="" style="float: left; margin: 1em 1em 0pt 0pt; width: 320px; height: 240px;" /></a></p>
<div>
<div style="padding-right: 0pt; padding-left: 0pt; padding-bottom: 1em; padding-top: 1em; text-align: left;"><a href="http://docs.google.com/File?id=ddcvzh74_35c4zpv3g5_b" target="_blank"><img src="http://docs.google.com/File?id=ddcvzh74_35c4zpv3g5_b" alt="" style="width: 320px; height: 240px;" /></a></div>
<br /></div>
<p><br />通过对HAproxy的maxconn参数的调整，得到了如上图的测试结果，我们不难发现在maxconn=1的情况下是效率最高的，这印证了前面对后端缺点的分析。因为在限制了每次只有一个链接之后，Mongrel的进程减少了锁和上下文切换的开销，所以得到了很稳定的性能，另外我们还可以注意到，随着maxconn越来越大，最后达到50的时候，这时候Mongrel进程中对于锁和上下文切换的开销也趋于平稳，情况变成了和Nginx/Mongrel的情况一样。<br />通过对比，我们可以发现，利用HAproxy限制到Mongrel的链接数为1，可以比Nginx+Mongrel的方式性能提高23%～28%，不过相比Passenger/Swiftiply方式而言，还是差一点点，但性能依然十分稳定。<br />这也是为什么ThoughtWorks的Rubyworks采用了HAproxy的缘故，我觉得在Rubyworks推出的当时是非常正确的选择，因为当时没有其他选择。</p>
<div>
<div><br /><span><strong>HAproxy/Thin的测试结果<br /></strong></span><a href="http://docs.google.com/File?id=ddcvzh74_38fsspcqfw_b" target="_blank"><img src="http://docs.google.com/File?id=ddcvzh74_38fsspcqfw_b" alt="" style="float: left; margin: 1em 1em 0pt 0pt; width: 320px; height: 240px;" /></a><a href="http://docs.google.com/File?id=ddcvzh74_39hkpzr6cv_b" target="_blank"><img src="http://docs.google.com/File?id=ddcvzh74_39hkpzr6cv_b" alt="" style="float: left; margin: 1em 1em 0pt 0pt; width: 320px; height: 240px;" /></a>
<div style="padding-right: 0pt; padding-left: 0pt; padding-bottom: 1em; padding-top: 1em; text-align: left;"><a href="http://docs.google.com/File?id=ddcvzh74_40hcmqx2c8_b" target="_blank"><img src="http://docs.google.com/File?id=ddcvzh74_40hcmqx2c8_b" alt="" style="width: 320px; height: 240px;" /></a></div>
由于Thin没有锁和上下文切换的开销，因此限制maxconn在测试结果上不如对Mongrel的效果那么明显。但基本上也可以看出来，将链接到后端的连接数限制在较小的范围内会对性能和稳定性有更好的帮助。<br /><span><strong>Lighttpd/Mongrel的测试结果<br /></strong><a href="http://docs.google.com/File?id=ddcvzh74_44dvsw4rcs_b" target="_blank"><img src="http://docs.google.com/File?id=ddcvzh74_44dvsw4rcs_b" alt="" style="float: left; margin: 1em 1em 0pt 0pt; width: 320px; height: 240px;" /></a><a href="http://docs.google.com/File?id=ddcvzh74_45f87jhcf9_b" target="_blank"><img src="http://docs.google.com/File?id=ddcvzh74_45f87jhcf9_b" alt="" style="float: left; margin: 1em 1em 0pt 0pt; width: 320px; height: 240px;" /></a>
<div style="padding-right: 0pt; padding-left: 0pt; padding-bottom: 1em; padding-top: 1em; text-align: left;"><a href="http://docs.google.com/File?id=ddcvzh74_46c4q4q529_b" target="_blank"><img src="http://docs.google.com/File?id=ddcvzh74_46c4q4q529_b" alt="" style="width: 320px; height: 240px;" /></a></div>
Lighttpd+Mongrel的图像与HAproxy+Mongrel的非常不同，尤其是在限制到后端的链接效果上。我在测试结果中发现了大量的</span><tt class="docutils literal"><span style="font-family: 新宋体;"><span class="pre">504</span><span class="pre">Gateway</span><span class="pre">timeout</span></span></tt><span>错误返回，从而导致了响应速度的降低。随着链接限制参数的变大，504错误越来越少。我们可以发现在并发量小于100的时候，其效果还是和HAproxy类似的。当链接限制大到一定程度，其效果和Nginx+Mongrel的方式也是一样的。<br /><strong>Lighttpd/Thin的测试结果<br /></strong><a href="http://docs.google.com/File?id=ddcvzh74_56cnh4frd4_b" target="_blank"><img src="http://docs.google.com/File?id=ddcvzh74_56cnh4frd4_b" alt="" style="float: left; margin: 1em 1em 0pt 0pt; width: 320px; height: 240px;" /></a><a href="http://docs.google.com/File?id=ddcvzh74_57c9zfhng2_b" target="_blank"><img src="http://docs.google.com/File?id=ddcvzh74_57c9zfhng2_b" alt="" style="float: left; margin: 1em 1em 0pt 0pt; width: 320px; height: 240px;" /></a><br />
<div style="padding-right: 0pt; padding-left: 0pt; padding-bottom: 1em; padding-top: 1em; text-align: left;"><a href="http://docs.google.com/File?id=ddcvzh74_55gc76qbcz_b" target="_blank"><img src="http://docs.google.com/File?id=ddcvzh74_55gc76qbcz_b" alt="" style="width: 320px; height: 240px;" /></a></div>
</span><span>Lighttpd搭配</span><span>Thin的情况</span><span>同样出现了Mongrel一样的情况，在<span>max-pool-size</span>参数为1的时候出现了大量的504错误返回，并随着这个参数的增加错误数减少。<br />Lighttpd+Thin的方式在不限制连接数的情况下性能要大大优于Nginx+Thin和HAproxy+Thin的方式。<br /></span><span><strong>Lighttpd/FastCGI的测试结果<br /></strong></span><span>通过Socket方式<br />
<div style="padding-right: 0pt; padding-left: 0pt; padding-bottom: 1em; padding-top: 1em; text-align: left;"><a href="http://docs.google.com/File?id=ddcvzh74_58c5rx42d9_b" target="_blank"><img src="http://docs.google.com/File?id=ddcvzh74_58c5rx42d9_b" alt="" style="float: left; margin: 1em 1em 0pt 0pt; width: 320px; height: 240px;" /></a><a href="http://docs.google.com/File?id=ddcvzh74_59c35zjpgm_b" target="_blank"><img src="http://docs.google.com/File?id=ddcvzh74_59c35zjpgm_b" alt="" style="float: left; margin: 1em 1em 0pt 0pt; width: 320px; height: 240px;" /></a><a href="http://docs.google.com/File?id=ddcvzh74_47cg7wrm9n_b" target="_blank"><img src="http://docs.google.com/File?id=ddcvzh74_47cg7wrm9n_b" alt="" style="width: 320px; height: 240px;" /></a></div>
<br />通过TCP方式</span><br /><a href="http://docs.google.com/File?id=ddcvzh74_60fkz8m3fp_b" target="_blank"><img src="http://docs.google.com/File?id=ddcvzh74_60fkz8m3fp_b" alt="" style="float: left; margin: 1em 1em 0pt 0pt; width: 320px; height: 240px;" /></a><a href="http://docs.google.com/File?id=ddcvzh74_61g9qvqhhb_b" target="_blank"><img src="http://docs.google.com/File?id=ddcvzh74_61g9qvqhhb_b" alt="" style="float: left; margin: 1em 1em 0pt 0pt; width: 320px; height: 240px;" /></a><br />
<div><a href="http://docs.google.com/File?id=ddcvzh74_48dhn8mfjp_b" target="_blank"><img src="http://docs.google.com/File?id=ddcvzh74_48dhn8mfjp_b" alt="" style="width: 320px; height: 240px;" /></a><br />
<p><span>我们可以发现Lighttpd的FastCGI方式</span><span><span>走TCP或Socket在性能方面没有太大差</span></span><span><span>别，但限制链接数容易造成Lighttpd直接给出错误返回，随着连接数限制的放宽，错误数也减少，响应速度也变得稳定。</span></span></p>
<p><span><span>根据前面对后端的测试，无论何种后端都应该在低链接的情况下有更好的表现，Lighttpd为何在限制了连接数之后反而有更过504错误呢，我认为是Lighttpd未实现像Apache和HAproxy的双重链接池的功能，同时Lighttpd的默认的超时时间又只有10秒钟。在Apache和HAproxy的情况中，当链接未进入某个后端服务器的等待队列时，会等待Timeout时间，而进入了后端等待队列之后会重新等待TTL的时间，这样就避免了快达到Timeout的时候进入等待队列没多久就被放弃的情况。当然Apache和HAproxy的Timeout和TTL参数也需要根据系统的性能和要求小心调整。而对于Lighttpd则可以考虑适当增大Timeout时间。<br /></span></span></p>
<h3><strong><strong>分析和</strong>小结</strong></h3>
<p><span>我</span><span><span>先</span></span><span>来将本案中的各种部署方式的性能排个名次，以下是</span><span><span>后各种方案在并发量&gt;=10的情况下的平均值（去掉出现0值的情况）：</span></span></p>
<p>&nbsp;</p>
<div>
<table cellspacing="0" border="1" cellpadding="3">
<tbody>
<tr>
<td width="20%">前端</td>
<td width="20%">后端</td>
<td width="20%"><span>平均每秒响应数</span></td>
<td width="20%">最大链接限制</td>
</tr>
<tr>
<td width="20%">Lighttpd</td>
<td width="20%">FastCGI/TCP</td>
<td width="20%">215.33</td>
<td width="20%">64</td>
</tr>
<tr>
<td width="20%">Lighttpd</td>
<td width="20%">FastCGI/Socket</td>
<td width="20%">214.65</td>
<td width="20%">64</td>
</tr>
<tr>
<td width="20%">Lighttpd</td>
<td width="20%">Thin</td>
<td width="20%">196.16</td>
<td width="20%">64</td>
</tr>
<tr>
<td width="20%">Swiftiply</td>
<td width="20%">Swiftiplied Mongrel</td>
<td width="20%">191.33</td>
<td width="20%">N/A</td>
</tr>
<tr>
<td width="20%">HAproxy</td>
<td width="20%">Thin</td>
<td width="20%">188.73</td>
<td width="20%">10</td>
</tr>
<tr>
<td width="20%">Swiftiply</td>
<td width="20%">Thin(Swiftiplied)</td>
<td width="20%">178.96</td>
<td width="20%">N/A</td>
</tr>
<tr>
<td width="20%">Apache2.2/Prefork</td>
<td width="20%">Passenger</td>
<td width="20%">173.02</td>
<td width="20%">N/A</td>
</tr>
<tr>
<td width="20%">HAproxy</td>
<td width="20%">Mongrel</td>
<td width="20%">170.4</td>
<td width="20%">1</td>
</tr>
<tr>
<td width="20%">Apache2.2/Worker</td>
<td width="20%">Passenger</td>
<td width="20%">163.9</td>
<td width="20%">N/A</td>
</tr>
<tr>
<td width="20%">Lighttpd</td>
<td width="20%">Mongrel</td>
<td width="20%">149.85</td>
<td width="20%">64</td>
</tr>
<tr>
<td width="20%">Nginx</td>
<td width="20%">Evented Mongrel</td>
<td width="20%">149.78</td>
<td width="20%">N/A</td>
</tr>
<tr>
<td width="20%">Nginx</td>
<td width="20%">Thin</td>
<td width="20%">143.88</td>
<td width="20%">N/A</td>
</tr>
<tr>
<td width="20%">Nginx</td>
<td width="20%">Mongrel</td>
<td width="20%">138.86</td>
<td width="20%">N/A</td>
</tr>
</tbody>
</table>
</div>
<br /><span>在这个表中，Lighttpd的三种方案占据了前三位，</span><span>Lighttpd+FastCGI是性能最高的部署方式。这种方式比另一种流行方案Nginx+Mongrel的方式性能提升了高达50%！</span><br />FastCGI的好处在此体现出来：<br />
<ul>
<li>二进制协议，无需HTTP的解析 </li>
<li>与前端可以建立持久链接 </li>
<li>没有锁和上下文切换的开销 </li>
</ul>
另外Lighttpd相对于Nginx的优势在于请求和响应的接收缓冲区很大，省去多次接收和发送的开销。<br />Lighttpd+Thin的方式的性能列第三位，这点似乎出乎意料之外，但实际上是因为Lighttpd 1.5支持对HTTP后端建立HTTP KeepAlive链接。在对后端单独的测试中，小并发下的Thin的KeepAlive测试性能并不比FastCGI差，同时Thin实现了非阻塞IO，而FastCGI则是阻塞式的。相反，HAproxy和Nginx则都不支持HTTP KeepAlive。<br />而Swiftiply的方式也显示出了强劲的性能，应该是得益于它的<span>&ldquo;让后端主动连接到Swiftiply&rdquo;的这种</span>特殊的结构。<br />当前备受关注的Passenger的部署方式在本案中并没有显示出特别的性能上的优势，不过如果将并发链接数放在300以内，则Apache2.2/Prefork + Passenger的部署方式的平均每秒响应数上升为204.03，这样看来，倘若为Apache进行一些优化配置，依然不失为一种高效的部署方案。而同时Passenger又是最容易配置的一种方案，能达到这种效果已经非常令人满意。<br />HAproxy + Mongrel并限制链接数为1，则是一种稳定、保守的部署方式，虽然在这里性能不出众，但是稳定性非常好。<br />最后，<span><span>与</span></span><span>Nginx相关的</span>三种方案都排在了该榜的末尾，由于Nginx的反向代理负载均衡缺少一些高级的特性以及Rails本身的特性而导致其不适合单独应用在Rails程序的部署上：<br />
<ul>
<li>缺少到后台服务器端的链接数限制的能力，这导致了Mongrel在接受大量请求时将时间消耗在上下文切换和锁的争用上。 </li>
<li>缺乏建立到后台服务器端的持久链接的能力，这导致了在链接的打开、建立、关闭上花费了额外的开销。 </li>
</ul>
<h2>延伸</h2>
<span><strong>Windows操作系统</strong></span><br />由于*nix操作系统中，可以替代Apache的选择很多，而Windows下基本上只能使用Apache2.2+Mongrel的方式了<span><span>，想使用Thin的朋友要记得单独安装<a href="http://rubyforge.org/frs/download.php/23665/eventmachine-win32-0.8.1.gem" title="EventMachine 0.8.1">EventMachine 0.8.1</a> ，目前最新的Windows安装包。<br />我给出一个比较合理的</span></span><span><span><span>Apache2.2</span></span></span><span><span>的配置，</span></span><span><span><span>最简化的配置</span></span></span><span><span>文件如下：<br /></span></span>
<blockquote><span><span>ThreadsPerChild 1024</span></span><br /><span><span>MaxRequestsPerChild 0</span></span><br /><br /><span><span>ServerRoot "C:/Apache2"</span></span><br /><span><span>Listen 80</span></span><br /><span><span>KeepAlive off</span></span><br /><span><span>KeepAliveTimeout 15</span></span><br /><span><span>Timeout 30</span></span><br /><span><span>MaxKeepAliveRequests 1024</span></span><br /><br /><span><span>LoadModule log_config_module modules/mod_log_config.so</span></span><br /><span><span>LoadModule proxy_module modules/mod_proxy.so</span></span><br /><span><span>LoadModule proxy_balancer_module modules/mod_proxy_balancer.so</span></span><br /><span><span>LoadModule proxy_http_module modules/mod_proxy_http.so</span></span><br /><span><span><span>LoadModule rewrite_module modules/mod_rewrite.so</span></span></span><br /><span><span>LoadModule status_module modules/mod_status.so</span></span><br /><br /><span><span>ServerAdmin admin@shiningray.cn</span></span><br /><span><span>ServerName </span></span><span><span><span>shiningray.cn</span></span></span><br /><span><span>DocumentRoot "D:/wwwroot/rails/public"</span></span><br /><span><span>ErrorLog logs/error.log</span></span><br /><span><span>LogLevel warn</span></span><br /><br /><span><span>&lt;IfModule log_config_module&gt;</span></span><br /><span><span>&nbsp;&nbsp;&nbsp; LogFormat "%h %l %u %t \"%r\" %&gt;s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined</span></span><br /><span><span>&nbsp;&nbsp;&nbsp; LogFormat "%h %l %u %t \"%r\" %&gt;s %b" common</span></span><br /><br /><span><span>&nbsp;&nbsp;&nbsp; &lt;IfModule logio_module&gt;</span></span><br /><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LogFormat "%h %l %u %t \"%r\" %&gt;s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O" combinedio</span></span><br /><span><span>&nbsp;&nbsp;&nbsp; &lt;/IfModule&gt;</span></span><br /><br /><span><span>&nbsp;&nbsp;&nbsp; CustomLog logs/access.log common</span></span><br /><span><span>&lt;/IfModule&gt;</span></span><br /><br /><span><span>&lt;Proxy balancer://mongrels&gt;</span></span><br /><span><span>&nbsp;&nbsp;&nbsp; BalancerMember http://127.0.0.1:30000 max=10 smax=1</span></span><br /><span><span>&nbsp;&nbsp;&nbsp; BalancerMember http://127.0.0.1:30001 max=10 smax=1</span></span><br /><span><span>&nbsp;&nbsp;&nbsp; #在这里放更多的后端服务器</span></span><br /><span><span>&lt;/Proxy&gt;</span></span><br /><br /><span><span><span>ProxyRequests off</span></span></span><br /><span><span><span>RewriteEngine On</span></span></span><span>&nbsp;&nbsp;&nbsp; </span><br /><span>RewriteCond %{REQUEST_FILENAME} !-d</span><br /><span>RewriteCond %{REQUEST_FILENAME} !-f</span><br /><span><span><span>RewriteRule ^/(.*)$ </span></span></span><span><span><span>balancer://mongrels</span></span></span><span>%{REQUEST_URI}</span><span><span><span> [QSA,P,L]</span></span></span><br /></blockquote>
<span><span>其中，smax=1表示限制到后端的最大链接数为1，max=10表示等待队列为10。如果后端是Mongrel，这样就可以解决Mongrel接受大量请求对锁和上下文切换的消耗。<br />而如果后端采用了Thin，根据前面的测试结果，应该打开KeepAlive功能，即在每个BalancerMember后面加上keepalive=on，并且适当提升max和smax的值，以充分利用Thin的特性。关于这些参数可以参考ProxyPass指令的解释。<br />在本文中就不对该平台下的部署方式进行性能测试了，这种方案通常是在对遗留项目的迁移中才会出现，建议Rails应用还是最终应该部署在*nix的平台上以达到最好的性能。<br /><br /><span><strong>其他有意思的部署方式<br /></strong>当然，除了前面的几种方案之外，我们可以还可以根据实际情况采用不同的组合来实现功能，下面我给出几个复杂一些的方案，希望能抛砖引玉。<strong><br /></strong></span>一、虽然Nginx不能限制到对后端的链接，而HAproxy又不支持静态文件，那么二者结合会怎样呢？我在公司的一台CentOS 3的服务器上便使用的是Nginx+HAproxy+Mongrel的方式。由于这个部署方式是对HAproxy+Mongrel在外面套一层，性能基本基本接近没有太大差别，便不放测试测试数据了。<br />二、之前提到了Nginx不支持对FastCGI的后端进行分发，似乎有些遗憾，但我们也提到HAproxy也可以做TCP转发的负载均衡器，利用Nginx+HAproxy来对FastCGI的后端做请求分发效果会如何呢？<br />于是我做了个测试：<br />HAproxy的配置改为：<br /></span></span>
<blockquote># this config needs haproxy-1.1.28 or haproxy-1.2.1<br /><br />global<br />&nbsp;&nbsp;&nbsp; log 127.0.0.1&nbsp;&nbsp;&nbsp; local0<br />&nbsp;&nbsp;&nbsp; log 127.0.0.1&nbsp;&nbsp;&nbsp; local1 notice<br />&nbsp;&nbsp;&nbsp; #log loghost&nbsp;&nbsp;&nbsp; local0 info<br />&nbsp;&nbsp;&nbsp; maxconn 2000<br />&nbsp;&nbsp;&nbsp; #chroot /usr/share/haproxy<br />&nbsp;&nbsp;&nbsp; #uid 99<br />&nbsp;&nbsp;&nbsp; #gid 99<br />&nbsp;&nbsp;&nbsp; #daemon<br />&nbsp;&nbsp;&nbsp; #debug<br />&nbsp;&nbsp;&nbsp; #quiet<br /><br />defaults<br />&nbsp;&nbsp;&nbsp; log&nbsp;&nbsp;&nbsp; global<br />&nbsp;&nbsp;&nbsp; mode&nbsp;&nbsp;&nbsp; http<br />&nbsp;&nbsp;&nbsp; option&nbsp;&nbsp;&nbsp; httplog<br />&nbsp;&nbsp;&nbsp; option&nbsp;&nbsp;&nbsp; dontlognull<br />&nbsp;&nbsp;&nbsp; retries&nbsp;&nbsp;&nbsp; 3<br />&nbsp;&nbsp;&nbsp; redispatch<br />&nbsp;&nbsp;&nbsp; maxconn&nbsp;&nbsp;&nbsp; 2000<br />&nbsp;&nbsp;&nbsp; contimeout&nbsp;&nbsp;&nbsp; 5000<br />&nbsp;&nbsp;&nbsp; clitimeout&nbsp;&nbsp;&nbsp; 50000<br />&nbsp;&nbsp;&nbsp; srvtimeout&nbsp;&nbsp;&nbsp; 50000<br /><br />listen test 0.0.0.0:9000<br />&nbsp;&nbsp;&nbsp; mode tcp<br />&nbsp;&nbsp;&nbsp; balance roundrobin<br />&nbsp;&nbsp;&nbsp; server mongrel_30000 127.0.0.1:30000 maxconn 8<br />&nbsp;&nbsp;&nbsp; server mongrel_30001 127.0.0.1:30001 maxconn 8<br />&nbsp;&nbsp;&nbsp; server mongrel_30002 127.0.0.1:30002 maxconn 8<br />&nbsp;&nbsp;&nbsp; server mongrel_30003 127.0.0.1:30003 maxconn 8<br />&nbsp;&nbsp;&nbsp; server mongrel_30004 127.0.0.1:30004 maxconn 8<br />&nbsp;&nbsp;&nbsp; server mongrel_30005 127.0.0.1:30005 maxconn 8<br />&nbsp;&nbsp;&nbsp; server mongrel_30006 127.0.0.1:30006 maxconn 8<br />&nbsp;&nbsp;&nbsp; server mongrel_30007 127.0.0.1:30007 maxconn 8<br />&nbsp;&nbsp;&nbsp; server mongrel_30008 127.0.0.1:30008 maxconn 8<br />&nbsp;&nbsp;&nbsp; server mongrel_30009 127.0.0.1:30009 maxconn 8<br /></blockquote>
<br /><span><span>Nginx的配置改为：<br /><br /></span></span>
<blockquote><span>worker_processes 1;</span><br /><br /><span>events {</span><br /><span>&nbsp;&nbsp;&nbsp; worker_connections 1024;</span><br /><span>&nbsp;&nbsp;&nbsp; use epoll;</span><br /><span>}</span><br /><br /><span>http {</span><br /><span>&nbsp;&nbsp;&nbsp; include&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mime.types;</span><br /><span>&nbsp;&nbsp;&nbsp; default_type application/octet-stream;</span><br /><br /><span>&nbsp;&nbsp;&nbsp; sendfile&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; on;</span><br /><span>&nbsp;&nbsp;&nbsp; #tcp_nopush&nbsp;&nbsp;&nbsp;&nbsp; on;</span><br /><br /><span>&nbsp;&nbsp;&nbsp; #keepalive_timeout 0;</span><br /><span>&nbsp;&nbsp;&nbsp; keepalive_timeout 65;</span><br /><br /><span>&nbsp;&nbsp;&nbsp; server {</span><br /><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; listen&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 8080;</span><br /><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; server_name localhost;</span><br /><br /><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; root /home/shiningray/NetBeansProjects/botadmin/public;</span><br /><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; location / {</span><br /><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; include fastcgi_params;</span><br /><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (-f $request_filename/index.html) {</span><br /><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rewrite (.*) $1/index.html break; </span><br /><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span><br /><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (-f $request_filename.html) {</span><br /><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rewrite (.*) $1.html break; </span><br /><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span><br /><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!-f $request_filename) {</span><br /><br /><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fastcgi_pass 127.0.0.1:9000;</span><br /><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break; </span><br /><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span><br /><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span><br /><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; error_page&nbsp;&nbsp; 500 502 503 504 /50x.html;</span><br /><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; location = /50x.html {</span><br /><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; root&nbsp;&nbsp; html;</span><br /><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span><br /><span>&nbsp;&nbsp;&nbsp; }</span><br /><span>}</span><br /></blockquote>
<span><span>据我测试，此部署方案的性能也可以与Lighttpd的几种一较高下，但毕竟因为多了一层，还是略占下风。<br />这两种方案部署上更为繁琐，小型应用上其实只需要考虑前面的两层方案便可，在此不做详细的评测了。<br /></span></span>
<h2><span><span>其它问题</span></span></h2>
除了对部属方案的性能考虑之外，我们还需要考虑一些别的问题。比如，Mongrel后端的启动是通过mongrel_cluster启动的，我们只要安装这个gem便可，如果要添加为自启动脚本可以利用mongrel_cluster自带的init脚本。但是这些脚本不能实现当mongrel进程崩溃、退出后的重新启动，同时，如果配置不恰当，当mongrel进程被强制杀死或系统宕机之后，mongrel遗留的pid文件会导致无法启动mongrel进程，必须先删除这些文件（Mongrel_cluster提供了--clean选项来事先清除无用pid）。FastCGI进程也有同样的问题。<br />有一个非常好的进程监控程序称之为Monit。Rubyworks也搭配了Monit来监控Mongrel的进程，而不使用Mongrel_cluster。并且monit可以限制mongrel的进程的内存用量，防止出现内存溢出的问题等。同时monit也可以监控其他的进程如我们的前端。<br />
<h2><span><span>总结</span></span></h2>
Rails的部署方式的核心问题就在于解决一、Rails本身是非线程安全，二、Ruby的线程性能差这两个问题上。本文列举了十余种常见的Rails部署方案，其中基于Lighttpd 1.5的几种解决方案都从原理上很好地解决了Rails部署的两大问题，而且有着不俗的性能。由于本案中的测试仅建立在我为公司的服务器端所做测试的基础上，并且设计、执行得不够严谨，仅仅具有一定的参考意义。另外限于我的能力和精力问题，通过<span>JRuby</span>借助JavaEE平台的部署方案未能进行评测，我相信也是很有潜力的方案。</div>
</div>
</div>
<p>不同的部署方式都有各自的优势，大家需要根据各自所开发的应用的特点和服务器特点来选择恰当的部署方式，例如跨平台性、易用性。<br />这些方案虽然是针对Ruby on Rails应用的，但是其中的原理是通用的，也希望能对大家在其他应用的部署和架构上有些启发。</p>
<p>&nbsp;</p>
<p><a href="http://docs.google.com/View?docid=ddcvzh74_28f9xppqfh">http://docs.google.com/View?docid=ddcvzh74_28f9xppqfh</a></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><a href="http://hi.baidu.com/gsxu/blog/item/e3aa518d11aa1b14b21bbae9.html">http://hi.baidu.com/gsxu/blog/item/e3aa518d11aa1b14b21bbae9.html</a></p>
          <br/>
          <span style="color:red;">
            <a href="http://tianshi0253.javaeye.com/blog/229173#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 18 Aug 2008 13:40:03 +0800</pubDate>
        <link>http://tianshi0253.javaeye.com/blog/229173</link>
        <guid>http://tianshi0253.javaeye.com/blog/229173</guid>
      </item>
      <item>
        <title>浅析Ruby on Rails部署方案(二)</title>
        <author>tianshi0253</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://tianshi0253.javaeye.com">tianshi0253</a>&nbsp;
          链接：<a href="http://tianshi0253.javaeye.com/blog/229172" style="color:red;">http://tianshi0253.javaeye.com/blog/229172</a>&nbsp;
          发表时间: 2008年08月18日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <div class="cnt">
<h3>后端的问题</h3>
<p>在前面的测试报告中，我们似乎看不出什么问题，好像即使处理速度不够，多开几个进程就可以了。这是因为测试是在比较理想的环境下进行的，而实际的生产环境情况要复杂得多。虽然Mongrel在此次测试的结果中显示了很好的稳定性，但是这并不能表示Mongrel就可以在生产环境中同样保持很好的稳定性。</p>
<p>原因在于Ruby的线程机制。但首先这里要强调的是，虽然Ruby的虚拟机有缺陷，线程是伪线程，线程性能较差，但这并不妨碍Ruby可以做一些同步或异步的工作（可以参考Erlang）。问题的关键在于Rails本身不是线程安全的，如果查看Mongrel的代码则会发现，Mongrel在调用Rails的分发器之前就加了锁，直到Rails处理完这个请求。请参考<code><span style="font-family: 新宋体;">/var/lib/gems/1.8/gems/mongrel-1.1.4/lib/mongrel/rails.rb</span></code>第74行（不同的系统上的目录有所不同，不同版本的mongrel，代码出现的位置也可能不同）如下：</p>
<pre><span style="background-color: #ffff00;">@guard.synchronize {</span>
              @active_request_path = request.params[Mongrel::Const::PATH_INFO] 
              Dispatcher.dispatch(cgi, 
                ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS, 
                response.body)
              @active_request_path = nil
            }</pre>
<p>我们知道，对于锁的粒度一般是越小越好的，而这里的锁就这是造成问题的关键原因。</p>
<p>假设一个Mongrel当前的请求被阻塞在Rails的代码中（比如一个较长的查询），后续的请求就会被阻塞，假如阻塞的时间足够长，导致队列中请求满了，那么接下来就是出现大量时间花费在上下文切换和锁的争用上。</p>
<p>这就是为什么Rails应该以进程方式来运行的原因。所以之后很多人致力于开发单线程、非阻塞IO的方式来处理请求，这样做的好处是可以减少对连接的创建、关闭的等待时间，以及省去对锁的操作&mdash;&mdash;锁操作是非常昂贵的。但它并不能解决Rails应用程序中被阻塞时的并发问题。同样地，FastCGI也无法解决这个问题。</p>
<p>而新的Ruby框架如Merb，则实现了线程安全，解决了这个问题，因此可以利用线程的方式来提高并发性。Ebb也宣称其线程模式的运行方式在运行Merb可以承受更大的压力。</p>
<p>为了解决这个，我们要做的就是使用多个进程来进行服务，并限制从前端到后端的链接数。</p>
<p>而使用进程方式的问题就在于，进程之间不能共享信息，进程比线程占用更多的资源。我给公司写的程序在启动完毕Mongrel之后，单个进程占用内存为34M，随着访问量的不断增加，内存占用也会逐渐增长，如果遇到大量并发请求，内存会增长地更快。</p>
<h3>前端的问题</h3>
前面列举的各种前端，除了Swiftiply因为是专门为Ruby设计的，其他的程序都十分通用，网上有非常多的比较，在此我们直接跳过对于前端的测试，直接讨论对于前端的问题。<br /><span><strong>Apache</strong></span><br />Apache的问题前面提到过，Apache占用资源非常多，在Prefork方式下，单个进程占用内存在5至10M，而占用的VMSize则非常巨大，随着服务的连接数增长，实际内存占用空间可以很容易达到内存极限，而VMSize可以达到十几倍于实际内存的数量。虽然Apache和Linux的稳定性让它和系统不至于崩溃，但这确实是很可怕和危险的数字。相对而言，Lighttpd、Nginx等则每个进程只占用1到2兆内存，便可以提供于与Apache相匹配的能力。<br />而前面也提到了，Rails也最好使用进程方式来运行，Rails占用内存更加巨大，加上为了给进程运行中一些缓冲的空间，一般一台1G内存的VPS建议最多只开10个Mongrel进程，也就只能同时服务10个链接。而如果Apache也与Rails争内存的话，便会使原本就紧张的内存空间更紧张，接着开始使用很多交换分区，CPU便把大量时间花费在内存交换上。所以，除非使用Passenger方式部署Rails应用和在Windows平台下部署，其他情况下推荐考虑别的部署方式。<br />如果不得不用Apache+Mongrel方式，也不用担心，因为Apache的负载均衡非常强大，不仅支持不同的后端，还实现了链接池的概念，通过smax和max两个水平线来控制到后端的数量，具体可以查看Apache的ProxyPass指令的解释。如下图：<br />
<blockquote>1&lt;=min&lt;=smax&lt;=max&lt;=系统限制<br /></blockquote>
在1到min之间是与后端创建的最少的连接数，一般是持久连接，min到smax之间是根据请求数量创建的动态链接的数量，smax到max之间的连接被放入连接池中，被给定一个生存时间ttl，大于max数量的链接将等待timeout时间。其中在Prefork模式下系统限制始终为1，Worker方式下为每个进程的线程数。<br />有了这些参数，使用Apache+Mongrel的部署方式我们便可以控制链接到Mongrel的链接数。<br />而且Apache也支持到后端服务器的持久链接，即KeepAlive<br /><span><strong>Lighttpd<br /></strong></span>如果采用尚未发布的Lighttpd 1.5，那么基本上可以说是没有什么问题，不仅占用资源少，功能也十分齐全，几乎无可挑剔。即可以支持HTTP后端的负载均衡，也支持FastCGI后端，同时还能限制到后端的链接数，并且可以支持不同的负载均衡算法。<br />虽然Lighttpd1.5也实现了链接池，但他不像Apache实现了两层的水平线，他只有一个最大链接池尺寸的参数来控制到后端的链接的数量，而没有设计等候池，所以超时时间不容易设置，在手面的测试中会显示出来。<br /><span><strong>Nginx<br /></strong></span><span>Nginx在HTTP分发上性能非常好，</span><span>但</span><span>不支持链接数的限制，同时</span><span>只实现了round-robin算法，而且</span><span>不支持FastCGI后端的分发。<br /><span><strong>HAproxy</strong></span><br />HAproxy作为一个负载均衡反向代理而言，功能十分强大，他和Apache一样，实现了对后端的两层的连接池，请求的控制也能好，同时占用资源也十分少。由于HAproxy不能服务静态页面，所以我们通常需要将HAproxy和其他几个软件搭配使用，或者在系统的架构上进行一些别的处理。<br /><span><strong>Swiftiply</strong></span><br />Swiftiply用Ruby写成，</span><span>即便使用了一些C扩展</span><span>，性能到底如何还是值得怀疑。Swiftiply不仅能实现分发，还能实现虚拟主机的功能来绑定不同域名。但其工作机制<br /></span>
<h3><span>前后端搭配的测试</span></h3>
<span>各种前端的，我在这里要测试的性能主要是对于动态请求的响应速度，所以本案中的某些配置既没有考虑使用Rewrite或其他方式对静态文件进行单独处理（除了Passenger和Swiftiply默认配置便实现了这个功能），也不考虑测试到前端的KeepAlive请求。主要测试以下的组合：<br /></span>
<ul>
<li>Apache + Passenger </li>
<li>Nginx + Mongrel </li>
<li>Nginx + Evented Mongrel </li>
<li>Nginx + Thin </li>
<li>Swiftiply + Swiftiplied Mongrel </li>
<li>Swiftiply + Thin </li>
<li>HAproxy + Mongrel </li>
<li>HAproxy + Thin </li>
<li>Lighttpd + Mongrel </li>
<li>Lighttpd + Thin </li>
<li>Lighttpd + FastCGI/Socket </li>
<li>Lighttpd + FastCGI/TCP </li>
</ul>
做服务器的被测试机器为ThinkPad T43，Intel Pentium M 1.86G，1.5G RAM，系统为Ubuntu 8.04。发送请求的是无线局域网中的另外一台笔记本，运行Vista。两台机器通过TP-Link WR340G+ 801.11g 54MB的无线局域网相连。<br />前端和后端处于同一台机器上，所有的后端都设为10个进程，绑定于30000-30009端口，Passenger设置为最大生成10个进程，Swiftiply则是绑定于4000端口监听。FastCGI的socket路径为/tmp/rails[0-9].sock。<br /><span><strong>Apache的配置</strong></span><br />Apache版本为2.2.8，编译配置选项如下：<br />
<blockquote><span>CFLAGS="-march=pentium4 -O3 -pipe -fomit-frame-pointer" ./configure --prefix=/opt/apache2 --disable-authn-file --disable-authn-default --disable-authz-host --disable-authz-groupfile --disable-authz-user --disable-authz-default --disable-auth-basic --disable-include --disable-filter --disable-charset-lite --disable-log-config --disable-env --disable-setenvif --disable-mime --disable-status --disable-autoindex --disable-asis --disable-cgid --disable-cgi --disable-negotiation --disable-dir --disable-actions --disable-userdir --disable-alias --enable-suexec --enable-http --enable-suexec --enable-proxy --enable-proxy-http --enable-proxy-balancer --enable-static-support --enable-static-htpasswd --enable-static-htdigest --enable-static-rotatelogs --enable-static-logresolve --enable-static-htdbm --enable-static-ab --enable-static-checkgid --with-mpm=prefork</span><br /></blockquote>
这个配置尽量减少了Apache所加载的模块，仅启用和测试相关的以提升Apache的性能。另外，这种配置下必须删除rails应用的public目录下默认的.htaccess文件，否则无法使Passenger成功处理静态文件。<br />Passenger推荐使用Apache的Prefork工作方式，但为了做一个对比，我还会给出Worker方式的Apache配合Passenger的性能比较。<br />Apache的配置文件httpd.conf为：<br />
<blockquote>
<pre>ServerRoot "/opt/apache2"

Listen 8080

&lt;IfModule !mpm_netware_module&gt;
&lt;IfModule !mpm_winnt_module&gt;
User shiningray
Group shiningray

&lt;/IfModule&gt;
&lt;/IfModule&gt;

&lt;IfModule !mpm_netware_module&gt;
    PidFile "logs/httpd.pid"
&lt;/IfModule&gt;

&lt;IfModule !mpm_winnt_module&gt;
&lt;IfModule !mpm_netware_module&gt;
LockFile "logs/accept.lock"
&lt;/IfModule&gt;
&lt;/IfModule&gt;
&lt;IfModule mpm_worker_module&gt;
    ThreadLimit 20000
    ServerLimit 32
    StartServers          2
    MaxClients          8192
    MinSpareThreads      64
    MaxSpareThreads      1024
    ThreadsPerChild      256
    MaxRequestsPerChild   0
&lt;/IfModule&gt;
&lt;IfModule mpm_prefork_module&gt;
    ServerLimit 1024
    StartServers          5
    MinSpareServers       5
    MaxSpareServers      10
    MaxClients          1024
    MaxRequestsPerChild   0
&lt;/IfModule&gt;

ServerAdmin admin@shiningray.cn

ServerName 127.0.0.1:8080

DocumentRoot "/var/www/"

&lt;IfModule dir_module&gt;
    DirectoryIndex index.html
&lt;/IfModule&gt;

ErrorLog "logs/error_log"

KeepAlive off
MaxKeepAliveRequests 1024

NameVirtualHost *:8080

<span style="background-color: #ffff00;">LoadModule passenger_module "/var/lib/gems/1.8/gems/passenger-1.0.1/ext/apache2/mod_passenger.so"</span><br style="background-color: #ffff00;" /><span style="background-color: #ffff00;">RailsSpawnServer /var/lib/gems/1.8/bin/passenger-spawn-server</span><br style="background-color: #ffff00;" /><span style="background-color: #ffff00;">RailsAutoDetect off</span><br style="background-color: #ffff00;" /><span style="background-color: #ffff00;">&lt;VirtualHost *:8080&gt;</span><br style="background-color: #ffff00;" /><span style="background-color: #ffff00;">    ServerName localhost</span><br style="background-color: #ffff00;" /><span style="background-color: #ffff00;">    DocumentRoot /home/shiningray/NetBeansProjects/botadmin/public</span><br style="background-color: #ffff00;" /><span style="background-color: #ffff00;">    RailsBaseURI /</span><br style="background-color: #ffff00;" /><span style="background-color: #ffff00;">    RailsEnv "production"</span><br style="background-color: #ffff00;" /><span style="background-color: #ffff00;">    RailsMaxPoolSize 10</span><br style="background-color: #ffff00;" /><span style="background-color: #ffff00;">&lt;/VirtualHost&gt;</span></pre>
</blockquote>
<span><strong>Nginx的配置</strong></span><br />Nginx 0.6.29，编译配置选项如下：<br />
<blockquote>
<pre>./configure --prefix=/opt/nginx --cpu-opt=pentium4</pre>
</blockquote>
<p>配置文件nginx.conf如下：</p>
<span><strong>Swiftiply的配置<br /></strong></span><span>我直接通过</span>&ldquo;gem i swiftiply&rdquo;来安装了Swiftiply，Swiftiply的配置文件如下：<br />
<blockquote><span>cluster_address: 0.0.0.0</span><br /><span>cluster_port: 8080</span><br /><span>daemonize: false</span><br /><span>map:</span><br /><span>- incoming:</span><br /><span>&nbsp;&nbsp;&nbsp; - localhost</span><br /><span>&nbsp;&nbsp;&nbsp; - 192.168.1.100</span><br /><span>&nbsp;&nbsp;&nbsp; outgoing: 127.0.0.1:4000</span><br /><span>&nbsp;&nbsp;&nbsp; default: true</span><br /><span>&nbsp;&nbsp;&nbsp; docroot: /home/shiningray/NetBeansProjects/botadmin/public</span><br /><span>&nbsp;&nbsp;&nbsp; cache_extensions:</span><br /><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - htm</span><br /><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - html</span><br /><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - txt</span><br /></blockquote>
<br /><span><strong>HAproxy的配置</strong></span><br />HAproxy 1.2.17，编译选项为<br />
<blockquote><span>make TARGET="linux26" CPU="pentium4"</span><br /></blockquote>
配置文件haproxy.cfg为：<br />
<blockquote><span># this config needs haproxy-1.1.28 or haproxy-1.2.1</span><br /><br /><span>global</span><br /><span>&nbsp;&nbsp;&nbsp; log 127.0.0.1&nbsp;&nbsp;&nbsp; local0</span><br /><span>&nbsp;&nbsp;&nbsp; log 127.0.0.1&nbsp;&nbsp;&nbsp; local1 notice</span><br /><span>&nbsp;&nbsp;&nbsp; maxconn 2000</span><br /><span>defaults</span><br /><span>&nbsp;&nbsp;&nbsp; log&nbsp;&nbsp;&nbsp; global</span><br /><span>&nbsp;&nbsp;&nbsp; mode&nbsp;&nbsp;&nbsp; http</span><br /><span>&nbsp;&nbsp;&nbsp; option&nbsp;&nbsp;&nbsp; httplog</span><br /><span>&nbsp;&nbsp;&nbsp; option&nbsp;&nbsp;&nbsp; dontlognull</span><br /><span>&nbsp;&nbsp;&nbsp; retries&nbsp;&nbsp;&nbsp; 3</span><br /><span>&nbsp;&nbsp;&nbsp; redispatch</span><br /><span>&nbsp;&nbsp;&nbsp; maxconn&nbsp;&nbsp;&nbsp; 2000</span><br /><span>&nbsp;&nbsp;&nbsp; contimeout&nbsp;&nbsp;&nbsp; 5000</span><br /><span>&nbsp;&nbsp;&nbsp; clitimeout&nbsp;&nbsp;&nbsp; 50000</span><br /><span>&nbsp;&nbsp;&nbsp; srvtimeout&nbsp;&nbsp;&nbsp; 50000</span><br /><br /><span>listen localhost 0.0.0.0:8080</span><br /><span>&nbsp;&nbsp;&nbsp; balance&nbsp;&nbsp;&nbsp; roundrobin</span><br /><span>&nbsp;&nbsp;&nbsp; server mongrel_30000 127.0.0.1:30000 </span><span style="background-color: #ffff00;">maxconn 1</span><br /><span>&nbsp;&nbsp;&nbsp; server mongrel_30001 127.0.0.1:30001 maxconn 1</span><br /><span>&nbsp;&nbsp;&nbsp; server mongrel_30002 127.0.0.1:30002 maxconn 1</span><br /><span>&nbsp;&nbsp;&nbsp; server mongrel_30003 127.0.0.1:30003 maxconn 1</span><br /><span>&nbsp;&nbsp;&nbsp; server mongrel_30004 127.0.0.1:30004 maxconn 1</span><br /><span>&nbsp;&nbsp;&nbsp; server mongrel_30005 127.0.0.1:30005 maxconn 1</span><br /><span>&nbsp;&nbsp;&nbsp; server mongrel_30006 127.0.0.1:30006 maxconn 1</span><br /><span>&nbsp;&nbsp;&nbsp; server mongrel_30007 127.0.0.1:30007 maxconn 1</span><br /><span>&nbsp;&nbsp;&nbsp; server mongrel_30008 127.0.0.1:30008 maxconn 1</span><br /><span>&nbsp;&nbsp;&nbsp; server mongrel_30009 127.0.0.1:30009 maxconn 1</span><br /></blockquote>
<br />maxconn参数表示限制到后端的连接数，我会在测试中调整这些参数来看对性能的影响。<br /><span><strong>Lighttpd的配置</strong></span><br />Lighttpd版本为 1.5.0 <a href="http://blog.lighttpd.net/articles/2007/09/06/pre-release-lighttpd-1-5-0-r1992">r1922</a><br />编译配置选项为：<br />
<blockquote><span>./configure --prefix=/opt/lighttpd</span><br /></blockquote>
配置文件lighttpd为<br />
<blockquote><span>server.modules&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = (</span><br /><span>&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; "mod_rewrite",</span><br /><span>&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; "mod_access",</span><br /><span>&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; "mod_proxy_core",</span><br /><span>&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; "mod_proxy_backend_http",</span><br /><span>&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; "mod_proxy_backend_fastcgi")</span><br /><br /><span>server.document-root&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = "/home/shiningray/NetBeansProjects/botadmin/public"</span><br /><span>server.bind&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = "0.0.0.0"</span><br /><span>server.port&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = 8080</span><br /><span>server.pid-file&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = "/opt/lighttpd/logs/lighttpd.pid"</span><br /><span>server.username&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = "shiningray"</span><br /><span>server.groupname&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = "shiningray"</span><br /><span>server.errorlog&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = "/opt/lighttpd/logs/lighttpd.error.log"</span><br /><br /><span>url.rewrite-once = ( "^/.*$" =&gt; "/dispatch.fcgi" )</span><br /><br /><span>$HTTP["url"] =~ "\.fcgi$" {</span><br /><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; proxy-core.balancer&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = "round-robin"</span><br /><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; proxy-core.allow-x-sendfile&nbsp;&nbsp;&nbsp;&nbsp; = "enable"</span><br /><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; proxy-core.protocol&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = "fastcgi"</span><br /><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="background-color: #ffff00;">proxy-core.backends&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = (</span><br style="background-color: #ffff00;" /><span style="background-color: #ffff00;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "</span><span style="background-color: #ffff00;">unix:/tmp/rails0.sock</span><span style="background-color: #ffff00;">",</span><br style="background-color: #ffff00;" /><span style="background-color: #ffff00;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "unix:/tmp/rails1.sock",</span><br style="background-color: #ffff00;" /><span style="background-color: #ffff00;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "unix:/tmp/rails2.sock",</span><br style="background-color: #ffff00;" /><span style="background-color: #ffff00;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "unix:/tmp/rails3.sock",</span><br style="background-color: #ffff00;" /><span style="background-color: #ffff00;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "unix:/tmp/rails4.sock",</span><br style="background-color: #ffff00;" /><span style="background-color: #ffff00;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "unix:/tmp/rails5.sock",</span><br style="background-color: #ffff00;" /><span style="background-color: #ffff00;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "unix:/tmp/rails6.sock",</span><br style="background-color: #ffff00;" /><span style="background-color: #ffff00;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "unix:/tmp/rails7.sock",</span><br style="background-color: #ffff00;" /><span style="background-color: #ffff00;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "unix:/tmp/rails8.sock",</span><br style="background-color: #ffff00;" /><span style="background-color: #ffff00;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "unix:/tmp/rails9.sock"</span><br style="background-color: #ffff00;" /><span style="background-color: #ffff00;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; )</span><br /><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="background-color: #ffff00;">proxy-core.max-pool-size=64</span><br /><span>}</span><br /></blockquote>
FastCGI的TCP方式则是将proxy-core-backends参数中的后端改为：<br />
<blockquote><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "127.0.0.1:30000",</span><br /><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "127.0.0.1:30001",</span><br /><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "127.0.0.1:30002",</span><br /><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "127.0.0.1:30003",</span><br /><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "127.0.0.1:30004",</span><br /><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "127.0.0.1:30005",</span><br /><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "127.0.0.1:30006",</span><br /><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "127.0.0.1:30007",</span><br /><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "127.0.0.1:30008",</span><br /><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "127.0.0.1:30009",</span><br /></blockquote>
Lighttpd使用HTTP后端的配置文件为：<br />
<blockquote><span>server.modules&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = (</span><br /><span>&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; "mod_rewrite",</span><br /><span>&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; "mod_access",</span><br /><span>&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; "mod_proxy_core",</span><br /><span>&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; "mod_proxy_backend_http",</span><br /><span>&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; "mod_proxy_backend_fastcgi")</span><br /><br /><span>server.document-root&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = "/home/shiningray/NetBeansProjects/botadmin/public"</span><br /><span>server.bind&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = "0.0.0.0"</span><br /><span>server.port&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = 8080</span><br /><span>server.pid-file&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = "/opt/lighttpd/logs/lighttpd.pid"</span><br /><span>server.username&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = "shiningray"</span><br /><span>server.groupname&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = "shiningray"</span><br /><span>server.errorlog&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = "/opt/lighttpd/logs/lighttpd.error.log"</span><br /><br /><span>$HTTP["url"] =~ "^.*$" {</span><br /><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; proxy-core.balancer&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = "round-robin"</span><br /><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; proxy-core.allow-x-sendfile&nbsp;&nbsp;&nbsp;&nbsp; = "enable"</span><br /><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; proxy-core.protocol&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = "http"</span><br /><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; proxy-core.backends&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = (</span><br /><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "127.0.0.1:30000",</span><br /><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "127.0.0.1:30001",</span><br /><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "127.0.0.1:30002",</span><br /><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "127.0.0.1:30003",</span><br /><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "127.0.0.1:30004",</span><br /><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "127.0.0.1:30005",</span><br /><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "127.0.0.1:30006",</span><br /><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "127.0.0.1:30007",</span><br /><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "127.0.0.1:30008",</span><br /><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "127.0.0.1:30009",</span><br /><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; )</span><br /><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; proxy-core.max-pool-size=1</span><br /><span>}</span><br /></blockquote>
<br />proxy-core.max-pool-size参数表示限制到后端的连接数，还将分别调整此参数来看对性能的影响。</div>
<p>&nbsp;</p>
          <br/>
          <span style="color:red;">
            <a href="http://tianshi0253.javaeye.com/blog/229172#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 18 Aug 2008 13:38:30 +0800</pubDate>
        <link>http://tianshi0253.javaeye.com/blog/229172</link>
        <guid>http://tianshi0253.javaeye.com/blog/229172</guid>
      </item>
      <item>
        <title>浅析Ruby on Rails部署方案(一)</title>
        <author>tianshi0253</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://tianshi0253.javaeye.com">tianshi0253</a>&nbsp;
          链接：<a href="http://tianshi0253.javaeye.com/blog/229170" style="color:red;">http://tianshi0253.javaeye.com/blog/229170</a>&nbsp;
          发表时间: 2008年08月18日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <div class="tit">浅析Ruby on Rails部署方案(一)</div>
<div class="date">2008-07-28 16:11</div>
<table border="0" style="table-layout: fixed;">
<tbody>
<tr>
<td>
<div class="cnt" id="blog_text">
<div class="date">作者：ShiningRay</div>
<table class="FCK__ShowTableBorders" border="0" style="table-layout: fixed;">
<tbody>
<tr>
<td>
<div class="cnt">
<h2>前言</h2>
<p>2006初，我接到了公司分配的一个遗留项目，让我负责一个基于C/S的系统的服务器端。其实是系统是基于HTTP协议的，因为负责客户端的同事对于服务器端编程不甚了解，虽然使用PHP对熟悉C＋＋的他来说是驾轻就熟，但是在进一步实现更多的功能和更高的性能上就捉襟见肘了。项目是在非常突然的情况下交给我的，因为该同事在客户端上有更多的事情要做。我在分析了他的数据库结构和PHP源代码之后，决定按照与客户端的通讯协议重写他的服务器端。为了能应付老板苛刻的时间限制，我打算使用正在学习的Ruby on Rails。后来，项目在功能上非常顺利地交付了。</p>
<p>两年过去了，随着客户端数量的不断增加、客户端功能的增加、与服务器端交互数据的增加、老板对功能的要求不断增加，我在这个项目上走了不少弯路，尤其是在部署&mdash;&mdash;或者说是架构&mdash;&mdash;方面。</p>
<p>我遇到的最大的问题就在于并发链接数上。服务器与客户端的每次交互的数据量并不大，但内容无法缓存。起初用的是Nginx/Apache+Mongrel的部署方式，但当遇到大量并发请求时，常常会遇到Mongrel进程死掉的情况。而客户端的用户在无法登录客户端的时候，经常会反复尝试，加重了服务器的负担、导致最后所有的Mongrel进程都挂掉。</p>
<p>最后，经过不懈努力，在现有的3台低端服务器上，可以满足每天500万次的请求。在这里，我将我的一些心得和研究成果总结出来，与大家分享。</p>
<h2>简介</h2>
<p><a href="http://www.rubyonrails.org/" title="Ruby on Rails">Ruby on Rails</a>的部署方案基本上都是由两层结构组成，前端做请求的分发，后端以多个Ruby进程接受并处理请求，主要的差别便是其中的通讯协议，比如使用<a href="http://www.fastcgi.com/" title="FastCGI">FastCGI</a> 或者是HTTP。这里讨论的局限于一台服务器，所以我不称之为架构方案，而仅仅是部署配置方案。</p>
<h3>前端的选择</h3>
<p>前端也有很多种不同的选择，我们来看一下开源领域主流的选择：</p>
<p><strong><a href="http://httpd.apache.org/" title="Apache">Apache</a></strong></p>
<p>Apache功能十分强大，稳定性也十分好，是全球市场占有率最高的Web服务器。与它搭配的Rails部署方案也有很多，如：</p>
<ul>
<li>Apache+mod_ruby：类似于mod_php、mod_python，将Ruby解释器作为一个模块加载到Apache中。（mod_ruby以及停止更新，所以并不流行） </li>
<li>Apache+mod_fastcgi或Apache+mod_fcgid，通过FastCGI协议与Rails进程通讯。（mod_fastcgi由于设计有缺陷因此仅推荐使用mod_fcgid） </li>
<li>Apache2.2 + mod_proxy_balancer：使用反向代理负载均衡器，通过HTTP与后端的Ruby Web服务器通讯，如Mongrel/Thin/Ebb等。 </li>
<li>Apache2 + <a href="http://www.modrails.com/" title="Passenger">Passenger</a> (mod_rails) ：新兴的模块方式，部署方式十分简单，大致的方式和FastCGI差不多，只不过与后台进程间的通讯协议使用了它自己的协议。 </li>
</ul>
Apache的一大问题就是Apache的性能和一些轻量级新秀Web服务器相比差很多，原因在于Apache到目前为止仅有prefork（进程）模式和worker（线程）模式的MPM是稳定的，这两种工作方式每服务一个链接，就需要创建一个进程或线程，而新兴的轻量级Web服务器，则都很好地利用内核的事件机制提高性能，极大地减少了线程或进程数量，而Apache的event（事件）模式的MPM依然在开发中。例如，Apache的请求处理速度、并发处理能力都比Lighttpd慢3-5倍，内存消耗和CPU消耗也高出很多。另一个问题是，mod_proxy_balancer虽然功能强大，但分发性能不高，比HAproxy或Nginx差很多。<br />基于这些问题，所以Apache+FastCGI/mod_proxy_balancer的部署方案并不流行，然而新兴的Passenger由于部署方式出奇简单，使得Apache可能会重新在Rails部署上再次占据一席之地。<br />
<p><strong><a href="http://www.lighttpd.net/" title="Lighttpd">Lighttpd</a></strong></p>
轻量级高性能Web服务器，服务静态文件的性能非常高。目前的稳定版本Lighttpd1.4中的反向代理模块有所缺陷，此模块会在1.5中全部重写并提供更好的负载均衡算法，可以对基于FastCGI、HTTP、AJP、SCGI的后端进行请求分发。Lighttpd+FastCGI是目前非常流行的一种部署方式，国内著名的JavaEye便采用的这种方式，<a href="http://www.javaeye.com/" title="JavaEye">JavaEye</a> 负责人之一Robbin对Lighttpd+FastCGI的方式推崇备至。<br />
<p><strong><a href="http://nginx.net/" title="Nginx">Nginx</a></strong></p>
Nginx也是一个轻量级高性能的Web服务器/反向代理负载均衡器。Nginx也支持FastCGI，但不像Lighttpd 1.5支持对FastCGI后端的负载均衡调度。Nginx+Mongrel的方式受到很多人推荐。<br />
<p><strong><a href="http://swiftiply.swiftcore.org/" title="HAproxy">HAproxy</a></strong></p>
HAproxy是一个纯粹的反向代理均衡器，非常小巧，基于事件机制。它不仅可以做HTTP反向代理，还可以作TCP的转发，所以同样可以对FastCGI做负载均衡。在做HTTP反向代的同时可以对请求作一些修改控制。在ThoughtWorks推出的Rubyworks这个Rails应用套件中用到了它，原因是它能很方便地限制到后端服务器的链接数量。但HAproxy不是Web服务器，它不能处理静态文件。<br />
<p><strong><a href="http://swiftiply.swiftcore.org/" title="Swiftiply">Swiftiply</a></strong></p>
<p>Swiftiply是一个负载均衡反向代理，但它与后端服务器的通讯方式很特殊&mdash;&mdash;它开放一个端口让后端服务器主动链接到Swiftiply，这样可以与后端服务器建立一个持久链接，而且无须重启就可以非常容易地增加新的后端。Swiftiply使用了Ruby的<a href="http://rubyeventmachine.com/" title="EventMachine">EventMachine</a> 实现了实践驱动机制。支持它的协议的后端有Swiftiplied Mongrel和Thin。</p>
<hr style="width: 100%; height: 2px;" />
<h3>后端的选择</h3>
<p>后端Rails的运行方式可以通过FastCGI或者是Ruby应用服务器的方式，CGI和mod_ruby已经不推荐。可以选的Ruby服务器有有：</p>
<p><strong><a href="http://www.webrick.org/" title="WEBrick">WEBrick </a></strong></p>
<p>WEBrick是Ruby标准库中自带的默认HTTP服务器，完全使用Ruby写成，性能较差。利用了Ruby的线程来服务并发的链接。有人写了利用事件机制来提高性能的补丁，由于应用少，不在讨论范围。</p>
<p><strong><a href="http://mongrel.rubyforge.org/" title="Mongrel">Mongrel</a></strong></p>
<p>目前最为成熟Ruby应用服务器。使用了C++写的HTTP头解析器，所以具有较好的性能，它同样利用了Ruby的线程机制来服务并发的链接。Mongrel的优点是稳定，兼容性好，很多平台上都可以使用，包括JRuby。Swiftiply小组还写了一个利用EventMachine的Mongrel修改版，称之为Evented Mongrel，使用单线程、事件驱动方式。</p>
<p><strong><a href="http://code.macournoyer.com/thin/" title="Thin">Thin</a></strong></p>
<p>利用事件驱动机制的Ruby应用服务器，并借用了Mongrel的HTTP头解析器，事件机制的部分同样是利用了EventMachine。相比Mongrel来说，稳定性和兼容性略差。例如，我在CentOS 3.2的平台上编译后启动便崩溃。</p>
<p><strong><a href="http://ebb.rubyforge.org/" title="Ebb">Ebb</a></strong></p>
<p>又一个高性能的Ruby应用服务器，有多种工作模式，可以使用事件驱动机制，也可以使用线程模式。据说线程模式服务Merb（另一个Ruby的Web应用框架）可以达到更好的性能。和Thin一样，由于刚出现不久，还不是非常稳定。它要求Glibc 2以上版本，所以老版本的Linux无法使用，另外我在自己的Ubuntu 8.04上编译的版本在运行中无法正常接受链接，所以在本文中没有涉及到Ebb的测试。</p>
<h2>性能测试</h2>
<p>为了了解各种前、后端程序搭配的方式各自的性能如何，必须做大量的测试。下面我将我为公司做的这个项目所进行的一系列测试的结果展示出来，并做简单的分析。</p>
<p>我利用了Apache Benchmark（ab），对服务器端压力最大的身份验证部分进行压力测试。</p>
<blockquote><span><strong>注意</strong></span>：这些测试都相对比较简单和宽松，很多因素、细节没有考虑进去，只是作为一个参考。而且，对于不同的Rails应用、应用中的不同部分，都应该做独立的测试，来找到最合适的部署方法。<br /></blockquote>
<h3>后端的测试</h3>
首先，我们先测试我们所使用的后端在同一台机器上的性能，由于前端通常通过内部环路或UNIX套接字与后端通讯，所以我没有从另外一台机器上进行测试。由于ab不能直接测试FastCGI，为了能了解FastCGI的性能，我通过Nginx来与FastCGI通讯，分别测试TCP和Unix套接字的性能，将这个测试结果做个参考。
<p>&nbsp;</p>
<p>测试机器为ThinkPad T43，Intel Pentium M 1.86G，1.5G RAM，系统为Ubuntu 8.04，内核版本为2.6.24-16。</p>
<p>被测试的对象的版本为：</p>
<ul>
<li>Mongrel 1.1.3，以及Evented Mongrel </li>
<li>Thin 0.8.1(EventMachine 0.10.0) </li>
<li>fcgi 0.8.7(Nginx 0.6.29) </li>
</ul>
<p>以上全部使用默认配置。测试方法是从1开始，以10为步长，到500的数值，作为并发链接数，每次测试1000个请求，得到的ab的报告中取每秒的请求数作为测试的结果。</p>
<p>由于Ebb没有能在我的系统上成功运行起来，所以尚未得到它的数据。其中Thin还支持KeepAlive，所以单独进行了测试，由于这个服务器的应用主要是动态内容，所以后面的测试都不测KeepAlive。</p>
<p>测试结果如下，左边的图是点和线，为了不让画面太乱，能清晰地了解的性能情况，我取了B样条，如右图：</p>
<div style="text-align: left;"><span><a href="http://docs.google.com/File?id=ddcvzh74_29cqh3t3dn_b" target="_blank"><img src="http://docs.google.com/File?id=ddcvzh74_29cqh3t3dn_b" alt="" style="float: left; margin: 1em 1em 0pt 0pt; width: 320px; height: 240px;" /></a></span></div>
<div style="padding-right: 0pt; padding-left: 0pt; padding-bottom: 1em; padding-top: 1em; text-align: left;"><a href="http://docs.google.com/File?id=ddcvzh74_30988s6r6x_b" target="_blank"><img src="http://docs.google.com/File?id=ddcvzh74_30988s6r6x_b" alt="" style="width: 320px; height: 240px;" /></a></div>
<p>我们从图上，在结合一些现有的知识，可以印证一些概念：</p>
<p>测试的前半部分FastCGI比HTTP快的原因是：</p>
<ul>
<li>由于FastCGI是二进制协议，避免了HTTP协议复杂的格式解析、生成的消耗&mdash;&mdash;这部分内容通常由更高效的前端服务器来完成。 </li>
<li>FastCGI与前端服务器之间建立的是持久链接，避免了大量的打开关闭套接字的操作。 </li>
</ul>
<p>我们也看到了起初支持KeepAlive的Thin处理请求的速度也很快，同样应该是得益于持久链接，减少了打开关闭套接字的操作而造成的。</p>
<p>两个FastCGI的测试，虽然TCP套接字的额外开销要比UNIX套接字高一点，但基本是接近的，因为这两者性能的差异与Rails应用本身的处理速度相比是很微小的。所以FastCGI无论是走TCP还是走Unix套接字性能都是接近的。</p>
<p>然而，当FastCGI接受的并发链接数量不断上升时，请求的处理速度不断降低，这是因为FastCGI的处理请求方式是阻塞的，每次只处理一个请求（可以从fcgi包中的代码中看出来），随着并发链接数量上升，维持链接的开销越来越大。同样的情况也发生在使用了KeepAlive的Thin中。</p>
<p>测试中，Mongrel的响应速度非常稳定。虽然性能在前250并发量的测试中占下风，但是随着并发链接数的上升，它利用线程的好处逐渐显现出来。Thin虽然使用了单线程，由于是基于事件驱动，与Mongrel性能相差不多，但稳定性则低了。</p>
<p>Evented Mongrel的性能令人印象深刻，在后半部的测试中占据了上风。同样使用了EventMachine的Thin，性能却不如它，我觉得可能在于：一、Mongrel不支持KeepAlive，Thin支持，所以需要作额外的考虑；二、可能是Mongrel的HTTP头解析器性能更好。关于第一个因素，我将最大持久链接数设为了0，最后的测试结果是比Mongrel还要低。至于进一步研究为什么，就不在本文讨论了。</p>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</td>
</tr>
</tbody>
</table>
          <br/>
          <span style="color:red;">
            <a href="http://tianshi0253.javaeye.com/blog/229170#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 18 Aug 2008 13:37:05 +0800</pubDate>
        <link>http://tianshi0253.javaeye.com/blog/229170</link>
        <guid>http://tianshi0253.javaeye.com/blog/229170</guid>
      </item>
      <item>
        <title>IE和FF下frame边框问题</title>
        <author>tianshi0253</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://tianshi0253.javaeye.com">tianshi0253</a>&nbsp;
          链接：<a href="http://tianshi0253.javaeye.com/blog/229081" style="color:red;">http://tianshi0253.javaeye.com/blog/229081</a>&nbsp;
          发表时间: 2008年08月18日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p><span style="font-size: medium; color: #ff0000;"><strong>无论在IE还是FF下面，都只需要定义frame的frameborder="0"就可以实现对frame的边框的隐藏。</strong></span></p>
          <br/>
          <span style="color:red;">
            <a href="http://tianshi0253.javaeye.com/blog/229081#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 18 Aug 2008 09:31:06 +0800</pubDate>
        <link>http://tianshi0253.javaeye.com/blog/229081</link>
        <guid>http://tianshi0253.javaeye.com/blog/229081</guid>
      </item>
      <item>
        <title>Rails、Sqlite的dll文件及安装</title>
        <author>tianshi0253</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://tianshi0253.javaeye.com">tianshi0253</a>&nbsp;
          链接：<a href="http://tianshi0253.javaeye.com/blog/229012" style="color:red;">http://tianshi0253.javaeye.com/blog/229012</a>&nbsp;
          发表时间: 2008年08月17日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p><strong>
<h3><a href="../../../blog/190654"></a></h3>
<div class="blog_content">[i][/i]本地安装rails2.0.2, 公司的网络有防火墙和代理，所以想通过&rdquo; gem install rails --include-dependencies&rdquo;安装就不行了，既然不行，那我们就本地安装rails好了。 <br /><br />先去http://rubyforge.org/frs/?group_id=307下载rails的安装包rails*.gem, <br />因为当前最新版本号是2.0.2，所以文件名为：rails-2.0.2.gem， <br /><br />把它放到ruby安装目录下并运行命令： <br />gem install rails， <br /><br />那么此时会提示你诸如rails requires activesupport = 2.0.2之类的信息， <br />实际上rails依赖的程序包不只activesupport，还有 <br />activerecord,actionpack,actionmailer,activeresource, <br /><br />去http://rubyforge.org/projects/程序包名/， <br /><br />例如如果要下载activesupport，则下载地址为：http://rubyforge.org/projects/activesupport/， <br /><br />依次下载rails所依赖的程序包后，然后逐一安装， <br /><br />命令同rails的安装：gem install activesupport. <br /><br />安装完所有的程序保后，运行gem install rails就可以完成rails的安装。 <br /><br />安装后，敲入命令rails &ndash;v 就会看到当前rails的版本号。</div>
</strong></p>
<p><strong></strong></p>
<p><strong>安装SQLite</strong></p>
<p>SQLite 是一个轻量级的sql风格数据库.可以执行大部分sql92标准</p>
<p>SQLite全部安装只有244kb,包括命令行客户端和DLL文件</p>
<p>SQLite不用安装服务进程，就像Access数据库一样使用方便</p>
<p>安装只需要2个文件</p>
<ol>
<li>SQLite <span class="caps">DLL</span> </li>
<li>SQLite command-line client for creating tables </li>
</ol>
<p><code><span style="font-family: 新宋体;"><span style="font-family: Arial;">添加</span>sqlite3.exe</span></code> 和<span style="font-family: 新宋体;">sqlite3<code>.dll</code></span> 到系统的path下，我放在了c:\windows\system32下了</p>
<p><strong>安装sqlite3-ruby.gem</strong></p>
<p>gem install sqlite3-ruby</p>
<p>Attempting local installation of 'sqlite3'<br />Local gem file not found: sqlite3*.gem<br />Attempting remote installation of 'sqlite3'<br />Select which gem to install for your platform (i386-mswin32)<br />1. sqlite3-ruby 1.1.0 (mswin32)<br />2. sqlite3-ruby 1.1.0 (ruby)<br />3. sqlite3-ruby 1.0.1 (ruby)<br />...<br />&gt;<br /><br />选择 1 安装sqlite3-ruby 1.1.0(mswin32) </p>
<p>现在好像2才是sqlite3-ruby 1.1.0(mswin32),总之选择(mswin32)就对了</p>
<p><strong>安装图像管理工具（也可以不用，直接用命令行也很方便）</strong></p>
<p><a href="http://sqlitebrowser.sourceforge.net/">http://sqlitebrowser.sourceforge.net/</a></p>
<p><strong>创建数据库</strong></p>
<p>进入项目所在目录，比如我的项目是testsql</p>
<p>d:\work\testsql&gt;sqlite db\test.db</p>
<p>上面命令就在db目录下，创建了一个test.db数据库</p>
<p><strong>配置database.yml文件，访问test.db数据库</strong></p>
<p>development:<br />&nbsp;&nbsp; adapter: sqlite3<br />&nbsp;&nbsp; database: db/test.db</p>
<p>&nbsp;&nbsp; #username: root<br />&nbsp;&nbsp; #password: <br />&nbsp;&nbsp; #host: localhost</p>
<p>后面如何操作，就和使用mysql数据库一样了。</p>
<p>建立数据表可以用db:migrate来完成</p>
<p>&nbsp;</p>
          <br/>
          <span style="color:red;">
            <a href="http://tianshi0253.javaeye.com/blog/229012#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Sun, 17 Aug 2008 19:41:11 +0800</pubDate>
        <link>http://tianshi0253.javaeye.com/blog/229012</link>
        <guid>http://tianshi0253.javaeye.com/blog/229012</guid>
      </item>
      <item>
        <title>第三章作业三</title>
        <author>tianshi0253</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://tianshi0253.javaeye.com">tianshi0253</a>&nbsp;
          链接：<a href="http://tianshi0253.javaeye.com/blog/228952" style="color:red;">http://tianshi0253.javaeye.com/blog/228952</a>&nbsp;
          发表时间: 2008年08月17日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <pre name="code" class="ruby">module Get_color
  def get_color(color)
    return color
  end
end

module Get_wheels
  def get_number_of_wheels(wheel)
    return 4 * wheel
  end
end

class Car
  @@wheel=0
  include Get_color
  include Get_wheels

end

car = Car.new()
puts car.get_color("red")
puts car.get_number_of_wheels(1)




</pre>
<p>&nbsp;</p>
          <br/>
          <span style="color:red;">
            <a href="http://tianshi0253.javaeye.com/blog/228952#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Sun, 17 Aug 2008 15:04:49 +0800</pubDate>
        <link>http://tianshi0253.javaeye.com/blog/228952</link>
        <guid>http://tianshi0253.javaeye.com/blog/228952</guid>
      </item>
      <item>
        <title>第三章作业二</title>
        <author>tianshi0253</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://tianshi0253.javaeye.com">tianshi0253</a>&nbsp;
          链接：<a href="http://tianshi0253.javaeye.com/blog/228946" style="color:red;">http://tianshi0253.javaeye.com/blog/228946</a>&nbsp;
          发表时间: 2008年08月17日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <pre name="code" class="ruby">class Vehicle
  def initialize(color)
    @color = color
  end

  def get_color
    return @color
  end
end

#ver = Vehicle.new("Red")
#puts ver.get_color
class Car &lt; Vehicle
  def initialize(color)
    super(color)
  end
  def get_color
    return "Blue"
  end
end

car = Car.new("Red")
puts car.get_color</pre>
<p>&nbsp;</p>
          <br/>
          <span style="color:red;">
            <a href="http://tianshi0253.javaeye.com/blog/228946#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Sun, 17 Aug 2008 14:50:34 +0800</pubDate>
        <link>http://tianshi0253.javaeye.com/blog/228946</link>
        <guid>http://tianshi0253.javaeye.com/blog/228946</guid>
      </item>
      <item>
        <title>第三章作业一</title>
        <author>tianshi0253</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href