<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>robbin (Robin Fan)</title>
    <link>https://ruby-china.org/robbin</link>
    <description></description>
    <language>en-us</language>
    <item>
      <title>[上海] 麦田亲子游招聘 Ruby 程序员 2 名 (robbin 创业项目，亲自招募)</title>
      <description>&lt;p&gt;麦田亲子游是 robbin 参与创办的移动互联网 O2O 创业项目，致力于创建线上亲子社区和亲子 O2O 交易平台，麦田亲子游的产品可以通过麦田亲子网站 &lt;a href="http://maitianqinzi.com" rel="nofollow" target="_blank"&gt;http://maitianqinzi.com&lt;/a&gt; 或者 订阅微信公众号“麦田亲子游”浏览。麦田亲子游的有三位联合创始人，CEO 是前艺龙 COO 谢震，CTO 是前 JavaEye 网站创始人 robbin(范凯)，旅游产品 VP 是前高梵旅行创始人乌江，各自拥有行业内超过十年的工作经验，目前已获著名投资机构注资，我们的团队急需各路英才加盟。&lt;/p&gt;
&lt;h2 id="我们急需："&gt;我们急需：&lt;/h2&gt;&lt;h3 id="Ruby工程师2名"&gt;Ruby 工程师 2 名&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;计算机领域的编程基础扎实，具备很强的自学能力，热爱开源，在 github 开源项目者优先；&lt;/li&gt;
&lt;li&gt;3 年以上 Web 领域的开发经验，2 年以上 Ruby 编程实际开发经验；&lt;/li&gt;
&lt;li&gt;在 Linux/Mac 环境下开发，会熟练使用 vi 或者 textmate；&lt;/li&gt;
&lt;li&gt;良好的沟通能力，团队协作能力；&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="iOS工程师2名"&gt;iOS 工程师 2 名&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;计算机领域的编程基础扎实，具备很强的自学能力，热爱开源，在 github 开源项目者优先；&lt;/li&gt;
&lt;li&gt;3 年以上 iOS 开发经验，经历从产品创意实现，到多版本迭代的完整过程，有个人产品更佳；&lt;/li&gt;
&lt;li&gt;良好的沟通能力，团队协作能力；&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="Android工程师2名"&gt;Android 工程师 2 名&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;计算机领域的编程基础扎实，具备很强的自学能力，热爱开源，在 github 开源项目者优先；&lt;/li&gt;
&lt;li&gt;3 年以上 Android 开发经验，经历从产品创意实现，到多版本迭代的完整过程，有个人产品更佳；&lt;/li&gt;
&lt;li&gt;良好的沟通能力，团队协作能力；&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="工作地点"&gt;工作地点&lt;/h2&gt;
&lt;p&gt;上海市闸北区广中西路多媒体大厦 2 层 (近地铁一号线上海马戏城站)&lt;/p&gt;
&lt;h2 id="薪资和工作环境"&gt;薪资和工作环境&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;视工作经验和能力而定，提供匹配市场价值和个人能力的薪水；&lt;/li&gt;
&lt;li&gt;每年 13 个月薪水，核心骨干根据工作贡献享有期权；&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;公司目前有 18 名员工 (麦田 18 罗汉)，仍在快速扩张中，现在加入，参与公司的高速成长，你也将分享到公司的成功，获得丰厚的个人回报。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="简历请发送至"&gt;简历请发送至&lt;/h2&gt;
&lt;p&gt;robbin.fan@maitianqinzi.com 也可以在 RubyChina 直接和我讨论，或者发站内私信。&lt;/p&gt;

