<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>shawnyu (tooooolong)</title>
    <link>https://ruby-china.org/shawnyu</link>
    <description>每个奥特曼背后都有一个默默挨打的小怪兽</description>
    <language>en-us</language>
    <item>
      <title>区块链如何改变世界</title>
      <description>&lt;p&gt;来自 TED 的一个演讲。&lt;/p&gt;

&lt;p&gt;不是想说明什么问题。视频不长，值得一看。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://v.qq.com/x/page/p0538vt2y3g.html" rel="nofollow" target="_blank"&gt;https://v.qq.com/x/page/p0538vt2y3g.html&lt;/a&gt;&lt;/p&gt;</description>
      <author>shawnyu</author>
      <pubDate>Tue, 27 Feb 2018 00:15:56 +0800</pubDate>
      <link>https://ruby-china.org/topics/35086</link>
      <guid>https://ruby-china.org/topics/35086</guid>
    </item>
    <item>
      <title>[南京] 10k-20k 暴走漫画诚聘 Ruby 工程师</title>
      <description>&lt;h2 id="暴走漫画诚聘Ruby工程师"&gt;暴走漫画诚聘 Ruby 工程师&lt;/h2&gt;&lt;h2 id="产品"&gt;产品&lt;/h2&gt;
&lt;p&gt;网站：&lt;a href="http://baozou.com" rel="nofollow" target="_blank"&gt;http://baozou.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;APP&lt;/p&gt;

&lt;p&gt;暴走漫画：&lt;a href="https://itunes.apple.com/ca/app/bao-zou-man-hua-bao-xiao-qiu/id511054696?mt=8" rel="nofollow" target="_blank"&gt;https://itunes.apple.com/ca/app/bao-zou-man-hua-bao-xiao-qiu/id511054696?mt=8&lt;/a&gt;
暴走拍：&lt;a href="https://itunes.apple.com/app/id899376498" rel="nofollow" target="_blank"&gt;https://itunes.apple.com/app/id899376498&lt;/a&gt;
暴走表情：&lt;a href="https://itunes.apple.com/ca/app/bao-zou-biao-qing-da-quan/id1017624491?mt=8" rel="nofollow" target="_blank"&gt;https://itunes.apple.com/ca/app/bao-zou-biao-qing-da-quan/id1017624491?mt=8&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="技术"&gt;技术&lt;/h2&gt;
&lt;p&gt;简单列一下技术栈，详细的架构请移步&lt;a href="http://dev.baozou.com/bao-zou-man-hua-bei-hou-de-gu-shi/" rel="nofollow" target="_blank" title=""&gt;这里&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Rails&lt;/li&gt;
&lt;li&gt;Nginx&lt;/li&gt;
&lt;li&gt;Unicorn&lt;/li&gt;
&lt;li&gt;Grape&lt;/li&gt;
&lt;li&gt;Mysql&lt;/li&gt;
&lt;li&gt;Redis&lt;/li&gt;
&lt;li&gt;Memcache&lt;/li&gt;
&lt;li&gt;ElasticSearch&lt;/li&gt;
&lt;li&gt;Docker&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;worker 系统还有一个推荐系统是用 Go 写的。&lt;/p&gt;
&lt;h2 id="任职要求"&gt;任职要求&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;2 年以上 Ruby 开发经验&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;业务上&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;负责暴走漫画全线移动产品的接口开发工作。暴漫接口流量峰值在 80K requests/minute.  每个业务的设计都要考虑周全，代码要保证性能。&lt;/li&gt;
&lt;li&gt;暴漫接口服务器使用 Golang 重构尝试&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;架构上&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;暴漫数据挖掘分析平台搭建。涉及到 PredictionIO，Spark，ElasticSearch&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;10k-20k 的薪资（具体根据你的能力），五险一金以及法定假期&lt;/li&gt;
&lt;li&gt;MacBook Pro + Dell 显示器&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;li&gt;工作地点在南京江宁区河定桥，地铁出口旁，周围生活便利&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;我们的工作环境
&lt;img src="https://l.ruby-china.com/photo/2015/b7abd338cd468ecfa90f96edab074998.jpg" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;简历请发至  yuchanghong@baozou.com&lt;/p&gt;</description>
      <author>shawnyu</author>
      <pubDate>Wed, 12 Aug 2015 10:59:17 +0800</pubDate>
      <link>https://ruby-china.org/topics/26887</link>
      <guid>https://ruby-china.org/topics/26887</guid>
    </item>
    <item>
      <title>我们为什么会选择 Golang</title>
      <description>&lt;p&gt;&lt;strong&gt;前情提要： &lt;a href="https://ruby-china.org/topics/26785" rel="nofollow" target="_blank"&gt;https://ruby-china.org/topics/26785&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;其实在用 Golang 重写我们的 worker 系统之前是做过很多调研的。
而真正让我们下定决心的是 Parse 的一篇文章。&lt;a href="http://blog.parse.com/learn/how-we-moved-our-api-from-ruby-to-go-and-saved-our-sanity/" rel="nofollow" target="_blank" title=""&gt;How We Moved Our API From Ruby to Go and Saved Our Sanity&lt;/a&gt;。文中讲了 Facebook 的 Parse 团队为什么选择 Golang 代替 Ruby。我翻译下关键几点：&lt;/p&gt;
&lt;h2 id="Parse面临的问题"&gt;Parse 面临的问题&lt;/h2&gt;
&lt;p&gt;Parse 跟暴漫的技术栈比较相似：服务器 Unicorn，部署使用 Capistrano。在高流量面前很多问题都被指数级放大，在每次部署的时候 app server 重启都要很长时间。并且 Unicorn 的重启并不是真正的‘graceful’（这个我们也有同感，重启之后服务会中断 10 秒左右，另外 Parse 在用 Golang 重构之后还写了一个库‘&lt;a href="https://github.com/facebookgo/grace" rel="nofollow" target="_blank" title=""&gt;Grace&lt;/a&gt;’专门解决重启中断服务的问题）。这样造成的服务中断带来的影响非常不好。&lt;/p&gt;

&lt;p&gt;另外像 Unicorn 这样 每个进程同时只能处理一个请求（one process per request），不仅仅是极度的浪费，而且如果某一个 action 突然变慢 将会占满整个 worker poll。导致整个服务都不可用。&lt;/p&gt;
&lt;h2 id="方案选择"&gt;方案选择&lt;/h2&gt;
&lt;p&gt;Parse 在 EventMachine，JRuby，c++, c#, golang 之前做了对比，并最终选择了 go。&lt;/p&gt;
&lt;h4 id="EventMachine"&gt;EventMachine&lt;/h4&gt;
&lt;p&gt;Parse 使用了 EventMachine 实现他们的 push 服务，在使用过程中，由于相关的 gem 成熟度不够，总是碰到一些奇怪的 bug。还是生态的问题，导致实现某些功能的时候无轮子可用。&lt;/p&gt;
&lt;h4 id="JRuby"&gt;JRuby&lt;/h4&gt;
&lt;p&gt;Parse 现在是 Ruby 实现，所以 JRuby 就是正确的选择？JRuby 基于 JVM 可以并发处理大量请求，看起来非常不错。不是的！JRuby 缺乏各种异步库的支持。Parse 担心为了应对业务的增长，还要第二次重构：从 JRuby 到 JAVA。并且 Parse 的工程师团队是在不想在 JVM 中部署并调节各种参数。&lt;/p&gt;

