<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>besfan (范某某)</title>
    <link>https://ruby-china.org/besfan</link>
    <description></description>
    <language>en-us</language>
    <item>
      <title>[杭州] 大搜车招聘 Ruby 工程师 1 名</title>
      <description>&lt;h2 id="职位要求"&gt;职位要求&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;1 年以上 Rails 开发经验，有相关工作经验者优先&lt;/li&gt;
&lt;li&gt;熟悉数据库，以 MySQL 为主，部分业务采用 PG；&lt;/li&gt;
&lt;li&gt;对技术有热情&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="加分项"&gt;加分项&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;熟练掌握自动化测试&lt;/li&gt;
&lt;li&gt;有开发高并发，高可用系统的经验 &lt;/li&gt;
&lt;li&gt;Github 独立维护项目者&lt;/li&gt;
&lt;li&gt;活跃的博客&lt;/li&gt;
&lt;li&gt;关注新技术的动向，例如 react.js&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="待遇&amp;amp;环境"&gt;待遇&amp;amp;环境&lt;/h2&gt;
&lt;p&gt;以下内容仅供参考，应该差别不大。&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;12 - 20 K&lt;/li&gt;
&lt;li&gt;期权：D 轮巨额融资已经到位，并且发过一轮期权了。期权不是画大饼，也不是镜花水月。&lt;/li&gt;
&lt;li&gt;工作电脑 MacBook Pro 新款，戴尔 24' 显示器 ( U2412M ) + 人体工程座椅&lt;/li&gt;
&lt;li&gt;上下班不打卡，可适当弹性，一般九点半左右到公司。&lt;/li&gt;
&lt;li&gt;健身房，游戏房，室内运动场等&lt;/li&gt;
&lt;li&gt;国家规定的五险一金、双休、节假日等。&lt;/li&gt;
&lt;li&gt;节假日应景礼品&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="工作内容以及这边情况"&gt;工作内容以及这边情况&lt;/h2&gt;
&lt;p&gt;Ruby 团队的大部门属于创新研发部，主要负责：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;业务：车牛拍卖，地推绩效，B2B 业务等&lt;/li&gt;
&lt;li&gt;微服务：主要是订单系统，包括支付，结算和优惠券&lt;/li&gt;
&lt;li&gt;内部系统：API 健康监测工具，测试用例 &amp;amp;&amp;amp; 测试任务，接口的全链路自动化测试。&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;目前需要两个方向的同学。&lt;/p&gt;
&lt;h5 id="运维工具开发"&gt;运维工具开发&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;负责公司运维工具，测试工具的开发&lt;/li&gt;
&lt;li&gt;与架构团队一起，推动团队的工程化与自动化&lt;/li&gt;
&lt;li&gt;工作内容 80% 以上可开源&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="业务开发"&gt;业务开发&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;维护和开发后台页面。使用传统的 Rails 架构，特别之处在于 View 层使用用 Ant Design( &lt;a href="http://ant.design" rel="nofollow" target="_blank"&gt;http://ant.design&lt;/a&gt; )&lt;/li&gt;
&lt;li&gt;给客户端提供 JSON 接口，主要是基于 Grape, 部分在试用 Rails 5.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="我们是谁"&gt;我们是谁&lt;/h2&gt;
&lt;p&gt;我们是大搜车，坐落杭州城西。旗下包括&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;大风车：为 4S 店集团提供官网，ERP.金融，销售 APP, 评估师 APP 等整套解决方案。&lt;/li&gt;
&lt;li&gt;车牛：针对个人车商以及 4S 店提供批发，拍卖，金融等服务。&lt;/li&gt;
&lt;li&gt;金融：为车商，消费者提供质保，消费贷，金融贷等支持&lt;/li&gt;
&lt;li&gt;大搜车：官网，面向 C 端用户，以及内部公共服务 (车型库，数据平台等)&lt;/li&gt;
&lt;li&gt;面向 C 端用户的汽车消费金融方案 &lt;a href="http://www.tangeche.com/" rel="nofollow" target="_blank" title=""&gt;弹个车&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="发展历程"&gt;发展历程&lt;/h4&gt;
&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2016/c3627cbe438878937dd2bcef0addfb7e.png!large" title="" alt=""&gt;&lt;/p&gt;
&lt;h4 id="加入大搜车"&gt;加入大搜车&lt;/h4&gt;
&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2016/78d01394f2696306f3242b4ae4d0a5c1.jpg!large" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;最后放几张我厂的图。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2016/30c462c4d8651c10771d4c92e4259a2f.jpg!large" title="" alt=""&gt;
&lt;img src="https://l.ruby-china.com/photo/2016/5902ed4e84c86fd1acb979e9fd154b0e.jpg!large" title="" alt=""&gt;
&lt;img src="https://l.ruby-china.com/photo/2016/87bb6c0f2081aca00f02c06469378c3d.jpg!large" title="" alt=""&gt;
&lt;img src="https://l.ruby-china.com/photo/2016/b4b16e1e11ccbfad65c6aac6c25739f5.jpg!large" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;茶水间&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2016/63d13808c7e5d55a3c3fcc6340a7c21f.jpg!large" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;活动室 &amp;amp;&amp;amp; 瑜伽室 每周一次，各种妹子 ( 和汉子，(⊙﹏⊙) )&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2016/57896eb5196bc3f3ef8793c4e41ea4ec.jpg!large" title="" alt=""&gt;
&lt;img src="https://l.ruby-china.com/photo/2016/693042fa9f884b87f23308b6bb2ded82.jpg!large" title="" alt=""&gt;
&lt;img src="https://l.ruby-china.com/photo/2016/d8f95ddfc87341a6a269ff1e562b2c31.jpg!large" title="" alt=""&gt;&lt;/p&gt;
&lt;h2 id="联系方式"&gt;联系方式&lt;/h2&gt;
&lt;p&gt;邮件：fanxiaopeng # souche.com&lt;br&gt;
地址：杭州余杭区五常大道 175 号  &lt;/p&gt;</description>
      <author>besfan</author>
      <pubDate>Mon, 28 Nov 2016 13:54:33 +0800</pubDate>
      <link>https://ruby-china.org/topics/31716</link>
      <guid>https://ruby-china.org/topics/31716</guid>
    </item>
    <item>
      <title>[杭州][D 轮] 大搜车招聘 Ruby 工程师 1 名</title>
      <description>&lt;h2 id="职位要求"&gt;职位要求&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;1 年以上 Rails 开发经验，有相关工作经验者优先&lt;/li&gt;
&lt;li&gt;熟悉数据库，以 MySQL 为主，部分业务采用 PG；&lt;/li&gt;
&lt;li&gt;对技术有热情&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="加分项"&gt;加分项&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;熟练掌握自动化测试&lt;/li&gt;
&lt;li&gt;有开发高并发，高可用系统的经验 &lt;/li&gt;
&lt;li&gt;Github 独立维护项目者&lt;/li&gt;
&lt;li&gt;活跃的博客&lt;/li&gt;
&lt;li&gt;关注新技术的动向，例如 react.js&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="待遇&amp;amp;环境"&gt;待遇&amp;amp;环境&lt;/h2&gt;
&lt;p&gt;以下内容仅供参考，应该差别不大。&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;12 - 20 K&lt;/li&gt;
&lt;li&gt;期权：D 轮巨额融资已经到位，并且发过一轮期权了。期权不是画大饼，也不是镜花水月。&lt;/li&gt;
&lt;li&gt;工作电脑 MacBook Pro 新款，戴尔 24' 显示器 ( U2412M ) + 人体工程座椅&lt;/li&gt;
&lt;li&gt;上下班不打卡，可适当弹性，一般九点半左右到公司。&lt;/li&gt;
&lt;li&gt;健身房，游戏房，室内运动场等&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="工作内容以及这边情况"&gt;工作内容以及这边情况&lt;/h2&gt;
&lt;p&gt;Ruby 团队的大部门属于创新研发部，主要负责：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;业务：车牛拍卖，地推绩效，B2B 业务等&lt;/li&gt;
&lt;li&gt;微服务：主要是订单系统，包括支付，结算和优惠券&lt;/li&gt;
&lt;li&gt;内部系统：API 健康监测工具，测试用例 &amp;amp;&amp;amp; 测试任务，接口的全链路自动化测试。&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;目前需要两个方向的同学。&lt;/p&gt;
&lt;h5 id="运维工具开发"&gt;运维工具开发&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;负责公司运维工具，测试工具的开发&lt;/li&gt;
&lt;li&gt;与架构团队一起，推动团队的工程化与自动化&lt;/li&gt;
&lt;li&gt;工作内容 80% 以上可开源&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="业务开发"&gt;业务开发&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;维护和开发后台页面。使用传统的 Rails 架构，特别之处在于 View 层使用用 Ant Design( &lt;a href="http://ant.design" rel="nofollow" target="_blank"&gt;http://ant.design&lt;/a&gt; )&lt;/li&gt;
&lt;li&gt;给客户端提供 JSON 接口，主要是基于 Grape, 部分在试用 Rails 5.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="我们是谁"&gt;我们是谁&lt;/h2&gt;
&lt;p&gt;我们是大搜车，坐落杭州城西。旗下包括&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;大风车：为 4S 店集团提供官网，ERP.金融，销售 APP, 评估师 APP 等整套解决方案。&lt;/li&gt;
&lt;li&gt;车牛：针对个人车商以及 4S 店提供批发，拍卖，金融等服务。&lt;/li&gt;
&lt;li&gt;金融：为车商，消费者提供质保，消费贷，金融贷等支持&lt;/li&gt;
&lt;li&gt;大搜车：官网，面向 C 端用户，以及内部公共服务 (车型库，数据平台等)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="联系方式"&gt;联系方式&lt;/h2&gt;
&lt;p&gt;邮件：fanxiaopeng # souche.com&lt;br&gt;
地址：杭州余杭区五常大道 175 号  &lt;/p&gt;

&lt;p&gt;最后放几张我厂的图。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2016/30c462c4d8651c10771d4c92e4259a2f.jpg!large" title="" alt=""&gt;
&lt;img src="https://l.ruby-china.com/photo/2016/5902ed4e84c86fd1acb979e9fd154b0e.jpg!large" title="" alt=""&gt;
&lt;img src="https://l.ruby-china.com/photo/2016/87bb6c0f2081aca00f02c06469378c3d.jpg!large" title="" alt=""&gt;
&lt;img src="https://l.ruby-china.com/photo/2016/b4b16e1e11ccbfad65c6aac6c25739f5.jpg!large" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;茶水间&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2016/63d13808c7e5d55a3c3fcc6340a7c21f.jpg!large" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;活动室 &amp;amp;&amp;amp; 瑜伽室 每周一次，各种妹子 ( 和汉子，(⊙﹏⊙) )&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2016/57896eb5196bc3f3ef8793c4e41ea4ec.jpg!large" title="" alt=""&gt;
&lt;img src="https://l.ruby-china.com/photo/2016/693042fa9f884b87f23308b6bb2ded82.jpg!large" title="" alt=""&gt;
&lt;img src="https://l.ruby-china.com/photo/2016/d8f95ddfc87341a6a269ff1e562b2c31.jpg!large" title="" alt=""&gt;&lt;/p&gt;</description>
      <author>besfan</author>
      <pubDate>Thu, 13 Oct 2016 09:39:25 +0800</pubDate>
      <link>https://ruby-china.org/topics/31305</link>
      <guid>https://ruby-china.org/topics/31305</guid>
    </item>
    <item>
      <title>分享一次排查问题的过程</title>
      <description>&lt;h3 id="问题描述"&gt;问题描述&lt;/h3&gt;
&lt;p&gt;发现于一个专门提供 API 的服务：优惠券服务，请求量比较低，吞吐量大概几十 cpm，通过监控查看到会有极少量请求比较慢，响应时间在两三秒的样子，出现频率也不固定，间隔几分钟到几十分钟不等。这个 API 是返回用户所拥有优惠券的数量，就是一个简单的 SQL count。监控上看到该 API 的一般响应时间大约几十毫秒，只是个别请求的响应时间比较长。&lt;/p&gt;
&lt;h3 id="服务器概况"&gt;服务器概况&lt;/h3&gt;
&lt;p&gt;Nginx, Puma, Rails 4.2, Grape, PostgreSQL, Sidekiq, Redis&lt;/p&gt;

&lt;p&gt;服务器、PostgreSQL 和 redis 都用阿里云的服务。&lt;/p&gt;
&lt;h3 id="定位问题的过程"&gt;定位问题的过程&lt;/h3&gt;&lt;h5 id="1. 看监控"&gt;1. 看监控&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;问题代码定位&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;我们使用的是 OneAPM 作为监控的 (OneAPM 是不是应该给点广告费，哈哈哈)。
&lt;img src="https://l.ruby-china.com/photo/2016/81f52e101b03b1c9d85eb3a612aaf629.png" title="" alt=""&gt;
第一张图片可以看出数据库查询的时间是可以接受的，时间都耗在了 Rack 上。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2016/5410f66d36fede256dc4ac9f0fcd0096.png" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;详情中也没有显示具体的慢的位置，没有说明是哪个 Rack，范围太大，没什么实际帮助。&lt;/p&gt;

&lt;p&gt;当时有过怀疑，是不是 OneAPM 的监控不准呢？在 Nginx 日志中是可以显示出响应的处理时间，这个时间相对 OneAPM 来说要更准确。&lt;/p&gt;

&lt;p&gt;经过确认，Nginx 日志中响应时间在 1-3 秒的请求每天都会有几十个。(在 Nginx 的配置中为 log_format 增加$upstream_response_time 或者$request_time，默认是没有这 2 个值的。)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;服务器负载分析&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;查看 OneAPM 以及阿里云上的资源监控，没有发现任何异常。请求响应迟钝的那段时间前后，也没有耗时较长或者有可能造成堵塞的其他异常请求。&lt;/p&gt;
&lt;h5 id="2. 分析代码"&gt;2. 分析代码&lt;/h5&gt;
&lt;p&gt;接口的实现中只有 3 行代码，逻辑很简单，生成 ActiveRecord::Relation，单表 count 查询，grape 中也没有去渲染其他数据，仅仅返回一个数量。&lt;/p&gt;

&lt;p&gt;简单来说就执行了这 2 行，数据库索引也加了，即使不加索引也是没问题的，因为数据一开始是很少的。&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;coupons&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Coupon&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;user_id: &lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:user_id&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; 
&lt;span class="n"&gt;coupons&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;count&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Puma 的问题？Grape 的问题？Rails？数据库？锁？…………&lt;/p&gt;
&lt;h5 id="3. 是否慢在业务代码的范围内？"&gt;3. 是否慢在业务代码的范围内？&lt;/h5&gt;
&lt;p&gt;用了最笨的办法，在每一行前后打上日志，缩小范围。&lt;/p&gt;

&lt;p&gt;结果：Rails 默认的请求日志和手动添加的第一条日志，这 2 个日志的间隔时间比较长。
可以确认的是，已经执行到了 Rails 的代码中，和 Puma 的关系不大了。同样，也不是业务代码的原因。&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;I, [2016-01-29T15:51:50.013946 #17676]  INFO -- : Started GET "problem/api" for 100.97.90.88 at 2016-01-29 15:51:50 +0800
---------------这里耗时较长-----这一行是我手动写上去的--------------
I, [2016-01-29T15:51:51.129605 #17676]  INFO -- : params: #&amp;lt;Hashie::Mash user_id="123456"&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h5 id="4. 是否慢在了某个Middleware内？"&gt;4. 是否慢在了某个 Middleware 内？&lt;/h5&gt;
&lt;p&gt;已经打印了请求日志，但是还没有进入到接口代码中，是否因为某个 middleware 处理慢了导致的？只是猜测，来验证一下。middleware 的相关介绍查看&lt;a href="http://blog.gauravchande.com/what-is-rack-in-ruby-rails" rel="nofollow" target="_blank" title=""&gt;这里&lt;/a&gt;。在 config/application.rb 添加下面的代码：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;after_initialize&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="no"&gt;Rails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;configuration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;middlewares&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;middleware&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="n"&gt;middleware_klass&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;klass&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;middleware_klass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;class&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="no"&gt;Class&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;middleware_klass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;method_defined?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:call&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;middleware_klass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;class_eval&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="k"&gt;alias&lt;/span&gt; &lt;span class="ss"&gt;:old_call&lt;/span&gt; &lt;span class="ss"&gt;:call&lt;/span&gt;

        &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;call&lt;/span&gt; &lt;span class="n"&gt;env&lt;/span&gt;
          &lt;span class="no"&gt;Rails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt; &lt;span class="s2"&gt;"-------&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
          &lt;span class="n"&gt;old_call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;end&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在每一个 middleware 的 call 之前打印一行日志。日志是这样的：&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;I, [2016-01-29T15:51:50.013946 #17676]  INFO -- : Started GET "problem/api" for 100.97.90.88 at 2016-01-29 15:51:50 +0800
I, [2016-01-29T15:51:50.014022 #17676]  INFO -- : middleware call time at: 15:51:50.014001 -------ActionDispatch::ShowExceptions
I, [2016-01-29T15:51:50.014091 #17676]  INFO -- : middleware call time at: 15:51:50.014072 -------ActionDispatch::DebugExceptions
I, [2016-01-29T15:51:50.014139 #17676]  INFO -- : middleware call time at: 15:51:50.014122 -------ActionDispatch::RemoteIp
I, [2016-01-29T15:51:50.014192 #17676]  INFO -- : middleware call time at: 15:51:50.014174 -------ActionDispatch::Callbacks
I, [2016-01-29T15:51:50.014261 #17676]  INFO -- : middleware call time at: 15:51:50.014242 -------ActiveRecord::ConnectionAdapters::ConnectionManagement
I, [2016-01-29T15:51:50.014324 #17676]  INFO -- : middleware call time at: 15:51:50.014305 -------ActiveRecord::QueryCache
---------------这里耗时较长-----这一行是我手动写上去的--------------
I, [2016-01-29T15:51:51.127367 #17676]  INFO -- : middleware call time at: 15:51:51.127277 -------ActionDispatch::Cookies
I, [2016-01-29T15:51:51.127480 #17676]  INFO -- : middleware call time at: 15:51:51.127459 -------ActionDispatch::Session::CookieStore
I, [2016-01-29T15:51:51.127573 #17676]  INFO -- : middleware call time at: 15:51:51.127547 -------ActionDispatch::Flash
I, [2016-01-29T15:51:51.127624 #17676]  INFO -- : middleware call time at: 15:51:51.127606 -------ActionDispatch::ParamsParser
I, [2016-01-29T15:51:51.127688 #17676]  INFO -- : middleware call time at: 15:51:51.127669 -------Rack::Head
I, [2016-01-29T15:51:51.127740 #17676]  INFO -- : middleware call time at: 15:51:51.127719 -------Rack::ConditionalGet
I, [2016-01-29T15:51:51.127797 #17676]  INFO -- : middleware call time at: 15:51:51.127778 -------Rack::ETag
I, [2016-01-29T15:51:51.127865 #17676]  INFO -- : middleware call time at: 15:51:51.127827 -------OneApm::Rack::BrowserMonitoring
I, [2016-01-29T15:51:51.127994 #17676]  INFO -- : middleware call time at: 15:51:51.127975 -------OneApm::Rack::MiddlewareHooks
I, [2016-01-29T15:51:51.128953 #17676]  INFO -- : middleware call time at: 15:51:51.128891 -------Rack::Head
I, [2016-01-29T15:51:51.129605 #17676]  INFO -- : params: #&amp;lt;Hashie::Mash user_id="123456"&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样就可以计算出是每个 middleware 的处理时间。可以看出是 ActiveRecord::QueryCache 和 ActionDispatch::Cookies 之间的间隔时间有 1 秒多，而我是在每个 middleware 的开始打印的日志，因此可以确认问题是出在了 ActiveRecord::QueryCache 中。
ActiveRecord::QueryCache 的作用是启用 Active Record 查询缓存，把每次查询的结果缓存起来，如果在同一次请求中遇到相同的查询，直接从缓存中读取结果，不用再次查询数据库。
因为服务器的负载很低，移除这个 middleware 的副作用比较小。&lt;/p&gt;
&lt;h5 id="5. 移除 ActiveRecord::QueryCache"&gt;5. 移除 ActiveRecord::QueryCache&lt;/h5&gt;
&lt;p&gt;加入下面的代码：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# config/application.rb&lt;/span&gt;
&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;delete&lt;/span&gt; &lt;span class="s2"&gt;"ActiveRecord::QueryCache"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;接着去观察日志，然并卵，依然会有慢请求存在，数量也没有明显减少。好在相比之前有了变化，问题定位到了接口的代码中，慢在得到 ActiveRecord::Relation，但还没执行 count 的时候。&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;coupons&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Coupon&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;user_id: &lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:user_id&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;看一下 ActiveRecord::QueryCache 的实现&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;ActiveRecord&lt;/span&gt;
  &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;QueryCache&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;connection&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connection&lt;/span&gt;
      &lt;span class="n"&gt;enabled&lt;/span&gt;       &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query_cache_enabled&lt;/span&gt;
      &lt;span class="n"&gt;connection_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connection_id&lt;/span&gt;
      &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enable_query_cache!&lt;/span&gt;

      &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vi"&gt;@app.call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Rack&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;BodyProxy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="n"&gt;restore_query_cache_settings&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;connection_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;enabled&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;

      &lt;span class="n"&gt;response&lt;/span&gt;
    &lt;span class="k"&gt;rescue&lt;/span&gt; &lt;span class="no"&gt;Exception&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;
      &lt;span class="n"&gt;restore_query_cache_settings&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;connection_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;enabled&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;ActiveRecord::QueryCache 和生成一个 ActiveRecord::Relation 共同点是什么？应该是获取数据库连接。&lt;/p&gt;
&lt;h5 id="6. 确认ActiveRecord::ConnectionAdapters::ConnectionPool#checkout的执行时间。"&gt;6. 确认ActiveRecord::ConnectionAdapters::ConnectionPool#checkout的执行时间。&lt;/h5&gt;
&lt;blockquote&gt;
&lt;p&gt;Check-out a database connection from the pool, indicating that you want to use it. You should call checkin when you no longer need this.&lt;/p&gt;

&lt;p&gt;This is done by either returning and leasing existing connection, or by creating a new connection and leasing it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;在 config/application.rb 添加下面的代码：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;after_initialize&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;CheckoutLog&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;checkout&lt;/span&gt;
      &lt;span class="no"&gt;Rails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt; &lt;span class="s1"&gt;'-------checkout start'&lt;/span&gt;
      &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;tap&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
        &lt;span class="no"&gt;Rails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt; &lt;span class="s1"&gt;'-------checkout end'&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;ConnectionAdapters&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;ConnectionPool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;prepend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;CheckoutLog&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在 checkout 执行前后打印日志，对于 prepend 的用法，参见&lt;a href="https://ruby-china.org/topics/28712" title=""&gt;理解 Ruby 中的 include 和 prepend&lt;/a&gt;
&lt;strong&gt;结果确实慢在了 checkout 中&lt;/strong&gt;。
通过类似的方法，一步一步追踪过去，最终定位到了 &lt;code&gt;@connection.query 'SELECT 1'&lt;/code&gt;，通过执行一个最简单的 SQL 来确认数据库连接是否活跃。 
下面是涉及到的方法，分布在多个类中。&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;checkout&lt;/span&gt;
  &lt;span class="n"&gt;synchronize&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;conn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;acquire_connection&lt;/span&gt;
    &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lease&lt;/span&gt;
    &lt;span class="n"&gt;checkout_and_verify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;checkout_and_verify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_run_checkout_callbacks&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;verify!&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="n"&gt;c&lt;/span&gt;
&lt;span class="k"&gt;rescue&lt;/span&gt;
  &lt;span class="n"&gt;remove&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;
  &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;disconnect!&lt;/span&gt;
  &lt;span class="k"&gt;raise&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;verify!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ignored&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;reconnect!&lt;/span&gt; &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="n"&gt;active?&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="c1"&gt;# Is this connection alive and ready for queries?&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;active?&lt;/span&gt;
  &lt;span class="vi"&gt;@connection.query&lt;/span&gt; &lt;span class="s1"&gt;'SELECT 1'&lt;/span&gt;
  &lt;span class="kp"&gt;true&lt;/span&gt;
&lt;span class="k"&gt;rescue&lt;/span&gt; &lt;span class="no"&gt;PGError&lt;/span&gt;
  &lt;span class="kp"&gt;false&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h5 id="7. 脱离Rails框架，确认是否是数据库的原因"&gt;7. 脱离 Rails 框架，确认是否是数据库的原因&lt;/h5&gt;
&lt;p&gt;直接用 pg 的 gem 单独执行&lt;code&gt;select 1&lt;/code&gt;&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'pg'&lt;/span&gt;
&lt;span class="n"&gt;conn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;PG&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="ss"&gt;dbname: &lt;/span&gt;&lt;span class="s1"&gt;'your_db_name'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                   &lt;span class="ss"&gt;host: &lt;/span&gt;&lt;span class="s1"&gt;'your_db_host'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                   &lt;span class="ss"&gt;port: &lt;/span&gt;&lt;span class="mi"&gt;5432&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                   &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="ss"&gt;:'user_name'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                   &lt;span class="ss"&gt;password: &lt;/span&gt;&lt;span class="s1"&gt;'your_password'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="mi"&gt;1000000&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;times&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each_with_index&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="n"&gt;start_t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;
  &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'select 1'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;end_t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;
  &lt;span class="n"&gt;tt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;end_t&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;start_t&lt;/span&gt;
  &lt;span class="nb"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:  &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;tt&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;tt&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="mf"&gt;0.05&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;经过多次验证，100 万次执行，会有几十次超过 50 毫秒，多次超过 1 秒。
结论已经很明显了，阿里云的 PostgreSQL 服务有问题。&lt;/p&gt;
&lt;h5 id="8. 给阿里云提工单"&gt;8. 给阿里云提工单&lt;/h5&gt;
&lt;p&gt;经过漫长的问题排查及定位，给出的回复是：数据库中间件的任务调度模块有些不高效的地方，导致工作负荷高的时候产生较大延迟，正在解决中。&lt;/p&gt;
&lt;h3 id="总结"&gt;总结&lt;/h3&gt;
&lt;p&gt;出现问题不可怕，可怕的是不知道问题在哪里。
定位问题的基本思路就是不断 &lt;strong&gt;缩小排查范围&lt;/strong&gt;。
每天都会出现几十次响应很慢的请求，对整个系统来说影响也不算很大，在生产服务器上打日志是一种笨办法，只能晚上发布，第二天观察结果，然后接着打日志，晚上发布……整个过程历时比较长。&lt;/p&gt;
&lt;h3 id=":pray: 招人 :pray:"&gt;
&lt;img title=":pray:" alt="🙏" src="https://twemoji.ruby-china.com/2/svg/1f64f.svg" class="twemoji"&gt; 招人 &lt;img title=":pray:" alt="🙏" src="https://twemoji.ruby-china.com/2/svg/1f64f.svg" class="twemoji"&gt;
&lt;/h3&gt;
&lt;p&gt;[杭州] 大搜车诚招一名 ruby 工程师
详情见&lt;a href="https://ruby-china.org/topics/27440" title=""&gt;之前的招聘贴&lt;/a&gt;
&lt;a href="http://f2e.souche.com/blog/hang-zhou-da-sou-che-ban-xin-jia-la/?from=timeline&amp;amp;isappinstalled=0" rel="nofollow" target="_blank" title=""&gt;这是新的办公环境&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;有意向的小伙伴可以联系我
微信：besfan
邮件：fanxiaopeng@souche.com
地址：杭州天目山路西溪印象城附近&lt;/p&gt;</description>
      <author>besfan</author>
      <pubDate>Fri, 25 Mar 2016 16:56:02 +0800</pubDate>
      <link>https://ruby-china.org/topics/29463</link>
      <guid>https://ruby-china.org/topics/29463</guid>
    </item>
    <item>
      <title>Ruby 服务器对比</title>
      <description>&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;之前一直对 Ruby 的服务器不是很了解，在 stackoverflow 看到一篇文章感觉不错，顺便翻译了一下，英语不好，如果哪里错了请大家指出，避免误导他人。
原文地址：&lt;a href="http://stackoverflow.com/questions/4113299/ruby-on-rails-server-options" rel="nofollow" target="_blank"&gt;http://stackoverflow.com/questions/4113299/ruby-on-rails-server-options&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;The word "deployment" can have two meanings depending on the context. You are also confusing the roles of Apache/Nginx with the roles of other components.&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Historic note: This article was originally written on November 6, 2010, when the Ruby app server ecosystem was limited. I've updated this article on March 15 2013 with all the latest updates in the ecosystem.&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Disclaimer: I am one of the authors of Phusion Passenger, one of the app servers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;一，Apache vs Nginx&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;他们都是 web 服务器，都能伺服静态文件，利用恰当的模块也能伺服动态的 web 应用。Apache 更加流行，拥有更多的功能；Nginx 则相对小巧、快速、功能少。&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;让 Apache 和 Nginx 来伺服 Ruby 服务器都不是开箱即用（out-of-the-box）的，为此你需要使用另外的插件来组合他们。&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Apache 和 Nginx 都能作为反向代理，就是说他们能够把进来的 HTTP 请求发给其他服务器，接着把该服务器的 HTTP 响应转给客户端，后面会看到为什么和这个有关系。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;二，Mongrel 以及其他 production 环境的服务器 vs WEBrick&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Mongrel 是 Ruby 实现的应用服务器，具体来说：&lt;/p&gt;

&lt;p&gt;1，在自己的进程空间中加载 Ruby 应用。&lt;/p&gt;

&lt;p&gt;2，创建一个 TCP socket，允许它可以和外部世界通信 (例如 Internet)。Mongrel 在这个 socket 上监听 HTTP 请求，并把请求数据转发给 Ruby&amp;nbsp;应用。&lt;/p&gt;

&lt;p&gt;3，Ruby 应用返回一个描述 HTTP 响应的对象，Mongrel 将其转换为真正的 HTTP 响应字节，并发回到 socket 中。&lt;/p&gt;

&lt;p&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;然而&amp;nbsp;Mongrel 已经不再维护了，其他替代的服务器是：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Phusion Passenger&lt;/li&gt;
&lt;li&gt;Unicorn&lt;/li&gt;
&lt;li&gt;Thin&lt;/li&gt;
&lt;li&gt;Puma&lt;/li&gt;
&lt;li&gt;Trinidad (JRuby only)&lt;/li&gt;
&lt;li&gt;TorqueBox (JRuby only)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;接下来我会讲一讲他们和 Mongrel 的区别&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;WEBrick 和 Mongrel 很像，区别如下：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;WEBrick&amp;nbsp;不适合用于 production。WEBrick 完全是用&amp;nbsp;Ruby&amp;nbsp;写的；Mongrel（以及其他&amp;nbsp;Ruby&amp;nbsp;应用服务器）是部分 Ruby 部分 C，主要是&amp;nbsp;Ruby，但它的 HTTP 解析器为了性能是用 C 写的。&lt;/li&gt;
&lt;li&gt;WEBrick 速度比较慢而且不够强壮，有普遍知道的内存泄漏问题，以及 HTTP 解析问题。&lt;/li&gt;
&lt;li&gt;因为 WEBrick 是 Ruby 默认自带的，所以 WEBrick 经常用于 development 环境下作为默认服务器，而其他的服务器则需要另外安装。不建议在 production 环境下使用 WEBrick 服务器，虽然因为某些原因，Heroku 选择了 WEBrick 作为默认服务器，他们以前使用的是 Thin，但我不知道他们为什么换到了 WEBrick。&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;三，应用服务器世界&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;当前所有的 Ruby 应用服务器都是 HTTP 类型的，一些服务器直接将 80 端口暴露到&amp;nbsp;Internet 中，另一些则没有。&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;暴露 80 端口的：Phusion Passenger，Rainbows。&lt;/li&gt;
&lt;li&gt;没有直接暴露的：Mongrel, Unicorn, Thin, Puma。这些服务器必须必须置于反向代理服务器之后，比如 Apache 和 Nginx。&lt;/li&gt;
&lt;li&gt;我不了解 Trinidad 和 TorqueBox，所以就忽略了。&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;为什么有些服务器需要置于反向代理之后？&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;某些服务器的每个进程在同一时间只能处理一个请求，如果想同时处理两个请求，你就需要启动多个服务器实例，都伺服同一个 Ruby 应用。这种应用服务器进程的集合称为应用服务器集群（比如 Mongrel Cluster, Thin Cluster）。然后你必须启动 Apache 或者 Nginx，给集群做反向代理，Apache/Nginx 会处理好集群中不同应用实例间的请求分发。(更多内容参见章节 "I/O 并发模型”)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Web 服务器可以缓存请求和响应。有些客户端发送数据、接收数据的速度缓慢，你当然不希望应用服务器在等待客户端收发数据时什么也不干，Web 服务器可以隔离应用服务器和慢客户端。Apache 和 Nginx 擅长同时很多事情，因为他们是多线程或者基于事件的。&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;大多数的应用服务器可以伺服静态文件，但不擅长，而 Apache 和 Nginx 可以更快速度处理这件事情。&amp;nbsp;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;人们经常直接使用 Apache 或者 Nginx 伺服静态文件，而不会处理需要转发的请求（forward requests），这是比较安全的策略。Apache 和 Nginx 足够聪明，可以保护应用服务器远离恶意请求。&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;为什么有些服务器可以直接暴露在 Internet 中？&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Phusion Passenger 和其他应用服务器不一样，其中一个特点是可以融入其他服务器。&lt;/li&gt;
&lt;li&gt;Rainbows 的作者公开指出，Rainbows 可以直接暴露在 Internet 中。他非常确认在解析 HTTP 过程中不会轻易遭受攻击。当然，作者也并不做任何担保，并表示不同应用环境下有其相应的风险。&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;四，应用服务器对比&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;在这一章中，我会比较我提过的大多数服务器，但不包括&amp;nbsp;Phusion Passenger。Phusion Passenger 和其他的不一样，我会单独开出一章。我还会忽略&amp;nbsp;Trinidad 和 TorqueBox，因为我对他们不是很了解，只有你用到 JRuby 的时候才会涉及到他们。&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Mongrel&amp;nbsp;&lt;/strong&gt; 只有最基础的功能。像之前提到的，Mongrel 仅仅是单线程、多进程，所以它只用于集群（cluster）中。没有进程监控，意味着如果集群中一个进程崩溃了，则需要手动重启。人们需要使用额外的进程来照看&amp;nbsp;Mongrel，比如&amp;nbsp;Monit 和 God。&amp;nbsp;&amp;nbsp;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Unicorn&amp;nbsp;&lt;/strong&gt; 是从&amp;nbsp;Mongrel 中 fork 出来的。支持监控一定数量的的进程：如果一个进程崩溃了，则会被主进程自动重启。它能让所有进程都监听同一个共享的 socket，而不是每个进程使用单独的 socket，这会简化反向代理的配置。像 Mongrel 一样，Unicorn 是单线程、多进程。&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Thin&amp;nbsp;&lt;/strong&gt; 利用&amp;nbsp;EventMachine 库，实现基于事件的&amp;nbsp;I/O 模型。它并不是使用&amp;nbsp;Mongrel 的 HTTP 解析器，没有基于&amp;nbsp;Mongrel。它的集群节点没有进程监控，所以你需要去监控进程是否崩溃。每个进程监听各自的 socket，不像&amp;nbsp;Unicorn 一样共享 socket。理论上来说，Thin 的 I/O 模型允许高并发，这也是 Thin 被应用的大部分场合。一个 Thin 的进程只能处理一个并发请求，所以你还需要集群。关于这个古怪的性质，更多内容参见“I/O 并发模型”。&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Puma&amp;nbsp;&lt;/strong&gt; 也是从 Mongrel 中 fork 出来的，但和 Unicorn 不一样的是，Puma 是基于多线程，使用 Thread Pool 实现。因为 GIL 的存在，所以 MRI 不能利用多核实现 CPU 并行，所以你需要特别确认的是你能利用多核。更多内容参见“I/O 并发模型”。&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Rainbows&amp;nbsp;&lt;/strong&gt; 通过给不同的库实现多种并发模型 &lt;strong&gt;。&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;五，Phusion Passenger&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Phusion Passenger 和其他的不一样。他直接融入 Apache 或者 Nginx，类似于 Apache 的&amp;nbsp;mod_php。就像&amp;nbsp;mod_php 使 Apache 伺服 PHP 应用一样，Phusion Passenger 也可以使 Apache 或者 Nginx 伺服 Ruby 应用。Phusion Passenger 的目标是所有的事情做起来尽可能地减少麻烦。&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;如果使用&amp;nbsp;Phusion Passenger 的话，你不需要为你的应用启动一个进程或者集群，为&amp;nbsp;Apache/Nginx 配置静态目录，或者设置反向代理。&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;你只需要：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;编辑 web 服务器的配置文件，写入&amp;nbsp;Ruby 应用下 public 文件夹的路径&lt;/li&gt;
&lt;li&gt;没有第二步。&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;所有的配置工作都在 Web 服务器配置文件的指导下做完了，Phusion Passenger 几乎自动化了所有事情，不需要启动集群以及管理进程。启动或者停止进程，他们崩溃时重启，这些都被自动化了。和其他应用服务器相比，Phusion Passenger 所需要做的改动工作非常少，这是人们使用&amp;nbsp;Phusion Passenger 的主要原因。&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;和其他应用服务器不同的是，Phusion Passenger&amp;nbsp;主要是用 C++ 写的，速度很快。&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Phusion Passenger 的企业版有更多的特性，比如自动回滚重启，支持多线程，容错部署。（such as automated rolling restarts, multithreading support, deployment error resistance, etc.）&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;基于以上原因，Phusion Passenger 是当前最流行的 Ruby 应用服务器，服务于超过 50,000 站点，包括大型站点：New York Times, Pixar, Airbnb。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;六，Phusion Passenger vs 其他服务器&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;相对其他的服务器 &lt;strong&gt;，Phusion Passenger 提供了更多的特性功能：&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;根据访问量自动调整进程的数量。在资源有限的服务器上，我们运行多个 Ruby 应用，而我们的应用不对外公开，而且组织内的访客每天的访问量也很低，例如&amp;nbsp;Gitlab, Redmine 等。Phusion Passenger 能够在进程不使用的时候挂起他们，需要的时候恢复进程，为更重要的应用腾出资源。相比之下，其他的服务器的所有进程会一直运行着。&lt;/li&gt;
&lt;li&gt;有些服务器不适合某些特定的负荷。例如&amp;nbsp;Unicorn 为轻量快速的请求而设计，See&amp;nbsp; &lt;a href="http://unicorn.bogomips.org/PHILOSOPHY.html" rel="nofollow" target="_blank" title=""&gt;the Unicorn website&lt;/a&gt;&amp;nbsp;section "Just Worse in Some Cases".&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Unicorn 不擅长的负荷：&lt;/p&gt;

&lt;p&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;gt;&amp;nbsp;流（e.g. Rails 4 live streaming or Rails 4 template streaming）&lt;/p&gt;

&lt;p&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;gt; 调用 HTTP API&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.phusionpassenger.com/enterprise" rel="nofollow" target="_blank" title=""&gt;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Phusion Passenger Enterprise 4&lt;/a&gt;及后续版本中多种 I/O 模型，使它非常适合这种负荷。&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;其他的应用服务器需要用户为每个应用至少启动一个实例，相比之下，Phusion Passenger 支持一个实例多个应用。这大大减少管理员的开支。&lt;/li&gt;
&lt;li&gt;Phusion Passenger 支持多个&amp;nbsp;MRI Ruby, JRuby 和 Rubinius。Mongrel, Unicorn 和 Thin 只支持 MRI，Puma 也支持三个。&lt;/li&gt;
&lt;li&gt;Phusion Passenger 不仅支持 Ruby，它还支持&amp;nbsp;Python WSGI，所以同样能运行&amp;nbsp;Django 和 Flask 应用。实际上，Phusion Passenger 正在向多语言服务器发展的道路上前进，Node.js 的支持已经列在计划中。&lt;/li&gt;
&lt;li&gt;Out-of-band garbage collection。Phusion Passenger 可以在请求的循坏外执行 Ruby 的垃圾回收，可以潜在地减少几百毫秒的请求时间（reducing request times by hundreds of milliseconds）。Unicorn 也有类似的功能，但是 Phusion Passenger 的版本更加灵活，因为 1，it's not limited to GC and can be used for arbitrary work。2，Phusion Passenger 的版本适应多进程应用，而&amp;nbsp;Unicorn 则不行。&lt;/li&gt;
&lt;li&gt;自动回滚重启（Automated rolling restarts）。Unicorn 以及其他应用服务器的回滚重启需要脚本来执行，Phusion Passenger&amp;nbsp;企业版自动帮你完成了。&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;还有更多的特性和优势，暂不一一列举。你可以参考全面的&amp;nbsp;Phusion Passenger 手册 ( &lt;a href="http://www.modrails.com/documentation/Users%20guide%20Apache.html" rel="nofollow" target="_blank" title=""&gt;Apache version&lt;/a&gt;,&amp;nbsp; &lt;a href="http://www.modrails.com/documentation/Users%20guide%20Nginx.html" rel="nofollow" target="_blank" title=""&gt;Nginx version&lt;/a&gt;)，或者到官网得到更多信息。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;七，I/O 并发模型&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;单线程，多进程。&lt;/strong&gt; Ruby 应用服务器中比较常见、流行的 I/O 模型，主要是因为 Ruby 生态系统中的多线程支持比较差。一个进程同时仅且只能处理一个请求，web 服务器通过多进程来进行均衡负载。这种模型比较稳定，开发者不会轻易造成并发 bug。这种模型适合执行快速的短请求，不适合速度慢、长请求阻塞 I/O 的运算，例如 调用 HTTP API。&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;纯多线程&lt;/strong&gt; 。现在 Ruby 生态系统已经很支持多线程了，所以这种 I/O 模型变得切实可行。多线程支持高 I/O 并发，既适合短请求也适合长请求。开发者也很容易引入并发 bug，幸运的是大多数框架按照这种方式设计，所以也不太可能发生。有一个需要注意的事情是，因为使用了全局解释器锁（GIL），MRI Ruby 解释器不能均衡使用多个 CPU 内核，即使有多个线程。为此，你可以使用多个进程，每个进程使用一个 CPU 内核。JRuby&amp;nbsp;和&amp;nbsp;Rubinius 没有 GIL，所以他们的一个进程可以均衡负载多个 CPU 内核。&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;结合多线程、多进程&lt;/strong&gt; 。Phusion Passenger Enterprise 4 以后版本实现了。你可以轻易在以下模型切换：单进程多线程，纯多线程，多进程多线程。这种模型给出了最好的选择方式。&amp;nbsp;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;事件。这种模型和之前提到的模型不一样。它允许极高的 I/O 并发，以及非常适合长请求。为实现此功能，需要从应用到框架的详细支持。然而主要的框架（Rails 和&amp;nbsp;Sinatra）并不支持事件模型。这也是实际上一个 Thin 进程同时不能处理多个请求的原因，就像单线程多进程模型一样。只有专门的框架才充分利用事件 I/O 模型，例如 Cramp。&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;八，Capistrano&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Capistrano 和其他的不一样。在之前的所有章节中，“部署”指的是在服务器上启动 Ruby 应用，然后对访客开放，但是在这之前需要一些准备工作，例如：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;将 Ruby 应用的代码和文件上传到服务器机器上。&lt;/li&gt;
&lt;li&gt;安装应用所依赖的库。&lt;/li&gt;
&lt;li&gt;创建或者迁移数据库。&lt;/li&gt;
&lt;li&gt;启动或者停止应用依赖的守护进程，例如&amp;nbsp;Sidekiq/Resque &amp;nbsp;或者&amp;nbsp;whatever。&lt;/li&gt;
&lt;li&gt;启动应用时需要做的所有其他事情。&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;在 Capistrano 的语义中，“部署”意味着去做所有的准备工作。Capistrano 不是一个服务器，反而是一个自动做那些准备工作的工具。你告诉&amp;nbsp;Capistrano 你的服务器在哪里，以及每当你部署新版本应用的时候需要执行的命令，Capistrano 就能帮你上传 Ruby 应用到服务器上并且运行你指定的命令。&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Capistrano 总是与应用服务器组合使用，并不会替代应用服务器。反之亦然，应用服务器也不会替代&amp;nbsp;Capistrano。&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;当然&amp;nbsp;Capistrano 也不是必须使用的。如果你可以使用 FTP 或者 手动上传 Ruby 应用，每一次都执行相同的动作。其他人厌倦这种重复，所以他们在&amp;nbsp;Capistrano 中自动执行这些步骤。&lt;/p&gt;</description>
      <author>besfan</author>
      <pubDate>Thu, 23 Apr 2015 21:51:41 +0800</pubDate>
      <link>https://ruby-china.org/topics/25276</link>
      <guid>https://ruby-china.org/topics/25276</guid>
    </item>
    <item>
      <title>杭州的线下聚会很少么？</title>
      <description>&lt;p&gt;杭州的 rubyist  很少么？ruby 聚会的频率很低唉……&lt;/p&gt;

&lt;p&gt;本人初到杭州&lt;/p&gt;</description>
      <author>besfan</author>
      <pubDate>Wed, 01 Oct 2014 09:41:49 +0800</pubDate>
      <link>https://ruby-china.org/topics/21804</link>
      <guid>https://ruby-china.org/topics/21804</guid>
    </item>
    <item>
      <title>如何参与 Ruby 开源项目？</title>
      <description>&lt;p&gt;小弟想参加开源项目，有几个问题请教一下：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;有哪些 ruby 相关的开源项目，或者到哪里去找到这些开源项目？&lt;/li&gt;
&lt;li&gt;参与开源项目需要投入多少时间和精力？&lt;/li&gt;
&lt;li&gt;参与开源项目需要注意些什么？&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;以上&lt;/p&gt;</description>
      <author>besfan</author>
      <pubDate>Wed, 13 Aug 2014 09:19:15 +0800</pubDate>
      <link>https://ruby-china.org/topics/20995</link>
      <guid>https://ruby-china.org/topics/20995</guid>
    </item>
    <item>
      <title>各位开发过程中都是遵循 TDD 的么？</title>
      <description>&lt;p&gt;请问各位，你们在 ruby on rails 相关的开发过程中，都是遵循 TDD 的么？先写测试，然后再编码&lt;/p&gt;</description>
      <author>besfan</author>
      <pubDate>Sun, 01 Jun 2014 10:52:27 +0800</pubDate>
      <link>https://ruby-china.org/topics/19665</link>
      <guid>https://ruby-china.org/topics/19665</guid>
    </item>
    <item>
      <title>production 模式下 @import "bootstrap"不能生效</title>
      <description>&lt;p&gt;我在跟着&lt;a href="http://railstutorial-china.org/chapter5.html" rel="nofollow" target="_blank"&gt;http://railstutorial-china.org/chapter5.html&lt;/a&gt; 学习，使用 bootstrap 的时候，发现在 development 下页面的布局是正常的，bootstrap 被导入了，而 production 下 bootstrap 没有被导入。
求各位大神帮忙看一下。&lt;/p&gt;

&lt;p&gt;使用 firebug 看到/assets/application-1cd2bb7dabfed08f435790f666470fe7.css&lt;/p&gt;
&lt;pre class="highlight scss"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;!&lt;/span&gt;&lt;span class="nt"&gt;DOCTYPE&lt;/span&gt; &lt;span class="nt"&gt;html&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;html&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;head&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;title&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nt"&gt;The&lt;/span&gt; &lt;span class="nt"&gt;page&lt;/span&gt; &lt;span class="nt"&gt;you&lt;/span&gt; &lt;span class="nt"&gt;were&lt;/span&gt; &lt;span class="nt"&gt;looking&lt;/span&gt; &lt;span class="nt"&gt;for&lt;/span&gt; &lt;span class="nt"&gt;doesn&lt;/span&gt;&lt;span class="s1"&gt;'t exist (404)&amp;lt;/title&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="s1"&gt;  &amp;lt;style&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="s1"&gt;  body {&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="s1"&gt;    background-color: #EFEFEF;&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="s1"&gt;    color: #2E2F30;&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="s1"&gt;    text-align: center;&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="s1"&gt;    font-family: arial, sans-serif;&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="s1"&gt;  }&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="s1"&gt;.......&lt;/span&gt;&lt;span class="err"&gt;

&lt;/span&gt;&lt;span class="s1"&gt;  &amp;lt;/style&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;

&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="s1"&gt;  &amp;lt;!-- This file lives in public/404.html --&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="s1"&gt;  &amp;lt;div class="dialog"&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="s1"&gt;    &amp;lt;h1&amp;gt;The page you were looking for doesn'&lt;/span&gt;&lt;span class="nt"&gt;t&lt;/span&gt; &lt;span class="nt"&gt;exist&lt;/span&gt;&lt;span class="nc"&gt;.&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;

    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nt"&gt;You&lt;/span&gt; &lt;span class="nt"&gt;may&lt;/span&gt; &lt;span class="nt"&gt;have&lt;/span&gt; &lt;span class="nt"&gt;mistyped&lt;/span&gt; &lt;span class="nt"&gt;the&lt;/span&gt; &lt;span class="nt"&gt;address&lt;/span&gt; &lt;span class="nt"&gt;or&lt;/span&gt; &lt;span class="nt"&gt;the&lt;/span&gt; &lt;span class="nt"&gt;page&lt;/span&gt; &lt;span class="nt"&gt;may&lt;/span&gt; &lt;span class="nt"&gt;have&lt;/span&gt; &lt;span class="nt"&gt;moved&lt;/span&gt;&lt;span class="nc"&gt;.&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nt"&gt;If&lt;/span&gt; &lt;span class="nt"&gt;you&lt;/span&gt; &lt;span class="nt"&gt;are&lt;/span&gt; &lt;span class="nt"&gt;the&lt;/span&gt; &lt;span class="nt"&gt;application&lt;/span&gt; &lt;span class="nt"&gt;owner&lt;/span&gt; &lt;span class="nt"&gt;check&lt;/span&gt; &lt;span class="nt"&gt;the&lt;/span&gt; &lt;span class="nt"&gt;logs&lt;/span&gt; &lt;span class="nt"&gt;for&lt;/span&gt; &lt;span class="nt"&gt;more&lt;/span&gt; &lt;span class="nt"&gt;information&lt;/span&gt;&lt;span class="nc"&gt;.&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;html&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而工程的 public/assets/application-1cd2bb7dabfed08f435790f666470fe7.css 中内容是正常的&lt;/p&gt;
&lt;pre class="highlight scss"&gt;&lt;code&gt;&lt;span class="cm"&gt;/*!
 * Bootstrap v2.3.2
 *
 * Copyright 2012 Twitter, Inc
 * Licensed under the Apache License v2.0
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Designed and built with all the love in the world @twitter by @mdo and @fat.
 */&lt;/span&gt;&lt;span class="na"&gt;article&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="na"&gt;aside&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="na"&gt;details&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="na"&gt;figcaption&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="na"&gt;figure&lt;/span&gt;&lt;span class="err"&gt;, ...
* &lt;/span&gt;&lt;span class="na"&gt;Bootstrap&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="na"&gt;v2&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="na"&gt;3&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="na"&gt;2&lt;/span&gt;&lt;span class="err"&gt;
 *
 * &lt;/span&gt;&lt;span class="na"&gt;Copyright&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="na"&gt;2012&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="na"&gt;Twitter&lt;/span&gt;&lt;span class="err"&gt;, &lt;/span&gt;&lt;span class="na"&gt;Inc&lt;/span&gt;&lt;span class="err"&gt;
 * &lt;/span&gt;&lt;span class="na"&gt;Licensed&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="na"&gt;under&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="na"&gt;the&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="na"&gt;Apache&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="na"&gt;License&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="na"&gt;v2&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="na"&gt;0&lt;/span&gt;&lt;span class="err"&gt;
 * &lt;/span&gt;&lt;span class="na"&gt;http&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="n"&gt;www&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;apache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;org&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;licenses&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;LICENSE-2&lt;/span&gt;&lt;span class="mi"&gt;.0&lt;/span&gt;
 &lt;span class="o"&gt;*&lt;/span&gt;
 &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;Designed&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;built&lt;/span&gt; &lt;span class="n"&gt;with&lt;/span&gt; &lt;span class="n"&gt;all&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;love&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;world&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;twitter&lt;/span&gt; &lt;span class="n"&gt;by&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;mdo&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;fat.&lt;/span&gt;
 &lt;span class="o"&gt;*/&lt;/span&gt;&lt;span class="n"&gt;article&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="n"&gt;aside&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="n"&gt;details&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="n"&gt;figcaption&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="n"&gt;figure&lt;/span&gt;&lt;span class="o"&gt;,...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;/app/assets/stylesheets/application.css&lt;/p&gt;
&lt;pre class="highlight scss"&gt;&lt;code&gt;&lt;span class="cm"&gt;/*
 *= require bootstrap
 *= require_self
 *= require_tree .
 */&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;/home/besfan/Documents/woke_space/sample_app/app/assets/stylesheets/custom.css.scss&lt;/p&gt;
&lt;pre class="highlight scss"&gt;&lt;code&gt;&lt;span class="k"&gt;@import&lt;/span&gt; &lt;span class="s2"&gt;"bootstrap"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="cm"&gt;/* mixins, variables, etc. */&lt;/span&gt;

&lt;span class="nv"&gt;$grayMediumLight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mh"&gt;#eaeaea&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="cm"&gt;/* universal */&lt;/span&gt;

&lt;span class="nt"&gt;html&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;overflow-y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;scroll&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.....&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Gemfile&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;source&lt;/span&gt; &lt;span class="s1"&gt;'http://ruby.taobao.org'&lt;/span&gt;
&lt;span class="n"&gt;ruby&lt;/span&gt; &lt;span class="s1"&gt;'2.0.0'&lt;/span&gt;

&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s1"&gt;'rails'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'4.0.4'&lt;/span&gt;

&lt;span class="n"&gt;group&lt;/span&gt; &lt;span class="ss"&gt;:development&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:test&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s1"&gt;'rspec-rails'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'2.13.1'&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="n"&gt;group&lt;/span&gt; &lt;span class="ss"&gt;:test&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s1"&gt;'selenium-webdriver'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'2.35.1'&lt;/span&gt;
  &lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s1"&gt;'capybara'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'2.1.0'&lt;/span&gt;
  &lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s1"&gt;'guard-rspec'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'2.5.0'&lt;/span&gt;
  &lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s1"&gt;'libnotify'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'0.8.0'&lt;/span&gt;

  &lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s1"&gt;'spork-rails'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'4.0.0'&lt;/span&gt;
  &lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s1"&gt;'guard-spork'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'1.5.0'&lt;/span&gt;
  &lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s1"&gt;'childprocess'&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s1"&gt;'sass-rails'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'4.0.1'&lt;/span&gt;
&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s1"&gt;'uglifier'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'2.1.1'&lt;/span&gt;
&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s1"&gt;'coffee-rails'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'4.0.1'&lt;/span&gt;
&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s1"&gt;'jquery-rails'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'2.2.1'&lt;/span&gt;
&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s1"&gt;'turbolinks'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'1.1.1'&lt;/span&gt;
&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s1"&gt;'jbuilder'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'1.0.2'&lt;/span&gt;

&lt;span class="n"&gt;group&lt;/span&gt; &lt;span class="ss"&gt;:doc&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s1"&gt;'sdoc'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'0.3.20'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;require: &lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s1"&gt;'pg'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'0.17.1'&lt;/span&gt;
&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s1"&gt;'therubyracer'&lt;/span&gt;
&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s1"&gt;'execjs'&lt;/span&gt;
&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s1"&gt;'bootstrap-sass'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'2.3.2.0'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;</description>
      <author>besfan</author>
      <pubDate>Sun, 13 Apr 2014 10:01:16 +0800</pubDate>
      <link>https://ruby-china.org/topics/18568</link>
      <guid>https://ruby-china.org/topics/18568</guid>
    </item>
    <item>
      <title>“Welcome aboard” 页面是如何生成的？</title>
      <description>&lt;p&gt;&lt;img src="//l.ruby-china.com/photo/2014/623e32e9813db9bd260795d1c9ca060c.png" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;这个页面是 rails 自己生成的，页面的定义在哪呢？为啥找不到&lt;/p&gt;

&lt;p&gt;使用的是 rails 4.0.2&lt;/p&gt;</description>
      <author>besfan</author>
      <pubDate>Sun, 30 Mar 2014 14:54:37 +0800</pubDate>
      <link>https://ruby-china.org/topics/18261</link>
      <guid>https://ruby-china.org/topics/18261</guid>
    </item>
    <item>
      <title>南京有哪些使用 Ruby on Rails 的公司？</title>
      <description>&lt;p&gt;RT&lt;/p&gt;</description>
      <author>besfan</author>
      <pubDate>Sun, 23 Mar 2014 08:44:24 +0800</pubDate>
      <link>https://ruby-china.org/topics/18103</link>
      <guid>https://ruby-china.org/topics/18103</guid>
    </item>
  </channel>
</rss>