&lt;p&gt;附麦田高大上的办公环境：
&lt;img src="https://l.ruby-china.com/photo/2014/fac84a42fac631b364e64816c0b37ab1.jpg" title="" alt=""&gt;
麦田 18 罗汉&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2014/2651870fe454f6ce213ec82689e0796d.jpg" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2014/974d019aec2c7f57fa074feff56808f2.jpg" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2014/d6c80a3b84ab28b773e263b3360ee0d5.jpg" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2014/ec7b52186f37214966e219a493297124.jpg" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2014/60af1f8136743d2b58430560474c8ebd.jpg" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2014/b035cf496951b514b3330404d1b03dee.jpg" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2014/7944c8aa73c72eb022d3d517b11efa6a.jpg" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2014/7185a57771f3c30d828c592d3215986d.jpg" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2014/6b4c1533bf42579e00899be469329a6c.jpg" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2014/3c537c1b5ce0218b03ac20cf52fcbeb3.jpg" title="" alt=""&gt;&lt;/p&gt;</description>
      <author>robbin</author>
      <pubDate>Tue, 18 Nov 2014 10:35:44 +0800</pubDate>
      <link>https://ruby-china.org/topics/22732</link>
      <guid>https://ruby-china.org/topics/22732</guid>
    </item>
    <item>
      <title>Ruby Web API Server 小评测</title>
      <description>&lt;p&gt;首发于自己的网站：&lt;a href="http://robbinfan.com/blog/45/ruby-framework-benchmark" rel="nofollow" target="_blank" title=""&gt;Ruby Web API Server 小评测&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;前几天看到 5 月份杭州 Ruby 活动上黄志敏的 Topic &lt;a href="http://yedingding.com/2013/05/14/ruby-event-5-11.html" rel="nofollow" target="_blank" title=""&gt;构建异步的 API 服务&lt;/a&gt; ，挺有收获的，对 Fiber 方式运行 Web API Server 比较有兴趣。可惜的是作者测试的是单进程并发对比 Fiber 并发的数据，没有测试多线程对比 Fiber 并发，所以周末我写了个简单的测试案例，做了一下评测，评测方案有 4 个，分别是：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://github.com/robbin/ruby_framework_bench/tree/master/grape_on_goliath" rel="nofollow" target="_blank" title=""&gt;grape_on_goliath&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Goliath 有点类似于 Rack，但是提供了 fiber 并发的封装，Grape 是类似于 Sinatra 的 Ruby 轻量级框架，专门为写 API 设计的框架。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://github.com/robbin/ruby_framework_bench/tree/master/grape_on_rainbows" rel="nofollow" target="_blank" title=""&gt;grape_on_rainbows&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Rainbows 是 Ruby 的多线程服务器，Grape 也可以以多线程的方式运行，用来和 fiber 并发做对比。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://github.com/robbin/ruby_framework_bench/tree/master/sinatra_on_rainbows" rel="nofollow" target="_blank" title=""&gt;sinatra_on_rainbows&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Sinatra 以多线程方式运行在 Rainbows 上，可以和 Grape 多线程模式做下对比。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://github.com/robbin/ruby_framework_bench/tree/master/sinatra_on_thin" rel="nofollow" target="_blank" title=""&gt;sinatra_on_thin&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/kyledrake/sinatra-synchrony" rel="nofollow" target="_blank" title=""&gt;sinatra_synchrony&lt;/a&gt;可以让 Sinatra 框架以 fiber 并发的方式运行在 Thin 上，这样测试可以用来对比多线程 Sinatra 并发性能，以及对比 Grape 的 fiber 并发。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;对于 IO 并发来说，无论是多线程并发，还是 fiber 并发，只有当 IO 操作占比例比较高的时候，并发的优势才能体现出来，而测试案例访问的数据库非常简单，数据量又太少，所以我在测试里面设置一个 WAIT_TIME 参数，用来控制访问数据库的时长，最多设置到 500ms，模拟真实环境的数据库 IO 比例。&lt;/p&gt;