&lt;p&gt;文中还提到了 Twitter 团队在迁移到 Scala 之前对 JRuby 的调查：Twitter 对 MRuby 做了很多工作，包括自己写了一个 GC 工具。本来在 MRuby 上工作很好，效率很高的库，到了 JRuby 上 就不好使了（说白了就是各种库不成熟，生态系统太重要！）迁移过去之后虽然 JRuby 本身快了 2 倍，但是其他东西都面临各种问题，有点得不偿失&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;That's not a fault of JRuby; it's just that at the moment the surrounding ecosystem is still kind of immature. CRuby's was too; we put a lot of investment into it, which we can now take advantage of, and we would have to do the same for JRuby.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;暴漫团队说实话没人用过 JRuby，而且经过这么长时间的发展，生态应该会好很多，但是尽管这样，迁移之后 仍然有很多工作要做吧？&lt;/p&gt;
&lt;h4 id="C++"&gt;C++&lt;/h4&gt;
&lt;p&gt;Parse 团队有很多 c++ 的开发经验，不过 c++ 代码难以 debug 和维护。就我个人而言 严重觉得 c++ 肯定不是 web 项目的选择。另外缺乏 web 相关各种库支持。&lt;/p&gt;
&lt;h4 id="C#"&gt;C#&lt;/h4&gt;
&lt;p&gt;c#有非常好的并发模型支持。不过在Linux上。。。还是看下一条吧&lt;/p&gt;
&lt;h4 id="Golang"&gt;Golang&lt;/h4&gt;
&lt;p&gt;Golang 语言效率高，语言层面支持并发，语法非常简单 易于上手，并发模型容易理解。（我们重构之前只给团队讲了一个小时的语法，然后给了一些些好的 worker 作为参考，然后大家都可以顺利的重构 2-3 个 worker，在两周的时间内）。应该是 worker 系统的最佳选择。&lt;/p&gt;

&lt;p&gt;最后回到暴走漫画的问题&lt;/p&gt;

&lt;p&gt;大家的疑问更多是 既然都是 io 消耗，为什么 golang 会快这么多。
我试着解释下（水平有限）：golang 静态语言 不需要类型推断 抛弃了各种语法糖，在语言效率层面上快上不少，另外在数据库 io 方面 gorm 没有 ActiveRecord 的黑魔法，自然会快很多。&lt;/p&gt;

&lt;p&gt;暴漫的 worker 系统瓶颈在高并发峰值，一旦抗不过去后面就会持续累积。而 golang 在单个任务上虽然只有 5 倍快，但是良好的并发机制，使 job 的执行速度飞快。而在原系统中 每台机器 150 并发跑慢之后，有些 100ms 的任务都等到 23s 之久。&lt;/p&gt;

&lt;p&gt;单个任务执行速度快 5 倍，并发再快 5 倍，所以从 10 台减到 1 台 而 golang 机器还游刃有余是合理的。&lt;/p&gt;

&lt;p&gt;Parse 在重构的时候考虑的是能容纳当前业务峰值的 10 倍的方案。我觉得我们在挑选方案的时候 也要有这种意识。虽然有些方案确实也可以解决目前的困境，但是对以后的架构调整是否有益，或者说兼容。&lt;/p&gt;</description>
      <author>shawnyu</author>
      <pubDate>Sun, 09 Aug 2015 15:34:25 +0800</pubDate>
      <link>https://ruby-china.org/topics/26838</link>
      <guid>https://ruby-china.org/topics/26838</guid>
    </item>
    <item>
      <title>[视频] Rust 0.1 到 1.1 代码变化的可视化效果</title>
      <description>&lt;p&gt;有点溜：&lt;/p&gt;

&lt;p&gt;&lt;span class="embed-responsive embed-responsive-16by9"&gt;&lt;iframe class="embed-responsive-item" src="//www.youtube.com/embed/URAJsTlPnnc" allowfullscreen=""&gt;&lt;/iframe&gt;&lt;/span&gt;&lt;/p&gt;</description>
      <author>shawnyu</author>
      <pubDate>Sun, 09 Aug 2015 14:12:33 +0800</pubDate>
      <link>https://ruby-china.org/topics/26835</link>
      <guid>https://ruby-china.org/topics/26835</guid>
    </item>
    <item>
      <title>[12 台减至 3 台] 用 Golang 重写 Sidekiq 的 worker</title>
      <description>&lt;p&gt;漫画之前使用了 12 台 8 核 16G 机器 跑 sidekiq 的任务&lt;/p&gt;

&lt;p&gt;每次重启 sidekiq 都会造成大量积压 而且要很久才能跑完，所以一般都不太敢重启 sidekiq&lt;/p&gt;

&lt;p&gt;7 月初&lt;a href="/tency" class="user-mention" title="@tency"&gt;&lt;i&gt;@&lt;/i&gt;tency&lt;/a&gt; 带头用 golang 重写了大部分 worker 逻辑
用了这个库 &lt;a href="https://github.com/jrallison/go-workers" rel="nofollow" target="_blank"&gt;https://github.com/jrallison/go-workers&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;最终还没有重构完的 ruby worker 占两台，go worker 只用了一台 而且基本上没什么负载&lt;/p&gt;

&lt;p&gt;有些事情确实不是 ruby 的强项。&lt;/p&gt;

&lt;p&gt;大家关注点有点歪啊，第一时间怀疑我们业务设计有问题么。
其实主要问题还是量大
每天跑 800 万任务&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2015/930667ef4c06f0f4f913f7cccb31ed6c.png" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;每秒 
&lt;img src="https://l.ruby-china.com/photo/2015/b480e50c3eaa7553556da63462dd0fef.png" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;抛个问题，像这样的重型 worker 系统，大家怎么选方案？&lt;/p&gt;

&lt;p&gt;最后最后，有人想来一起维护这个嘛？yuchanghong@baozou.com&lt;/p&gt;

&lt;p&gt;评论区几个有价值的观点：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="/luikore" class="user-mention" title="@luikore"&gt;&lt;i&gt;@&lt;/i&gt;luikore&lt;/a&gt; ：worker 一次取多个任务，然后把 io 读写都 batch。&lt;a href="https://github.com/gzigzigzeo/sidekiq-grouping" rel="nofollow" target="_blank"&gt;https://github.com/gzigzigzeo/sidekiq-grouping&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="/quakewang" class="user-mention" title="@quakewang"&gt;&lt;i&gt;@&lt;/i&gt;quakewang&lt;/a&gt; ：重度网络 IO 试试 异步的 http client&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;</description>
      <author>shawnyu</author>
      <pubDate>Wed, 05 Aug 2015 19:48:02 +0800</pubDate>
      <link>https://ruby-china.org/topics/26785</link>
      <guid>https://ruby-china.org/topics/26785</guid>
    </item>
    <item>
      <title>基于 docker 的高可用 Rails 集群方案探索</title>
      <description>&lt;p&gt;前天看了一篇文章，名字叫做：&lt;a href="http://www.yidianzixun.com/n/083Xmwj5?s=undefined" rel="nofollow" target="_blank" title=""&gt;基于 Docker 的 Rails 集群+Ruby 负载均衡代理&lt;/a&gt;。看完之后心里挺捉鸡的。刚好最近也遇到一些集群的管理问题，这边一起来聊聊基于 DOcker 的 Rails 集群。&lt;/p&gt;