&lt;p&gt;在我的 MacbookPro 上做的测试结果在：&lt;a href="https://github.com/robbin/ruby_framework_bench" rel="nofollow" target="_blank" title=""&gt;ruby_framework_bench&lt;/a&gt; ，大家有兴趣和耐心，可以自己测试一下。测试原始数据比较多，我也懒得一一整理了，直接上结论吧：&lt;/p&gt;
&lt;h2 id="Fiber vs Multi-thread"&gt;Fiber vs Multi-thread&lt;/h2&gt;
&lt;p&gt;fiber 并发和多线程并发的原理其实差不多，都是当前执行线程 (纤程) 在执行到外部 IO 调用的时候，放弃 CPU 控制权，让另一个线程 (纤程) 来获取 CPU。主要差异在于 fiber 并发只占用 1 个操作系统线程，由应用程序来调度纤程；而多线程并发占用 n 个操作系统线程，由 Ruby VM 来调度线程。&lt;/p&gt;

&lt;p&gt;因此两者的性能差异主要是调度方式带来的：纤程的场景切换非常轻量级，而多线程的场景切换代价高于纤程，因此理论上来说 fiber 并发性能会更好，实际测试结果也表明了这一点：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Running 状态的并发线程/纤程不太多的情况下，多线程和 fiber 并发的性能差异很小，不明显。&lt;/li&gt;
&lt;li&gt;Running 状态的并发线程/纤程很高的情况下，比方说超过 50 个 running 的线程和纤程，性能差异可以明显的看出来，fiber 并发 CPU 的消耗明显低于线程并发 10-20%。并发越高，性能差异越大。&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;运行 fiber 并发有两个常见的方案：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://github.com/kyledrake/sinatra-synchrony" rel="nofollow" target="_blank" title=""&gt;sinatra_synchrony&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;这是 Kyle Drake 写的一个 Sinatra 扩展，在支持 EventMachine 的 Ruby Web Server(例如 Thin) 运行。当 Web 请求到达的时候，调用 rack fiber_pool 中间件，创建一个 fiber，封装当前执行场景，请求执行完毕，释放 fiber。sinatra_synchrony 还 hack 了 ruby 内置的 TCPSocket，所以向外发起 HTTP 请求，也不会被阻塞，也会让当前 fiber 释放 CPU 控制权。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://github.com/postrank-labs/goliath" rel="nofollow" target="_blank" title=""&gt;goliath&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Goliath 是一个底层的框架，相当于实现了一个 fiber 并发版本的 Rack 框架，简单的项目，可以直接用 Goliath 自己的 API 写，也可以使用 Grape 在 Goliath 上面运行。Sinatra 做一些额外的处理也可以跑在 Goliath 上，但没有用 sinatra_synchrony 更加方便。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;在我的测试当中，sinatra_on_thin 和 grape_on_goliath 没有表现出明显的性能差异，sinatra_on_thin 性能表现的稍微好一点点。&lt;/p&gt;
&lt;h2 id="Sinatra vs Grape"&gt;Sinatra vs Grape&lt;/h2&gt;
&lt;p&gt;sinatra 和 grape 都是 Ruby 的轻量级框架，在同样跑 Rainbows 多线程的评测对比下，也没有表现出明显的性能差异，两者主要区别还是在功能方面：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Grape 是一个纯 API 框架，提供了非常多写 json/xml API 很方便的设施，但不提供任何 view 模板功能&lt;/li&gt;
&lt;li&gt;Sinatra 是一个通用的框架，提供了主流的各种 view 模板功能，但写纯 json/xml API，没有 Grape 方便&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;所以如果写纯 json/xml API 的话，用 Grape 更方便；如果需要模板渲染，那么就用 Sinatra。&lt;/p&gt;
&lt;h2 id="Sinatra on Thin的配置"&gt;Sinatra on Thin 的配置&lt;/h2&gt;
&lt;p&gt;用 Sinatra 写 Web 项目，如果应用的 IO 并发请求非常高，那么用 Thin 跑 fiber 并发，无疑是一个非常好的选择，我是强烈推荐用 sinatra_synchrony 的。但是 fiber 并发对驱动和 IO 库的兼容性要求非常高，目前只有很少的驱动和库能够良好的支持 fiber 并发，&lt;a href="https://github.com/igrigorik/em-synchrony" rel="nofollow" target="_blank" title=""&gt;em-synchrony&lt;/a&gt;提供了常用的 fiber 并发 IO 支持库，我们开发 web 项目，可能涉及到的有：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;数据库，例如 mysql，postgresql，mongodb 等等，目前 em-synchrony 可以良好的支持 mysql 和 mongodb，其他数据库尚不支持。&lt;/li&gt;
&lt;li&gt;缓存服务器，例如 redis 和 memcached，目前 redis-rb 可以提供良好的支持，memcached 也可以用。&lt;/li&gt;
&lt;li&gt;向外发起 HTTP 请求，例如调用其他外部服务，目前 sinatra-synchrony 内置支持，faraday 也提供了良好的支持。&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;我写了一个简单的示例：&lt;a href="https://github.com/robbin/sinatra_synchrony_template" rel="nofollow" target="_blank" title=""&gt;sinatra_synchrony_template&lt;/a&gt; ，相比标准的 sinatra 项目，fiber 并发需要修改如下配置：&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Gemfile&lt;/code&gt;里面&lt;a href="https://github.com/robbin/sinatra_synchrony_template/blob/master/Gemfile" rel="nofollow" target="_blank" title=""&gt;相关配置&lt;/a&gt;：&lt;/p&gt;

&lt;p&gt;gem 'sinatra-synchrony', :require =&amp;gt; 'sinatra/synchrony'
    gem 'em-synchrony', :require =&amp;gt; ['em-synchrony', 'em-synchrony/mysql2', 'em-synchrony/activerecord']&lt;/p&gt;

&lt;p&gt;数据库的配置文件&lt;code&gt;database.yml&lt;/code&gt;需要如下修改：&lt;/p&gt;

&lt;p&gt;adapter: em_mysql2&lt;/p&gt;

&lt;p&gt;如果需要使用 redis 做缓存，配置如下&lt;a href="https://github.com/robbin/sinatra_synchrony_template/blob/master/application.rb" rel="nofollow" target="_blank" title=""&gt;application.rb&lt;/a&gt;    &lt;/p&gt;

&lt;p&gt;CACHE = EventMachine::Synchrony::ConnectionPool.new(size: 100) do
      ActiveSupport::Cache.lookup_store :redis_store, { :host =&amp;gt; "localhost", :port =&amp;gt; "6379", :driver =&amp;gt; :synchrony, :expires_in =&amp;gt; 1.week }
    end&lt;/p&gt;

&lt;p&gt;每个 fiber 会分配一个 redis 连接。&lt;/p&gt;

&lt;p&gt;如果需要使用 memcached 做缓存也可以，memcached 的 ruby client：dalli 并不原生支持 fiber，所以当一个 fiber 访问 memcached 的时候，fiber 并不会放弃 CPU 控制权。不过因为 memcached 访问速度非常快，一般只有 0.1ms 左右，所以并不会造成 fiber 堵塞的问题，可以直接配置：&lt;/p&gt;

&lt;p&gt;CACHE = ActiveSupport::Cache::DalliStore.new("127.0.0.1")&lt;/p&gt;

&lt;p&gt;如果使用 faraday 访问外部服务，配置如下：&lt;/p&gt;

&lt;p&gt;conn = Faraday.new(:url =&amp;gt; '&lt;a href="http://www.facebook.com" rel="nofollow" target="_blank"&gt;http://www.facebook.com&lt;/a&gt;') do |faraday|
        faraday.request  :url_encoded             # form-encode POST params
        faraday.response :logger                  # log requests to STDOUT
        faraday.adapter  :em_synchrony            # fiber aware http client
      end    &lt;/p&gt;

&lt;p&gt;当访问外部服务的时候，当前 fiber 就会放弃 CPU 控制权。&lt;/p&gt;