&lt;h2 id="0x0 问题"&gt;0x0 问题&lt;/h2&gt;
&lt;p&gt;运维从来都是一个“不起眼”的大问题。运维工作还特别琐碎，一般要花去工程师大量的时间，同时还有突发性，对工程师机动性要求比较高。所以运维自动化一直在困扰暴走漫画团队。&lt;/p&gt;

&lt;p&gt;虽说大部分运维工作都交给第三方云服务提供商了，但是平时还是有一些机器的维护之类的，繁琐的事情。&lt;/p&gt;

&lt;p&gt;我做的最多的应该就是加减服务器了。暴漫的流量趋势非常规律，每年寒暑假是访问的高峰期，一般会比平时流量高出 2 倍。所以每年寒暑假之前都要添加足量的服务器以应对马上到来的流量高峰，而在寒暑假结束之后，要去掉一部分机器，以节省开支。刚开始完全是人肉运维，我一个人先去开 5 台机器，然后一个个上去改配置文件之类的，感觉好傻。后面就用了 ansible 作为自动化运维工具，这个要比 puppet 和 chef 轻量很多，对付我们这些简单的运维工作绰绰有余。于是现在就变成了开完机器，用 ansible 同步配置，代码，启动 app server，然后手动更新 nginx 配置。&lt;/p&gt;

&lt;p&gt;使用 ansible 之后其实已经轻松很多了，但是还不够，我想象中的自动化集群，应该可以随意增加删除 node，node 不可用的时候自动删除，当然这些都不能影响服务的访问。&lt;/p&gt;

&lt;p&gt;下面介绍一种自动化的 Rails 集群方案。&lt;/p&gt;
&lt;h2 id="0x1 相关技术"&gt;0x1 相关技术&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;docker&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/hashicorp/consul" rel="nofollow" target="_blank" title=""&gt;hashicorp/consul&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/hashicorp/consul-template" rel="nofollow" target="_blank" title=""&gt;hashicorp/consul-template&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/gliderlabs/registrator" rel="nofollow" target="_blank" title=""&gt;hashicorp/registrator&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="0X2 整体架构"&gt;0X2 整体架构&lt;/h2&gt;
&lt;p&gt;&lt;img src="http://dev.baozou.com/content/images/2015/07/Untitled.png" title="" alt=""&gt;&lt;/p&gt;
&lt;h2 id="0x3 实践"&gt;0x3 实践&lt;/h2&gt;
&lt;p&gt;由于不是科普帖，各种工具的详细信息就不自己介绍了。&lt;/p&gt;
&lt;h4 id="consul &amp;amp; registrator"&gt;consul &amp;amp; registrator&lt;/h4&gt;
&lt;p&gt;这两个工具是集群中每个节点的基础服务。我在一台机器上，所以把 consul cluster 给省掉了，只用了一个 consul 节点。下面是 docker-compose 配置。&lt;/p&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;consul&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;hostname&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;node1&lt;/span&gt;
   &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;progrium/consul&lt;/span&gt;
   &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;-server -bootstrap -advertise 172.17.42.1&lt;/span&gt;
   &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
     &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;8400:8400"&lt;/span&gt;
     &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;8500:8500"&lt;/span&gt;
     &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;8600:53/udp"&lt;/span&gt;
&lt;span class="na"&gt;registrator&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gliderlabs/registrator&lt;/span&gt;
   &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;consul://consul:8500&lt;/span&gt;
   &lt;span class="na"&gt;hostname&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;registrator1&lt;/span&gt;
   &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
     &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/var/run/docker.sock:/tmp/docker.sock&lt;/span&gt;
   &lt;span class="na"&gt;links&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
     &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;consul&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;需要注意的是 consul 的启动参数里的 advertise。应该声明为 host 机器的 docker0 的 ip。如果不声明的话会默认使用容器 ip，这样 registrator 注册的设备 ip 都是不可访问的。&lt;/p&gt;

&lt;p&gt;以上配置启动之后一套自动服务器发现功能就算完工了。&lt;/p&gt;

&lt;p&gt;接下来，我们配置一个 web 应用测试一下。&lt;/p&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;web&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx&lt;/span&gt;
  &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./sites-enabled:/etc/nginx/conf.d&lt;/span&gt;
  &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;80:80"&lt;/span&gt;
  &lt;span class="na"&gt;links&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;rails&lt;/span&gt;
&lt;span class="na"&gt;rails&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;tutum/hello-world&lt;/span&gt;
  &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;80"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这个配置生成了 nginx 和 rails，并且挂载了本地的 sites-enabled 文件夹作为 nginx 的配置来源。注意 rails 的 ports 是随机的。&lt;/p&gt;