&lt;p&gt;最后提醒一点：无论多线程还是 fiber 并发，都只能利用单颗 CPU 内核，在多核服务器上，应该启动多个进程，有几个 CPU 内核，就启动几个进程，这样可以充分利用服务器的 CPU 资源。目前无论是支持多线程的 Rainbows，还是支持 fiber 并发的 Thin，都内置了 cluster 的方式，可以配置和控制多个进程。&lt;/p&gt;</description>
      <author>robbin</author>
      <pubDate>Mon, 27 May 2013 00:46:40 +0800</pubDate>
      <link>https://ruby-china.org/topics/11249</link>
      <guid>https://ruby-china.org/topics/11249</guid>
    </item>
    <item>
      <title>Ruby 访问 SQL Server 数据库的简单配置</title>
      <description>&lt;p&gt;首发于自己的网站：&lt;a href="http://robbinfan.com/blog/44/ruby-connect-sqlserver" rel="nofollow" target="_blank" title=""&gt;Ruby 访问 SQL Server 数据库的简单配置&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;因为工作需要，要分析存放在 SQL Server 上的数据，所以不得不研究一下如何使用 Ruby 访问 SQL Server，发现其实还是很简单的：&lt;/p&gt;
&lt;h2 id="安装FreeTDS"&gt;安装 FreeTDS&lt;/h2&gt;
&lt;p&gt;我参考的是&lt;a href="http://qingbo.net/picky/512-freetds-install.html" rel="nofollow" target="_blank" title=""&gt;FreeTDS 安装&lt;/a&gt;这个教程：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;下载&lt;a href="http://mirrors.ibiblio.org/freetds/stable/" rel="nofollow" target="_blank" title=""&gt;FreeTDS 源代码&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;解压编译安装：&lt;/p&gt;

&lt;p&gt;./configure --prefix=/usr/local/freetds &amp;amp;&amp;amp; make &amp;amp;&amp;amp; sudo make install&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="安装Tiny_TDS"&gt;安装 Tiny_TDS&lt;/h2&gt;
&lt;p&gt;我看&lt;a href="http://qingbo.net/picky/513-mac-ruby-sql-server.html" rel="nofollow" target="_blank" title=""&gt;Mac OS X 上 Ruby 连接 SQL Server&lt;/a&gt;这篇文章介绍，还需要安装 unixODBC，DBI，DBI-ODBC 等等，安装和配置起来超麻烦，还需要配置 FreeTDS，我果断的放弃了。我找到了一个新的项目&lt;a href="https://github.com/rails-sqlserver/tiny_tds" rel="nofollow" target="_blank" title=""&gt;Tiny_TDS&lt;/a&gt;，安装和使用非常简单，推荐使用：&lt;/p&gt;

&lt;p&gt;sudo gem install tiny_tds -- --with-freetds-dir=/usr/local/freetds&lt;/p&gt;

&lt;p&gt;用 tiny_tds 访问 SQL Server 很简单：&lt;/p&gt;

&lt;p&gt;require 'tiny_tds'
    client = TinyTds::Client.new(:username =&amp;gt; 'fankai', :password =&amp;gt; 'fankai', :host =&amp;gt; '192.168.0.1', :database =&amp;gt; 'test')
    result = client.execute("select top 10 * from User");
    result.each do |row|
      puts row
    end&lt;/p&gt;
&lt;h2 id="在ActiveRecord上使用Tiny_TDS"&gt;在 ActiveRecord 上使用 Tiny_TDS&lt;/h2&gt;
&lt;p&gt;这也非常简单，参考这个教程&lt;a href="https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/wiki/Using-TinyTds" rel="nofollow" target="_blank" title=""&gt;Using TinyTDS&lt;/a&gt;：&lt;/p&gt;

&lt;p&gt;gem install activerecord-sqlserver-adapter&lt;/p&gt;

&lt;p&gt;配置 database.yml 如下：&lt;/p&gt;

&lt;p&gt;development:
        adapter: sqlserver
        host: mydb.net
        database: myapp_development
        username: sa
        password: secret    &lt;/p&gt;</description>
      <author>robbin</author>
      <pubDate>Mon, 13 May 2013 17:55:22 +0800</pubDate>
      <link>https://ruby-china.org/topics/10955</link>
      <guid>https://ruby-china.org/topics/10955</guid>
    </item>
    <item>
      <title>Ruby 的多线程应用服务器介绍</title>
      <description>&lt;p&gt;随着 Rails4.0 的发布，Ruby 的 Web 开发社区开始进入多线程的时代了：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;从 Ruby1.9 开始，多线程已经是 native thread 了，尽管有 GIL 全局锁的存在，但是对于 IO 并发来说，已经可以实现并行处理了。&lt;/li&gt;
&lt;li&gt;Rails4.0 开始，默认打开了多线程运行模式，将推动整个 Ruby 的 Web 开发社区迁移到多线程 Web 模式。&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;多线程服务器的模型，相比传统多进程服务器模型，可以非常有效的提高 IO 并发的吞吐量。我现在开发 Web 应用，已经全部改用多线程了，我写过一个相关的文档介绍：&lt;a href="http://vdisk.weibo.com/s/kiwIU" rel="nofollow" target="_blank" title=""&gt;Web 并发模型粗浅探讨&lt;/a&gt;，有哪些 Ruby 的应用服务器可以良好的支持多线程呢？&lt;/p&gt;
&lt;h2 id="Rainbows"&gt;Rainbows&lt;/h2&gt;
&lt;p&gt;&lt;a href="http://rainbows.rubyforge.org/" rel="nofollow" target="_blank" title=""&gt;rainbows&lt;/a&gt;和&lt;a href="http://unicorn.bogomips.org/" rel="nofollow" target="_blank" title=""&gt;unicorn&lt;/a&gt;是同一个作者 Eric Wong 开发的，rainbows 和 unicorn 非常像，他们之间的主要区别就是：unicorn 是多进程服务器，rainbows 是多线程服务器，此外基本用法，配置都一样的，本身 rainbows 就是基于 unicorn 开发的。&lt;/p&gt;

&lt;p&gt;unicorn 现在被广泛的使用在很多负载非常高的生产环境中，rainbows 也和 unicorn 同样非常稳定。由于 Ruby1.9 的 GIL，多线程并发只能有效使用 1 颗 CPU 内核，因此在多核服务器上，需要运行多个 rainbows 进程。一般来说，服务器有多少 CPU 内核，就启动多少个 rainbows worker 进程。每个 rainbows 进程里面再启动多个线程，因此理想情况下，能够同时处理的 IO 并发请求数量等于“进程数” × “线程数”，看一个例子：&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/robbin/robbin_site/blob/master/config/rainbows.rb" rel="nofollow" target="_blank" title=""&gt;rainbows.rb&lt;/a&gt;，注意以下 3 项配置：&lt;/p&gt;

&lt;p&gt;use :ThreadPool          # 使用线程池模式，进程启动的时候创建好线程数
    worker_processes 4       # 创建多少个进程
    worker_connections 64    # 每个进程创建多少个线程&lt;/p&gt;

&lt;p&gt;以上面的配置为例，如果你在一台 4 核服务器上面部署应用，希望尽量使用服务器资源，那么可以创建 4 个进程，每个进程创建 64 个线程，因此整个服务器 IO 并发处理能力是 256 个执行线程，这比传统的多进程模式要高得多。&lt;/p&gt;

&lt;p&gt;控制 rainbows 服务器的 shell 脚本很容易写：&lt;a href="https://github.com/robbin/robbin_site/blob/master/rainbows.sh" rel="nofollow" target="_blank" title=""&gt;rainbows.sh&lt;/a&gt;，rainbows 和 unicorn 一样，都是通过给进程发送信号来控制服务器的。&lt;/p&gt;

&lt;p&gt;以上的配置启动以后，会有 5 个 rainbows 进程：1 个 master 控制进程，4 个 worker 工作进程。master 进程负责加载应用程序代码，创建和销毁 worker 进程，分发请求；worker 进程负责处理请求。这个 master-workers 的工作模式和 nginx 是一样的。你还可以通过给 master 进程发送信号，让 master 进程创建更多 worker 进程，或者减少 worker 进程，还可以实现“平滑的重启”，即在不中断 web 请求服务的同时，重新启动进程，加载新的应用代码，这一点通过： &lt;code&gt;rainbowsctl reload&lt;/code&gt;就可以实现。&lt;/p&gt;