&lt;p&gt;在 sites-enabled 中配置 nginx server 已 rails 作为 backend。&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;upstream backend {
}
server {
        server_name "10.0.2.15";
        location / {
                proxy_pass http://backend;
        }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;对你并没有看错，upstream 并没有定义可用的 backend node。这个配置将会有 consul-template 根据服务列表自动填充。&lt;/p&gt;

&lt;p&gt;让我们启动这个 web 应用，访问 80 端口是无法访问的 应为没有 backend node。&lt;/p&gt;

&lt;p&gt;接下来需要安装 consule-template, 在 github 下载对应的 release。&lt;/p&gt;

&lt;p&gt;然后创建一个配置文件 ct-nginx.conf&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;consul = "127.0.0.1:8500"
log_level = "warn"

template {
  source = "/home/vagrant/nginx.ctmpl"
  destination = "/home/vagrant/sites-enabled/backend.conf"
  command = "docker-compose -f /home/vagrant/docker-compose.yml restart web"
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;我有映射 consul 的端口，所以直接使用了 127.0.0.1。source 就是我们配置文件的模板。如下&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;upstream backend {
        {{range service "hello-world"}}
        server {{.Address}}:{{.Port}};{{end}}
}
server {
        server_name "10.0.2.15";
        location / {
                proxy_pass http://backend;
        }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;consul-template 提供了方便的模板查询语句，可以直接从 consul 中查询并渲染出配置文件。这个模板中就找出了所有名字为“hello-world”的 service，并且循环输出 service 对应的 Address，也就是服务 ip，Port。&lt;/p&gt;

&lt;p&gt;接着看 ct-nginx.conf，destination 代表模板生成完毕之后的位置，这里直接放在 nginx 的配置文件夹，最后 command 是生成配置后的动作，可以重启各种服务。我们这里在更新 nginx 之后重启生效。&lt;/p&gt;

&lt;p&gt;ok，配置已经妥当，consul 和 registrator 也已经启动，让我们看看当前的服务列表。&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;curl localhost:8500/v1/catalog/service/hello-world?pretty
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;当前并没有注册名为 hello_world 的服务。&lt;/p&gt;

&lt;p&gt;稍微提一下 registrator 注册服务的命名机制
&lt;img src="http://dev.baozou.com/content/images/2015/07/gliderlabs_registrator.png" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;可以通过环境变量来指定。如果不指定，比如我们上面的配置，默认会是镜像名。&lt;/p&gt;

&lt;p&gt;接下来我们启动 consul-template&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;consul-template &lt;span class="nt"&gt;-config&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;./ct-nginx.conf
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;会直接根据模板生成一个 nginx 配置 虽然现在并没有 backend node。&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; /home/vagrant/sites-enabled/backend.conf
upstream backend &lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
server &lt;span class="o"&gt;{&lt;/span&gt;
        server_name &lt;span class="s2"&gt;"10.0.2.15"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        location / &lt;span class="o"&gt;{&lt;/span&gt;
                proxy_pass http://backend&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后启动我们的 web 应用。&lt;/p&gt;

&lt;p&gt;启动之后，请求服务列表就可以看到 helle-world 服务，说明已经实现自动服务发现。&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;curl localhost:8500/v1/catalog/service/hello-world?pretty
&lt;span class="o"&gt;[&lt;/span&gt;
    &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="s2"&gt;"Node"&lt;/span&gt;: &lt;span class="s2"&gt;"node1"&lt;/span&gt;,
        &lt;span class="s2"&gt;"Address"&lt;/span&gt;: &lt;span class="s2"&gt;"172.17.42.1"&lt;/span&gt;,
        &lt;span class="s2"&gt;"ServiceID"&lt;/span&gt;: &lt;span class="s2"&gt;"registrator1:vagrant_rails_1:80"&lt;/span&gt;,
        &lt;span class="s2"&gt;"ServiceName"&lt;/span&gt;: &lt;span class="s2"&gt;"hello-world"&lt;/span&gt;,
        &lt;span class="s2"&gt;"ServiceTags"&lt;/span&gt;: null,
        &lt;span class="s2"&gt;"ServiceAddress"&lt;/span&gt;: &lt;span class="s2"&gt;""&lt;/span&gt;,
        &lt;span class="s2"&gt;"ServicePort"&lt;/span&gt;: 32783
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;浏览器中可以正常访问了，Yeah！
&lt;img src="http://dev.baozou.com/content/images/2015/07/Hello_world_.png" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;ok, 让我们更进一步，scale 我们的 rails node。&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;docker-compose scale &lt;span class="nv"&gt;rails&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;4

&lt;span class="nv"&gt;$ &lt;/span&gt;curl localhost:8500/v1/catalog/service/hello-world?pretty
&lt;span class="o"&gt;[&lt;/span&gt;
    &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="s2"&gt;"Node"&lt;/span&gt;: &lt;span class="s2"&gt;"node1"&lt;/span&gt;,
        &lt;span class="s2"&gt;"Address"&lt;/span&gt;: &lt;span class="s2"&gt;"172.17.42.1"&lt;/span&gt;,
        &lt;span class="s2"&gt;"ServiceID"&lt;/span&gt;: &lt;span class="s2"&gt;"registrator1:vagrant_rails_1:80"&lt;/span&gt;,
        &lt;span class="s2"&gt;"ServiceName"&lt;/span&gt;: &lt;span class="s2"&gt;"hello-world"&lt;/span&gt;,
        &lt;span class="s2"&gt;"ServiceTags"&lt;/span&gt;: null,
        &lt;span class="s2"&gt;"ServiceAddress"&lt;/span&gt;: &lt;span class="s2"&gt;""&lt;/span&gt;,
        &lt;span class="s2"&gt;"ServicePort"&lt;/span&gt;: 32783
    &lt;span class="o"&gt;}&lt;/span&gt;,
    &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="s2"&gt;"Node"&lt;/span&gt;: &lt;span class="s2"&gt;"node1"&lt;/span&gt;,
        &lt;span class="s2"&gt;"Address"&lt;/span&gt;: &lt;span class="s2"&gt;"172.17.42.1"&lt;/span&gt;,
        &lt;span class="s2"&gt;"ServiceID"&lt;/span&gt;: &lt;span class="s2"&gt;"registrator1:vagrant_rails_2:80"&lt;/span&gt;,
        &lt;span class="s2"&gt;"ServiceName"&lt;/span&gt;: &lt;span class="s2"&gt;"hello-world"&lt;/span&gt;,
        &lt;span class="s2"&gt;"ServiceTags"&lt;/span&gt;: null,
        &lt;span class="s2"&gt;"ServiceAddress"&lt;/span&gt;: &lt;span class="s2"&gt;""&lt;/span&gt;,
        &lt;span class="s2"&gt;"ServicePort"&lt;/span&gt;: 32784
    &lt;span class="o"&gt;}&lt;/span&gt;,
    &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="s2"&gt;"Node"&lt;/span&gt;: &lt;span class="s2"&gt;"node1"&lt;/span&gt;,
        &lt;span class="s2"&gt;"Address"&lt;/span&gt;: &lt;span class="s2"&gt;"172.17.42.1"&lt;/span&gt;,
        &lt;span class="s2"&gt;"ServiceID"&lt;/span&gt;: &lt;span class="s2"&gt;"registrator1:vagrant_rails_3:80"&lt;/span&gt;,
        &lt;span class="s2"&gt;"ServiceName"&lt;/span&gt;: &lt;span class="s2"&gt;"hello-world"&lt;/span&gt;,
        &lt;span class="s2"&gt;"ServiceTags"&lt;/span&gt;: null,
        &lt;span class="s2"&gt;"ServiceAddress"&lt;/span&gt;: &lt;span class="s2"&gt;""&lt;/span&gt;,
        &lt;span class="s2"&gt;"ServicePort"&lt;/span&gt;: 32785
    &lt;span class="o"&gt;}&lt;/span&gt;,
    &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="s2"&gt;"Node"&lt;/span&gt;: &lt;span class="s2"&gt;"node1"&lt;/span&gt;,
        &lt;span class="s2"&gt;"Address"&lt;/span&gt;: &lt;span class="s2"&gt;"172.17.42.1"&lt;/span&gt;,
        &lt;span class="s2"&gt;"ServiceID"&lt;/span&gt;: &lt;span class="s2"&gt;"registrator1:vagrant_rails_4:80"&lt;/span&gt;,
        &lt;span class="s2"&gt;"ServiceName"&lt;/span&gt;: &lt;span class="s2"&gt;"hello-world"&lt;/span&gt;,
        &lt;span class="s2"&gt;"ServiceTags"&lt;/span&gt;: null,
        &lt;span class="s2"&gt;"ServiceAddress"&lt;/span&gt;: &lt;span class="s2"&gt;""&lt;/span&gt;,
        &lt;span class="s2"&gt;"ServicePort"&lt;/span&gt;: 32786
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;此时 nginx 已经重启，可以看到 4 个 backend 都开始处理请求。&lt;/p&gt;

&lt;p&gt;&lt;img src="http://dev.baozou.com/content/images/2015/07/2015-07-26-03_47_23.gif" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;可以看到，rails 服务器只要启动之后就自动加入集群，如果一台节点挂掉之后，会自动从集群里去掉，基本上没有任何影响。&lt;/p&gt;

&lt;p&gt;肯定有不足的地方，欢迎讨论，发出来就是为了学习。&lt;/p&gt;

&lt;p&gt;原帖地址  &lt;a href="http://dev.baozou.com/ye-tan-ji-yu-dockerde-railsji-qun/" rel="nofollow" target="_blank"&gt;http://dev.baozou.com/ye-tan-ji-yu-dockerde-railsji-qun/&lt;/a&gt;&lt;/p&gt;</description>
      <author>shawnyu</author>
      <pubDate>Sun, 26 Jul 2015 11:41:09 +0800</pubDate>
      <link>https://ruby-china.org/topics/26651</link>
      <guid>https://ruby-china.org/topics/26651</guid>
    </item>
    <item>
      <title>持续交付初探</title>
      <description>&lt;p&gt;本文不是教程，重在撕逼。只是记录暴走漫画是如何实现简单持续交付方案，我们也在学习中，所以可能有很多不足，大家多多指教。&lt;/p&gt;
&lt;h2 id="0x0 简介"&gt;0x0 简介&lt;/h2&gt;
&lt;p&gt;本文用一个简单的 go 项目作为示例，讲解暴走漫画如果使用 ci 和 tutum 来实现基于容器的持续交付方案。&lt;/p&gt;

&lt;p&gt;准备工作：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;一台服务器作为 ci runner(执行 ci 脚本的机器)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;ci 服务器。我们用的是 gitlab-ci&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;代码库。gitlab&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="0x1 ci配置"&gt;0x1 ci 配置&lt;/h2&gt;
&lt;p&gt;我们代码托管于自建 gitlab, 很自然的选择了 gitlab 的持续集成方案：gitlab-ci. ci 主要有两部分工作要做：1. 测试代码; 2. 部署代码&lt;/p&gt;

&lt;p&gt;ci 所有的任务的执行者是&lt;a href="https://gitlab.com/gitlab-org/gitlab-ci-multi-runner" rel="nofollow" target="_blank" title=""&gt;ci-runner&lt;/a&gt;. 由于最初想在一台机器上实现各个项目的 runner 所以在测试部分选择的 docker 模式的 ci-runner(其他还有 shell 之类). 安装完如图：&lt;/p&gt;

&lt;p&gt;&lt;img src="http://ww3.sinaimg.cn/large/005VSSgcjw1eu9c7c7m01j30ue01e750.jpg" title="" alt="安装完ci-runner"&gt;&lt;/p&gt;

&lt;p&gt;另外由于这个项目是封装在 docker 镜像中，部署之前需要重制镜像并且更新 registry. 所以无奈又新建了一个 runner 直接跑在这个 ci 服务器上，这次使用的是&lt;a href="https://gitlab.com/gitlab-org/gitlab-ci-multi-runner/blob/master/docs/install/linux-repository.md" rel="nofollow" target="_blank" title=""&gt;linux mode&lt;/a&gt;. 安装完之后我们的 ci 服务器就注册两个 ci runner:&lt;/p&gt;

&lt;p&gt;&lt;img src="http://ww4.sinaimg.cn/large/005YapDtjw1eu9ceq88iuj31hg072mzd.jpg" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;至此 ci 部分环境搭建基本结束。下面主要是在 ci 中配置相关 job.&lt;/p&gt;

&lt;p&gt;测试 job&lt;/p&gt;

&lt;p&gt;&lt;img src="http://ww3.sinaimg.cn/large/005S4Lsxjw1eu9ciphl17j31ho0ycaeo.jpg" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;关键是里面的 tags. tags 决定了这个 job 的执行 runer.  在 runner 的配置中也可以指定 tag, 跟这里的 tags 是对应的，只有拥有相同 tag 的 runner 才能执行该 job.&lt;/p&gt;

&lt;p&gt;部署 job
&lt;img src="http://ww2.sinaimg.cn/large/edecee36jw1eu9cn170pvj21hc0z2jwq.jpg" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;deploy job 里面有一个选项是 Refs, 这个可以配置你的部署分支。代码提交到指定分支之后会先做 test 通过之后就会执行 deoloy job.&lt;/p&gt;

&lt;p&gt;类似这样
&lt;img src="http://ww1.sinaimg.cn/large/edf27051jw1eu9crf15f7j21kw0s4af1.jpg" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;最后一句调用 tutum 的 api 重新部署 service. &lt;/p&gt;
&lt;h2 id="0x2 tutum配置"&gt;0x2 tutum 配置&lt;/h2&gt;
&lt;p&gt;tutum 提供了基于 docker 的一整套应用管理方案。他将应用定义为包含多种 service 的 stack, 这个 stack 的感念我感觉就是 docker-compose 而且 api 也很像。所以他的 dashboard 可以分为 stack,service,node,repository 的管理。我就不安利了，大家自己看把。&lt;/p&gt;
&lt;h4 id="添加node"&gt;添加 node&lt;/h4&gt;
&lt;p&gt;应用的载体。&lt;/p&gt;

&lt;p&gt;&lt;img src="http://ww4.sinaimg.cn/large/005S4Lkijw1eu9d19meujj31cg06ojsb.jpg" title="" alt=""&gt;&lt;/p&gt;
&lt;h4 id="添加私有repository"&gt;添加私有 repository&lt;/h4&gt;
&lt;p&gt;&lt;img src="http://ww3.sinaimg.cn/large/edaa5568jw1eu9d4en5a9j21kw03s0t5.jpg" title="" alt=""&gt;
点 lunch 就可以开始生成 service 并且部署。&lt;/p&gt;
&lt;h4 id="配置service"&gt;配置 service&lt;/h4&gt;
&lt;p&gt;我没有使用 stack 是因为这个项目只有一个 web server 需要单独跑，数据库之类的都是在第三方服务。&lt;/p&gt;

&lt;p&gt;&lt;img src="http://ww4.sinaimg.cn/large/e0b2be0ajw1eu9d89xj3wj21kw0o9wil.jpg" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;这边 tutum 默认是动态端口，可以方便的 scale. 使用了 weave 的网络方案.
&lt;img src="http://ww1.sinaimg.cn/large/e59c9bccjw1eu9dfr71qdj212a04gn0z.jpg" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;不过我这目前就一个 node 就写死了。如果动态端口的话需要配合 stack 使用。&lt;/p&gt;

&lt;p&gt;再回到之前的 &lt;code&gt;tutum service xx redeploy&lt;/code&gt;, 这个是 tutum 提供的&lt;a href="https://github.com/tutumcloud/cli" rel="nofollow" target="_blank" title=""&gt;命令行工具&lt;/a&gt;,非常方便。感觉就像在 docker-compose 外面套了一层。api 基本相似。&lt;/p&gt;

&lt;p&gt;至此，我们已经实现了自动测试部署的功能。整个 workflow 可以通过 slack 监控&lt;/p&gt;

&lt;p&gt;&lt;img src="http://ww4.sinaimg.cn/large/e2f43038jw1eu9ea57hz4j20k70dnmzi.jpg" title="" alt=""&gt;&lt;/p&gt;
&lt;h2 id="0x3 总结"&gt;0x3 总结&lt;/h2&gt;
&lt;p&gt;tutum 毕竟是国外的东西。折腾环境绝笔是最痛苦的！不过装好之后，感觉确实好用。有一点，tutum 分配 node 的方式只有两种：most_empitest, high_avaliable, 我不需要管到底分配给那个 node.  对这个心里总是有点点担心，不过另一边又觉得挺爽。&lt;/p&gt;

&lt;p&gt;上面那么多其实挺简单的，没啥技术含量都是配置。下面我还会研究 tutum 的 stack, 主要是用官方的 haproxy 镜像来 scale web service.&lt;/p&gt;

&lt;p&gt;另外还有一个需要考虑的是线上代码的快速回滚。官方提供了一篇相关的&lt;a href="http://blog.tutum.co/2015/06/08/blue-green-deployment-using-containers/" rel="nofollow" target="_blank" title=""&gt;博文&lt;/a&gt;不过目前还没搞明白。&lt;/p&gt;

&lt;p&gt;再发一个官方教程，蛮有帮助的：&lt;a href="https://support.tutum.co/support/solutions/folders/5000204714" rel="nofollow" target="_blank"&gt;https://support.tutum.co/support/solutions/folders/5000204714&lt;/a&gt;&lt;/p&gt;</description>
      <author>shawnyu</author>
      <pubDate>Mon, 20 Jul 2015 18:07:04 +0800</pubDate>
      <link>https://ruby-china.org/topics/26575</link>
      <guid>https://ruby-china.org/topics/26575</guid>
    </item>
    <item>
      <title>Select TOP n rows form each group</title>
      <description>&lt;p&gt;怎么解决这个问题&lt;/p&gt;

&lt;p&gt;mysql 查起来很慢。
Redis 模型太复杂了，而且还不好更新
关键是数据量没法控制
mongodb 的 Map/Reduce 据说很慢？&lt;/p&gt;

&lt;p&gt;来讨论下
查询要实时。&lt;/p&gt;</description>
      <author>shawnyu</author>
      <pubDate>Mon, 27 Oct 2014 16:25:56 +0800</pubDate>
      <link>https://ruby-china.org/topics/22287</link>
      <guid>https://ruby-china.org/topics/22287</guid>
    </item>
    <item>
      <title>[上海，南京] 暴走漫画诚聘各路英才，一起改变中国动漫产业</title>
      <description>&lt;p&gt;暴走漫画现在还算是创业公司，技术团队还是不到 10 人的小团队，为了应对公司业务的快速发展，我们也在不断扩充技术团队。&lt;/p&gt;
&lt;h2 id="工作环境"&gt;工作环境&lt;/h2&gt;
&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2014/8c9edda993aefe946da29d8cf9d4ce17.jpg" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2014/756c7a1e3313789928afb4b45266c33e.jpg" title="" alt=""&gt;&lt;/p&gt;
&lt;h2 id="基本要求"&gt;基本要求&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;工作积极主动，自我驱动。&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;良好的沟通能力&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;精通 Rails&lt;/li&gt;
&lt;li&gt;熟悉 Redis，Mysql，Memcached&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="加分项"&gt;加分项&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Mahout(推荐系统，分类系统)&lt;/li&gt;
&lt;li&gt;Angular JS&lt;/li&gt;
&lt;li&gt;Elasticsearch&lt;/li&gt;
&lt;li&gt;数据可视化&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="报酬"&gt;报酬&lt;/h2&gt;
&lt;p&gt;8K 起不封顶&lt;/p&gt;
&lt;h2 id="工作地点"&gt;工作地点&lt;/h2&gt;
&lt;p&gt;南京－暴漫系列产品  简历请发至 yuchanghong at baozou.com
上海－一款 killer app 简历请发至 shhr at baozou.com&lt;/p&gt;</description>
      <author>shawnyu</author>
      <pubDate>Fri, 24 Oct 2014 13:56:07 +0800</pubDate>
      <link>https://ruby-china.org/topics/22243</link>
      <guid>https://ruby-china.org/topics/22243</guid>
    </item>
    <item>
      <title>[上海，南京] 暴走漫画诚聘各方英才</title>
      <description>&lt;p&gt;暴走漫画现在还算是创业公司，技术团队还是不到 10 人的小团队，为了应对公司业务的快速发展，我们也在不断扩充技术团队。&lt;/p&gt;
&lt;h2 id="我们在这里"&gt;我们在这里&lt;/h2&gt;
&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2014/8c9edda993aefe946da29d8cf9d4ce17.jpg" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2014/756c7a1e3313789928afb4b45266c33e.jpg" title="" alt=""&gt;&lt;/p&gt;
&lt;h2 id="做了这些事情"&gt;做了这些事情&lt;/h2&gt;
&lt;p&gt;暴走漫画网站日 140 万访问量，API 服务器每日处理请求数量峰值 7000 万次。每日新增帖子 2 万，新注册用户 7 千。
暴走大事件单日播放 300 万，累计播放量过亿。
我们超过万万没想到冲到优酷第一，评分已经 10 分马上就要爆了。&lt;/p&gt;
&lt;h2 id="我们想找一些同学一起扩大我们的业务。"&gt;我们想找一些同学一起扩大我们的业务。&lt;/h2&gt;&lt;h2 id="基本要求"&gt;基本要求&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;工作积极主动，自我驱动。&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;良好的沟通能力&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;精通 Rails&lt;/li&gt;
&lt;li&gt;熟悉 Redis，Mysql，Memcached&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="加分项"&gt;加分项&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Mahout(推荐系统，分类系统)&lt;/li&gt;
&lt;li&gt;Angular JS&lt;/li&gt;
&lt;li&gt;Elasticsearch&lt;/li&gt;
&lt;li&gt;数据可视化&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="工作地点"&gt;工作地点&lt;/h2&gt;
&lt;p&gt;南京－暴漫系列产品
上海－一款 killer app（Leader &lt;a href="/shiningray" class="user-mention" title="@shiningray"&gt;&lt;i&gt;@&lt;/i&gt;shiningray&lt;/a&gt;）&lt;/p&gt;
&lt;h2 id="报酬"&gt;报酬&lt;/h2&gt;
&lt;p&gt;8K 起不封顶&lt;/p&gt;

&lt;p&gt;简历请发至 yuchanghong@baozou.com&lt;/p&gt;</description>
      <author>shawnyu</author>
      <pubDate>Sat, 26 Jul 2014 22:03:45 +0800</pubDate>
      <link>https://ruby-china.org/topics/20695</link>
      <guid>https://ruby-china.org/topics/20695</guid>
    </item>
    <item>
      <title>case..when.. 条件是 class 的时候不能理解的现象</title>
      <description>&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;ruby&lt;/span&gt; &lt;span class="err"&gt;－&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;
&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mf"&gt;2.0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;p247&lt;/span&gt;

&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&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="n"&gt;a&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;=&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Array&lt;/span&gt;

&lt;span class="n"&gt;a&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;Array&lt;/span&gt;
&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;

&lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;class&lt;/span&gt;
&lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="no"&gt;Array&lt;/span&gt;
  &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt;
  &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这个怎么理解，或者说其中原理是什么？
刚被坑了一下。&lt;/p&gt;

&lt;p&gt;所以最后我觉得 case..when..应该这么写吧&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;
&lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="no"&gt;Array&lt;/span&gt;
  &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt;
  &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="下面是从Stack Overflow 上扒下来的"&gt;下面是从 Stack Overflow 上扒下来的&lt;/h2&gt;
&lt;p&gt;I'm going to heavily quote the Object documentation here, because I think it has some great explanations. I encourage you to read it, and also the documentation for these methods as they're overridden in other classes, like String.&lt;/p&gt;

&lt;p&gt;Side note: if you want to try these out for yourself on different objects, use something like this:&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Object&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;all_equals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ops&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:==&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:===&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:eql?&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:equal?&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="no"&gt;Hash&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ops&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="ss"&gt;:to_s&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;zip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ops&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nb"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;)&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="s2"&gt;"a"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all_equals&lt;/span&gt; &lt;span class="s2"&gt;"a"&lt;/span&gt; &lt;span class="c1"&gt;# =&amp;gt; {"=="=&amp;gt;true, "==="=&amp;gt;true, "eql?"=&amp;gt;true, "equal?"=&amp;gt;false}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="== — generic "&gt;== — generic "equality"&lt;/h2&gt;
&lt;p&gt;At the Object level, == returns true only if obj and other are the same object. Typically, this method is overridden in descendant classes to provide class-specific meaning.&lt;/p&gt;

&lt;p&gt;This is the most common comparison, and thus the most fundamental place where you (as the author of a class) get to decide if two objects are "equal" or not.&lt;/p&gt;
&lt;h2 id="=== — case equality"&gt;=== — case equality&lt;/h2&gt;
&lt;p&gt;For class Object, effectively the same as calling #==, but typically overridden by descendants to provide meaningful semantics in case statements.&lt;/p&gt;

&lt;p&gt;This is incredibly useful. Examples of things which have interesting === implementations:&lt;/p&gt;

&lt;p&gt;Range
Regex
Proc (in Ruby 1.9)&lt;/p&gt;

&lt;p&gt;So you can do things like:&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;some_object&lt;/span&gt;
&lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="sr"&gt;/a regex/&lt;/span&gt;
  &lt;span class="c1"&gt;# The regex matches&lt;/span&gt;
&lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;
  &lt;span class="c1"&gt;# some_object is in the range 2..4&lt;/span&gt;
&lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="nb"&gt;lambda&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;some_crazy_custom_predicate&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="c1"&gt;# the lambda returned true&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;See my answer here for a neat example of how case+Regex can make code a lot cleaner. And of course, by providing your own === implementation, you can get custom case semantics.&lt;/p&gt;
&lt;h2 id="eql? — generic (possibly alternate) equality"&gt;eql? — generic (possibly alternate) equality&lt;/h2&gt;
&lt;p&gt;The eql? method returns true if obj and other have the same value. Used by Hash to test members for equality. For objects of class Object, eql? is synonymous with ==. Subclasses normally continue this tradition, but there are exceptions. Numeric types, for example, perform type conversion across ==, but not across eql?, so:&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mf"&gt;1.0&lt;/span&gt;     &lt;span class="c1"&gt;#=&amp;gt; true&lt;/span&gt;
&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;eql?&lt;/span&gt; &lt;span class="mf"&gt;1.0&lt;/span&gt;   &lt;span class="c1"&gt;#=&amp;gt; false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So you're free to override this for your own uses, or you can just override == and by default eql? will behave the same way.&lt;/p&gt;
&lt;h2 id="equal? — identity comparison"&gt;equal? — identity comparison&lt;/h2&gt;
&lt;p&gt;Unlike ==, the equal? method should never be overridden by subclasses: it is used to determine object identity (that is, a.equal?(b) iff a is the same object as b).&lt;/p&gt;

&lt;p&gt;This is effectively pointer comparison.&lt;/p&gt;</description>
      <author>shawnyu</author>
      <pubDate>Tue, 10 Dec 2013 10:05:25 +0800</pubDate>
      <link>https://ruby-china.org/topics/16109</link>
      <guid>https://ruby-china.org/topics/16109</guid>
    </item>
    <item>
      <title>[已解决] 有没有人用过百度云推送</title>
      <description>&lt;p&gt;有人用 ruby 开发过百度云推送的接口吗，我现在一直遇到 403 错误，大概是因为签名生成的有问题。
高手们 来告诉我吧。
在线等&lt;/p&gt;

&lt;p&gt;UPDATE
这是生成的签名串
POSThttp://channel.api.duapp.com/rest/2.0/channel/channelapikey=GMY1kj3SGG19CQvX6LG967Rpmethod=query_bindlisttimestamp=13787756536xxxxxx&lt;/p&gt;

&lt;p&gt;百度说要 urlencode 这个字符串
然后我就直接 URI.encode 得到的结果和上面一样。&lt;/p&gt;

&lt;p&gt;其实 &lt;code&gt;:&lt;/code&gt;,&lt;code&gt;/&lt;/code&gt; 这些符号都需要 encode
换成 CGI::escape 就行了&lt;/p&gt;

&lt;p&gt;UPDATE
应&lt;a href="/iamzhangdabei" class="user-mention" title="@iamzhangdabei"&gt;&lt;i&gt;@&lt;/i&gt;iamzhangdabei&lt;/a&gt;要求来写下怎么发现这个问题的.
我们试了很多方法，搜了很多都没注意到那个 url 的问题.
最后&lt;a href="/iamzhangdabei" class="user-mention" title="@iamzhangdabei"&gt;&lt;i&gt;@&lt;/i&gt;iamzhangdabei&lt;/a&gt;下载了一个 nodejs 的 demo 运行了一下发现这个坑
:(&lt;/p&gt;</description>
      <author>shawnyu</author>
      <pubDate>Mon, 09 Sep 2013 20:48:42 +0800</pubDate>
      <link>https://ruby-china.org/topics/13992</link>
      <guid>https://ruby-china.org/topics/13992</guid>
    </item>
    <item>
      <title>暑假结束了，网站流量暴跌</title>
      <description>&lt;p&gt;简直惨，流量不到暑假的一半
&lt;img src="//l.ruby-china.com/photo/a6d248987d15523cdefcee1e2feacf6b.png" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;这张是一天的
&lt;img src="//l.ruby-china.com/photo/060a751be7614c831ec5cadae8fa721c.png" title="" alt=""&gt;&lt;/p&gt;</description>
      <author>shawnyu</author>
      <pubDate>Fri, 06 Sep 2013 16:25:42 +0800</pubDate>
      <link>https://ruby-china.org/topics/13927</link>
      <guid>https://ruby-china.org/topics/13927</guid>
    </item>
    <item>
      <title>上传图片 403</title>
      <description>&lt;p&gt;试过好几次。&lt;/p&gt;</description>
      <author>shawnyu</author>
      <pubDate>Tue, 03 Sep 2013 11:21:15 +0800</pubDate>
      <link>https://ruby-china.org/topics/13844</link>
      <guid>https://ruby-china.org/topics/13844</guid>
    </item>
    <item>
      <title>HHKB pro2 白色无刻 换 黑色</title>
      <description>&lt;p&gt;如题，看腻了，想试试黑色的。&lt;/p&gt;

&lt;p&gt;99 新 发票盒子都有.
淘宝花尽数码买的.
yu.chaong#gmail&lt;/p&gt;

&lt;p&gt;稍后传图，现在传不上去...&lt;/p&gt;</description>
      <author>shawnyu</author>
      <pubDate>Tue, 03 Sep 2013 11:09:31 +0800</pubDate>
      <link>https://ruby-china.org/topics/13842</link>
      <guid>https://ruby-china.org/topics/13842</guid>
    </item>
    <item>
      <title>数据库大比拼</title>
      <description>&lt;p&gt;&lt;a href="http://kkovacs.eu/cassandra-vs-mongodb-vs-couchdb-vs-redis/" rel="nofollow" target="_blank"&gt;http://kkovacs.eu/cassandra-vs-mongodb-vs-couchdb-vs-redis/&lt;/a&gt;&lt;/p&gt;</description>
      <author>shawnyu</author>
      <pubDate>Mon, 08 Jul 2013 14:17:05 +0800</pubDate>
      <link>https://ruby-china.org/topics/12341</link>
      <guid>https://ruby-china.org/topics/12341</guid>
    </item>
    <item>
      <title>Rails  number_to_human 怎么设置 xx 万的格式</title>
      <description>&lt;p&gt;number_to_human 这个方法 用的是美国的习惯 已千断位&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;number_to_human(11234511)
=&amp;gt; 11.2 百万

number_to_human(112345)
=&amp;gt; 112.3 千
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;不太符合中国人的习惯 所以想设置成已万为单位&lt;/p&gt;

&lt;p&gt;如何设置 &lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;number_to_human(112345)
=&amp;gt; 11.2 万
&lt;/code&gt;&lt;/pre&gt;</description>
      <author>shawnyu</author>
      <pubDate>Thu, 04 Jul 2013 10:37:27 +0800</pubDate>
      <link>https://ruby-china.org/topics/12237</link>
      <guid>https://ruby-china.org/topics/12237</guid>
    </item>
    <item>
      <title>理解 Rails 之 Array 的 extract_options! 方法</title>
      <description>&lt;p&gt;注：原帖地址&lt;a href="http://www.simonecarletti.com/blog/2009/09/inside-ruby-on-rails-extract_options-from-arrays/" rel="nofollow" target="_blank"&gt;http://www.simonecarletti.com/blog/2009/09/inside-ruby-on-rails-extract_options-from-arrays/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;刚刚在讨论《代码的未来》的翻译，我也来试试，体验下译者的辛苦，请在评论里纠错
我英文很烂 &lt;img title=":cry:" alt="😢" src="https://twemoji.ruby-china.com/2/svg/1f622.svg" class="twemoji"&gt;&lt;/p&gt;

&lt;p&gt;在 Rails 项目里面是不是经常看到下面的方法调用？&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;my_method&lt;/span&gt; &lt;span class="ss"&gt;:arg1&lt;/span&gt;
&lt;span class="n"&gt;my_method&lt;/span&gt; &lt;span class="ss"&gt;:arg1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:arg2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:argN&lt;/span&gt;
&lt;span class="n"&gt;my_method&lt;/span&gt; &lt;span class="ss"&gt;:arg1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:foo&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:bar&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;my_method&lt;/code&gt;的特别之处在于它可以接受任意数量的参数（&lt;code&gt;:arg1&lt;/code&gt;, &lt;code&gt;:arg2&lt;/code&gt;...）后跟一个键值对的选项（options）。&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ActiveSupport&lt;/code&gt;中提供的一个叫做&lt;code&gt;extract_options!&lt;/code&gt;的牛逼方法使之成为可能。它的主要作用是提取给出的参数中的选项（options）。如果没有选项（options）它会返回一个空的 Hash。&lt;/p&gt;

&lt;p&gt;给你们秀一个列子！&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Use args with the splat operation to allow&lt;/span&gt;
&lt;span class="c1"&gt;# an unlimited number of parameters&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;my_method&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;extract_options!&lt;/span&gt;
  &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"Arguments:  &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;inspect&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"Options:    &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;inspect&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;my_method&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&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="c1"&gt;# Arguments:  [1, 2]&lt;/span&gt;
&lt;span class="c1"&gt;# Options:    {}&lt;/span&gt;

&lt;span class="n"&gt;my_method&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&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="ss"&gt;:a&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# Arguments:  [1, 2]&lt;/span&gt;
&lt;span class="c1"&gt;# Options:    {:a=&amp;gt;:b}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;extract_options!&lt;/code&gt;被大量用在 Rails 项目中，你肯定已经遇见它无数次了。它驱动（powers）了大多数你每天用到的的 Rails 功能，包括 ActionController filters，ActiveRecord validations 和 finder 方法。&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# ActionController filters&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyController&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationController&lt;/span&gt;
  &lt;span class="n"&gt;before_filter&lt;/span&gt; &lt;span class="ss"&gt;:my_method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:if&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:execute?&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:only&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="sx"&gt;%w(new)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="c1"&gt;# ActiveRecord validations and finders&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyModel&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&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="n"&gt;validates_presence_of&lt;/span&gt; &lt;span class="ss"&gt;:field&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:allow_blank&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;

  &lt;span class="o"&gt;...&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;my_find&lt;/span&gt;
    &lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:all&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:order&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:limit&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;10&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;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;extract_options!&lt;/code&gt; 可以让你从一个数组的参数中方便的提取出选项列（a list of options），这通常发生在方法调用时。
它不是 Ruby 的标准方法，但是它是 Rails 的核心扩展，并且你需要引用 &lt;code&gt;ActiveSupport&lt;/code&gt;才能使用。请注意它是一个“bang”方法，因此它会修改调用它的对象。&lt;/p&gt;</description>
      <author>shawnyu</author>
      <pubDate>Mon, 03 Jun 2013 13:47:00 +0800</pubDate>
      <link>https://ruby-china.org/topics/11449</link>
      <guid>https://ruby-china.org/topics/11449</guid>
    </item>
    <item>
      <title>HHKB 想玩键帽， 有没有什么推荐</title>
      <description>&lt;p&gt;某宝上找了，都不是很喜欢，大家还有什么推荐的吗。
来来来，有没有已经换过的 show 一下&lt;/p&gt;</description>
      <author>shawnyu</author>
      <pubDate>Fri, 24 May 2013 08:18:33 +0800</pubDate>
      <link>https://ruby-china.org/topics/11201</link>
      <guid>https://ruby-china.org/topics/11201</guid>
    </item>
    <item>
      <title>写给想买 Linode 但是没有信用卡的同学</title>
      <description>&lt;p&gt;最近无聊，看到财付通出了个虚拟运通卡的业务，可以国际支付。
于是就试试能不能支付一些比较常见的国外服务，试了一下 Linode
结果是可以的。哈哈 有兴趣的同学可以去试试，一下有几点注意事项。&lt;/p&gt;

&lt;p&gt;首先 支付的时候财付通的余额必须比需要支付的金额多个几十块钱，因为他要先多扣一些 应对 汇率变化，财付通和运通的结算时间不一样，中间有汇率差。&lt;/p&gt;

&lt;p&gt;然后 买了 Linode 之后，建议在每月一号之前自己去 Linode 后台充值下个月的费用，财付通的那个虚拟卡 还是不太稳定 会有支付失败的情况，不知道多次失败后，这张卡会不会被 linode 封掉&lt;/p&gt;</description>
      <author>shawnyu</author>
      <pubDate>Wed, 22 May 2013 09:33:58 +0800</pubDate>
      <link>https://ruby-china.org/topics/11141</link>
      <guid>https://ruby-china.org/topics/11141</guid>
    </item>
  </channel>
</rss>