&lt;p&gt;此外如果你使用的是 Ruby2.0，还可以在&lt;code&gt;rainbows.rb&lt;/code&gt;里面打开 &lt;u&gt;copy on write&lt;/u&gt; 特性，如下：&lt;/p&gt;

&lt;p&gt;preload_app true
    GC.respond_to?(:copy_on_write_friendly=) and GC.copy_on_write_friendly = true&lt;/p&gt;

&lt;p&gt;可以让多个进程共享加载应用程序框架和库的内存空间，节省很多物理内存。&lt;/p&gt;

&lt;p&gt;总之对于大型多线程 Ruby Web 应用，推荐使用 rainbows，我使用下来感觉也很不错。&lt;/p&gt;
&lt;h2 id="Puma"&gt;Puma&lt;/h2&gt;
&lt;p&gt;我在相当长一段时间都不怎么关注 puma，因为 puma 是个单进程多线程服务器，没有 cluster 模式，不太适合真实有负载的环境，对于多核服务器，启动多进程跑 cluster 是必须的。但是最近 Puma 升级到 2.0 版本以后，也支持了多进程 cluster 模式，而且也是 master-workers 的方式，类似 nginx 和 rainbows，请看配置文件：&lt;a href="https://github.com/robbin/robbin_site/blob/master/config/puma.rb" rel="nofollow" target="_blank" title=""&gt;puma.rb&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;workers 0           # 指定创建多少个 worker 进程，如果 0 则不打开 cluster 模式
    threads 0, 16       # 最少线程和最多线程，可根据请求量在这个范围自动伸缩&lt;/p&gt;

&lt;p&gt;通过 workers 设置进程数，通过 threads 设置线程数，最大 IO 并发请求量等于进程数乘以最大线程数。Puma 比较有意思的地方在于：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;通过 workers 设置，可以在单进程和多进程 cluster 模式之间自动切换，如果是 0，则不启动 master 进程，只有一个单进程，如果 workers 不是 0，则启动 1 个 master 和多个 workers。而且 master 进程不会加载应用代码，master 进程占有内存非常少，当然这个的代价就是如果启动 workers 进程很多，启动时间会很长。&lt;/li&gt;
&lt;li&gt;线程可以根据请求量自动在 min 和 max 之间伸缩，对于较少的请求，启动的线程数少，可以节省资源。&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;此外 puma 也支持“平滑的重启”，也提供了很多有趣的状态控制方式，请看&lt;a href="https://github.com/robbin/robbin_site/blob/master/puma.sh" rel="nofollow" target="_blank" title=""&gt;puma.sh&lt;/a&gt; Puma 启动的时候可以设置一个状态文件，它会把进程的运行状态写进去，方便你控制进程的运行。&lt;/p&gt;
&lt;h2 id="Rainbows or Puma"&gt;Rainbows or Puma&lt;/h2&gt;
&lt;p&gt;我对 Rainbows 和 Puma 做了一些简单的性能压力测试，测试结果表明两者之间的性能差异非常小，Rainbows 稍稍胜出。使用哪个，更多取决于个人偏好。我觉得大型应用使用 Rainbows 更好一些，希望节省服务器资源的小型应用更适合用 Puma。这是因为：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Rainbows 基于 unicorn 的代码，稳定性得到了大量高负载应用的考验。&lt;/li&gt;
&lt;li&gt;Rainbows 提供了很多通过信号控制进程的手段，方便系统管理员干预应用服务器运行。&lt;/li&gt;
&lt;li&gt;在单进程模式下 Puma 只有 1 个工作进程，单 Rainbows 仍然会启动 master-worker 模式，因此 Puma 的单进程更节省内存。&lt;/li&gt;
&lt;li&gt;Puma 的线程可以根据请求自动伸缩，对于请求量小的应用，比较节省资源。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="Zbatery"&gt;Zbatery&lt;/h2&gt;
&lt;p&gt;&lt;a href="http://zbatery.bogomip.org/" rel="nofollow" target="_blank" title=""&gt;zbatery&lt;/a&gt;也是 unicorn 和 rainbows 的作者 Eric Wong 开发的，配置文件可以直接用 rainbows 的，它是 rainbows 的简化版本，只支持单进程多线程，没有 master 进程，信号支持的也不完整，而且很久没有升级过了。比较正规的生产环境可能就不太适合了。但 zbatery 的好处是特别节省内存，比单进程的 puma 还要节省很多内存，如果你想在一个 VPS 上跑很多 web 应用，每个 web 应用流量都很小，那用 zbatery 到非常合适。&lt;/p&gt;</description>
      <author>robbin</author>
      <pubDate>Wed, 08 May 2013 22:25:26 +0800</pubDate>
      <link>https://ruby-china.org/topics/10832</link>
      <guid>https://ruby-china.org/topics/10832</guid>
    </item>
    <item>
      <title>Ruby Web 框架简单介绍</title>
      <description>&lt;p&gt;既然提倡&lt;a href="http://robbinfan.com/blog/40/ruby-off-rails" rel="nofollow" target="_blank" title=""&gt;去 Rails 化&lt;/a&gt;我很想介绍一下 Rails 之外的 Web 框架，懒得长篇大论写文章了，简单写个帖子。&lt;/p&gt;

&lt;p&gt;比较适合写 Web 服务接口的轻量级 Web 框架我推荐两个：Grape 和 Sinatra，两个的区别主要是：&lt;/p&gt;

&lt;p&gt;Grape 是个纯粹的写 API 的框架，提供了很多写 API 很方便的功能，用 Grape 写 API 很爽，应该是首选，他只提供 json/xml/txt 格式输出。&lt;/p&gt;

&lt;p&gt;Sinatra 是个相对完善点的 Web 框架，带有模板渲染功能，但单纯写 API 的话，没有 Grape 爽。不过如果你的 API Server 有可能输出 HTML 页面片段，需要模板功能的话，还是 Sinatra 更合适，否则用 Grape 在代码里面拼字符串还是很麻烦的事情。&lt;/p&gt;

&lt;p&gt;Grape 和 Sinatra 都是基于 Rack 之上很轻量级的封装，我做了框架处理请求速度的测试，以及多线程并发的简单测试，基本上性能差异非常小，Grape 稍微快一点点，但不超过 5%。&lt;a href="https://github.com/robbin/grape-goliath-example/blob/master/test_data.md" rel="nofollow" target="_blank" title=""&gt;测试结果&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;比较适合写 Website 的框架，功能最完善的当然是 Rails，不过我用 Padrino 做了自己的网站项目，发现也很不错，推荐大家用用。&lt;/p&gt;

&lt;p&gt;最后说到并发性能，我自己的测试结果表明，Ruby 的多线程性能在并发量并不是超高的情况下，还是很不错的，对比 Fiber 的来说，性能差异非常小。我做了 Goliath(raw code), Goliath(Grape), Rainbows(Grape), Puma(Grape), Rainbows(Sinatra), Puma(Sinatra), 的并发性能测试，基本在同一水平线上。&lt;a href="https://github.com/robbin/grape-goliath-example/blob/master/test_data.md" rel="nofollow" target="_blank" title=""&gt;测试结果&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;所以如果用 Ruby 写高并发的 API Server，即使不用 Goliath 也行，用 Grape/Sinatra 写 API，用 Rainbows 来跑即可，性能也非常好，而且 Rainbows 的可管理性也非常棒，和 Unicorn 一样方便。&lt;/p&gt;</description>
      <author>robbin</author>
      <pubDate>Fri, 29 Mar 2013 20:10:30 +0800</pubDate>
      <link>https://ruby-china.org/topics/9851</link>
      <guid>https://ruby-china.org/topics/9851</guid>
    </item>
  </channel>
</rss>
