<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>chrisloong (王子龙)</title>
    <link>https://ruby-china.org/chrisloong</link>
    <description></description>
    <language>en-us</language>
    <item>
      <title>[深圳] 友好速搭 Ruby 工程师 2 名</title>
      <description>&lt;p&gt;&lt;a href="https://youhaosuda.com/" rel="nofollow" target="_blank" title=""&gt;友好速搭&lt;/a&gt;，是提供电商建站的 SaaS 应用。
2014 年 9 月正式上线，至今累计建站数量 1w+，近期刚完成天使轮融资。&lt;/p&gt;

&lt;p&gt;&lt;em&gt;为什么要做友好速搭？&lt;/em&gt;
初创团队之前一起兼职做项目，常帮客户做电商或门户站点。
这类开发工作，重复劳动太多，所以就想做个 SaaS 类产品，可以高效、快速满足建站需求，那时是 2011 年。
到了 2013 年，才有资金和时间去实现这个想法。&lt;/p&gt;

&lt;p&gt;&lt;em&gt;初创团队都有谁？&lt;/em&gt;
初创五个人，没啥明星。一部分来自网易，一部分来自 IT 企业。潮汕人居多，都很低调务实。&lt;/p&gt;

&lt;p&gt;&lt;em&gt;目前团队结构怎样？&lt;/em&gt;
研发有两个组：前端和后端，现在一共 7 人。其它部门，比如设计、产品等都齐全。总体人不多，但都很精悍。&lt;/p&gt;

&lt;p&gt;&lt;em&gt;公司管理层怎样？&lt;/em&gt;
这个阶段，没经理人、没 HR，没啥层级关系。基本上，没人有空管你。&lt;/p&gt;

&lt;p&gt;&lt;em&gt;当前产品的情况？&lt;/em&gt;
上线后，经过每两周的迭代，核心业务已经很成熟。
目前在电商产品领域，找不到比友好速搭便宜好用的。
像 wordpress、ecshop、magento、spree 等，呵呵~~好的地方都被我们剽窃来了。
当然，后续要做的事情还有很多，远比 Shopify 多，来了你就知道。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;产品技术栈&lt;/strong&gt;
产品核心业务，都是用 Ruby 开发，整体架构，都是微服务化的，所以没用 Rails 这种大而全的框架。
Ruby 相关技术栈：
Padrino/Sinatra + Sequel(PostgreSql) + MongoMapper(MongoDB) + Sidekiq(Redis)
除 Ruby 以外，我们还使用 Nodejs、Golang、Lua 等语言。&lt;/p&gt;

&lt;p&gt;薪资：
&lt;strong&gt;10K-20K&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;福利：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;保险齐全&lt;/li&gt;
&lt;li&gt;没打卡考勤&lt;/li&gt;
&lt;li&gt;人人有份的下午茶&lt;/li&gt;
&lt;li&gt;22:00 后打车报销&lt;/li&gt;
&lt;li&gt;每年两次涨薪机会&lt;/li&gt;
&lt;li&gt;每周健身&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;要求：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;学习或使用 Ruby 2 年+&lt;/li&gt;
&lt;li&gt;熟悉 SQL &lt;/li&gt;
&lt;li&gt;对 Web 产品有安全意识&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;加分项：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;有静态语言开发经验，比如 C#、Java 等&lt;/li&gt;
&lt;li&gt;熟悉 Linux 的基本操作&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;工作地点：深圳南山科技园
简历发送：hr@yeezon.com（请注明来自 RubyChina）&lt;/p&gt;</description>
      <author>chrisloong</author>
      <pubDate>Mon, 20 Jul 2015 12:05:19 +0800</pubDate>
      <link>https://ruby-china.org/topics/26567</link>
      <guid>https://ruby-china.org/topics/26567</guid>
    </item>
    <item>
      <title>建议大家尽早应用验证码</title>
      <description>&lt;p&gt;之前一直认为，验证码是 web 应用中，体验最糟糕的环节，登录或注册账号时，最烦去识别那些验证码。
所以在开发产品的时候，一直没把验证码列入开发计划。虽然知道有隐患，但觉得我们增速不会太快，没必要那么早注重安全环节。&lt;/p&gt;

&lt;p&gt;但是，最近审查产品的请求日志，发现有异样：
&lt;img src="https://l.ruby-china.com/photo/2015/2067108d97866305b8ef618afc3d1712.jpg" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;有很多请求，没有入口页面，上来就请求指定接口，并且请求 HEADER 信息一致。懂 web 的人肯定能看出，写个脚本，实现这种请求，非常容易。&lt;/p&gt;

&lt;p&gt;在去年，抢火车票，抢小米，使得国内爆破 web 接口的技术水平，迈上新台阶。抢东西倒还好，碰撞密码才是大危害。
如果没验证码，那等于是虚掩着大门，开发者可以轻松推开；加了验证码，至少还有把锁，想进去的人，需要一些技巧，才能开。&lt;/p&gt;

&lt;p&gt;这周在研究 CAPTCHA 实现方案时，发现这是 Ruby 的短板之一。
开源的方案中，大都是依赖 ImageMagick 这种第三方库去实现，验证码的图片很小，并不复杂，用个那么庞大的库，太浪费。&lt;/p&gt;

&lt;p&gt;后面考虑用其它语言，包括 Java、C#，这类语言生成个验证码图片，很轻松，我们团队也都熟悉语法，但是运行时太庞大。
最后，考虑到 Golang，它的标准库带了图像处理，而且安装非常方便，解压下就能用，虽然不熟语法，但有静态语言经验，学起来不难，而且 Github 上有相关代码可供参考：&lt;a href="https://github.com/dchest/captcha" rel="nofollow" target="_blank" title=""&gt;https://github.com/dchest/captcha&lt;/a&gt;。&lt;/p&gt;

&lt;p&gt;在实现图片验证码前，仔细看过乌云的两篇文章：&lt;a href="http://drops.wooyun.org/tips/4550" rel="nofollow" target="_blank" title=""&gt;初探验证码识别&lt;/a&gt;，&lt;a href="http://drops.wooyun.org/tips/141" rel="nofollow" target="_blank" title=""&gt;常见验证码的弱点与验证码识别 &lt;/a&gt;。&lt;/p&gt;

&lt;p&gt;不得不承认，国内的智能破解验证码水平，已经很高。所以在生成验证码图片时，不要太天真。
我们用的策略，就是尽可能随机，包括：背景色和字体色，字体倾斜角度，验证码位数等。&lt;/p&gt;

&lt;p&gt;为了不影响常规体验，我们也是在登录失败达到一定次数后，强制用户输入验证码，这个次数统计，我们是放在 Redis 里面做，全局的。有些产品是把这个计数器，存在 Cookie 里，Cookie 是客户端传来的，不可信。&lt;/p&gt;

&lt;p&gt;我们已经将这套方案上线：
&lt;img src="https://l.ruby-china.com/photo/2015/0f8deea269b07e98ce4115a9091d9e74.png" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;简单说下我们的实现：&lt;/strong&gt;
1) 提供独立的域名//captcha.ibanquan.com，来呈现验证码，这个域名的后端是 Golang 进程；
2) Ruby 中通过 Redis 记录一个账号的登录失败次数，一旦超过指定值，那么登录时必须带合法验证码；
3) 需要用到验证码时，前端发起请求：//captcha.ibanquan.com/?callback=funcname（这里用 JSONP 避免跨域问题）返回：&lt;/p&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;func&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nf"&gt;func&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;8a362d95a1d5289b3429be8b936c9d31&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;path&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/image/8a362d95a1d5289b3429be8b936c9d31.png&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;4) 前端把上面返回的图片路径，放到域名后面：
//captcha.ibanquan.com/image/8a362d95a1d5289b3429be8b936c9d31.png
作为&lt;img&gt;标签的 src 就可以呈现验证码图片，再把 id 的值，隐藏在表单中；
5) 表单提交时，把用户输入的验证码，以及隐藏的验证码 ID 提交给 Ruby 后端；
6) Ruby 里面，通过验证码的 ID 从 Redis 取出对应 Value，和用户输入的验证码匹配。&lt;/p&gt;

&lt;p&gt;随手点开社区的酷站，发现很多产品，要么没 CAPTCHA 机制，要么图片验证码太简单。
尤其是我们社区，都还没有 CAPTCHA 机制。其实开发者社区账号，更有价值，一旦开发者账号攻陷后，域名的账号、主机账号等都可以去碰撞，一旦得手，可以为所欲为。&lt;/p&gt;

&lt;p&gt;最后，推荐一位国内安全领域牛人，&lt;a href="http://weibo.com/ringzero" rel="nofollow" target="_blank" title=""&gt;微博 ringzero&lt;/a&gt;，乌云里核心白帽子&lt;a href="http://www.wooyun.org/whitehats/%E7%8C%AA%E7%8C%AA%E4%BE%A0" rel="nofollow" target="_blank" title=""&gt;猪猪侠&lt;/a&gt;。&lt;/p&gt;</description>
      <author>chrisloong</author>
      <pubDate>Thu, 22 Jan 2015 12:02:26 +0800</pubDate>
      <link>https://ruby-china.org/topics/23877</link>
      <guid>https://ruby-china.org/topics/23877</guid>
    </item>
    <item>
      <title>访问 https://3wcoffee.com/ 返回的是 rubychina</title>
      <description>&lt;p&gt;Google 搜索 rubychina 内容时发现的：
&lt;img src="https://l.ruby-china.com/photo/2015/9efcc1b0bf389f303178dfe7726b02f1.png" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;开始还以为域名被劫持。
但是发现，3wcoffee.com 和 ruby-china.org 解析出来的 IP 是同一个，而且都是用 nginx。&lt;/p&gt;

&lt;p&gt;难道两个站部署在同台主机？&lt;/p&gt;</description>
      <author>chrisloong</author>
      <pubDate>Mon, 19 Jan 2015 20:48:30 +0800</pubDate>
      <link>https://ruby-china.org/topics/23821</link>
      <guid>https://ruby-china.org/topics/23821</guid>
    </item>
    <item>
      <title>如何科学使用青云的秒级计费</title>
      <description>&lt;p&gt;在今年北京的 rubyconf 上，&lt;a href="/fsword" class="user-mention" title="@fsword"&gt;&lt;i&gt;@&lt;/i&gt;fsword&lt;/a&gt;分享过基于青云 API 的作品&lt;a href="https://github.com/fsword/larrow-runner" rel="nofollow" target="_blank" title=""&gt;larrow-runner&lt;/a&gt;，应该是第一个 ruby-client 实现。&lt;/p&gt;

&lt;p&gt;下面的内容，之前在&lt;a href="https://www.qingcloud.com/workshop/" rel="nofollow" target="_blank" title=""&gt;青云深圳沙龙&lt;/a&gt;分享过，可能社区里没人去，整理成文字版再来分享下。&lt;/p&gt;

&lt;p&gt;先看看&lt;a href="https://youhaosuda.com/" rel="nofollow" target="_blank" title=""&gt;友好速搭&lt;/a&gt;的部署架构：
&lt;img src="https://l.ruby-china.com/photo/2014/33e96e6ac63391c122169f2446511242.png" title="" alt=""&gt;
一共部署了三十多台主机，是很常规的 web 应用三层架构。&lt;/p&gt;

&lt;p&gt;系统动态请求统计图：
下午：
&lt;img src="https://l.ruby-china.com/photo/2014/4c61ad9bb014153f4b06e77885718c94.png" title="" alt=""&gt;
晚上：
&lt;img src="https://l.ruby-china.com/photo/2014/8b5406c50aac6faa05b31f8d27888424.png" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;下午和晚上的请求数，差距很大，午夜以后，基本没请求。
对于大部分应用，应该都有这种忙闲的周期。在闲的时候，保持最小可用就可以，没必要浪费。
既然青云将 IaaS 做成水电一样的资源，那也要学会节约。我们目前节约的方式，就是定时开关机。
动机很单纯： &lt;strong&gt;一台 2 核 4G 的主机，运行时 0.45 元/小时，关机时 0.032 元/小时。&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;关机的时候，要避免中断当前正在处理的请求，所以要先从 nginx 下手。在 nginx 里面设置定时任务，执行 ruby 脚本，修改 upstream 配置，移除那些要关机的主机 IP，再通过&lt;code&gt;service nginx reload&lt;/code&gt;更新配置。reload 是用&lt;a href="http://wiki.nginx.org/CommandLine#Stopping_or_Restarting_Nginx" rel="nofollow" target="_blank" title=""&gt;HUP 信号&lt;/a&gt;，不会对正在处理的请求造成影响：&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Configuration reload 
Start the new worker processes with a new configuration 
Gracefully shutdown the old worker processes&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;之后等 20 分钟，主要是等要关机的 unicorn，将请求处理完。之后 crontab 执行 ruby 脚本，通过 API 关机，可以直接用&lt;a href="https://github.com/fsword/larrow-qingcloud/blob/master/lib/larrow/qingcloud/connection.rb" rel="nofollow" target="_blank" title=""&gt;larrow-qingcloud 中的 class&lt;/a&gt;：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;conn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Connection&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="s1"&gt;'your_key'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'your_secret'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'zone_id'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# 调用关机接口&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;get&lt;/span&gt; &lt;span class="s1"&gt;'StopInstances'&lt;/span&gt;&lt;span class="p"&gt;,{&lt;/span&gt; &lt;span class="s1"&gt;'instances.1'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'i-xxxx'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'instances.2'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'i-xxxxx'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'zone'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'gd1'&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;注意，执行调用接口的主机，时间必须同步。&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;定时开机的话，顺序正好反过来。先通过 API 启动主机，主机中的 unicorn 配置成开机启动。然后等一段时间，等主机和 unicorn 启动完成，就更改 nginx 的 upstream 配置。&lt;/p&gt;

&lt;p&gt;通过这种方式，全年可以节约 8% 的开支。有些包年月的 IaaS 服务商，可以打折，同样能节省开支。但是，节省开支，并非我们终极目的。&lt;/p&gt;

&lt;p&gt;友好速搭作为服务商，商家做活动，不会通知我们做准备。商家在活动期间，系统负载不够，转化率降低，那就出大事了。&lt;/p&gt;

&lt;p&gt;所以，我们正在尝试基于青云的 API，把这个节约体系，做的更智能。目前这个阶段，系统的负载瓶颈，主要是在中间的 Rack App 层，这个层面的主机数量也最多。我们要实现应用主机资源池，设定应用主机数量的上下限，通过算法，分析判断负载趋势，再通过工程，部署或销毁主机。&lt;/p&gt;</description>
      <author>chrisloong</author>
      <pubDate>Wed, 03 Dec 2014 23:17:44 +0800</pubDate>
      <link>https://ruby-china.org/topics/23012</link>
      <guid>https://ruby-china.org/topics/23012</guid>
    </item>
    <item>
      <title>微软终于迈出这一步</title>
      <description>&lt;p&gt;微软最近&lt;a href="http://news.microsoft.com/2014/11/12/microsoft-takes-net-open-source-and-cross-platform-adds-new-development-capabilities-with-visual-studio-2015-net-2015-and-visual-studio-online/" rel="nofollow" target="_blank" title=""&gt;开源的动作&lt;/a&gt;很大：
全面推动.NET 的跨平台（Windows、Linux、MacOS）发展；
.NET 全面开源，包括 ASP.NET, .NET 编译器，.NET 核心库，&lt;a href="https://github.com/Microsoft/dotnet" rel="nofollow" target="_blank" title=""&gt;戳 github&lt;/a&gt;；
还成立了一个&lt;a href="http://www.dotnetfoundation.org/projects" rel="nofollow" target="_blank" title=""&gt;.NET 基金会&lt;/a&gt;。&lt;/p&gt;

&lt;p&gt;遥想当年，用着全套的盗版工作站，码着 C#。
看.NET Core 源码，要开个 Reflector 这种反编译器，后来这个工具竟然要收费。微软产品的代码，写的真心漂亮。&lt;/p&gt;

&lt;p&gt;还有那个 Mono，当时一堆人担心，微软会因专利保护为由，通过起诉来搞死这个项目。
所以要想给 Mono 贡献代码，前提是绝对不能看.NET 实现代码，防止写出和.NET 类似的代码。
后来，Mono 团队还争取到微软的授权，消除社区对 Mono 合法性的担心。&lt;/p&gt;

&lt;p&gt;时代变化了，Mac 的设备到处都是，云计算风起云涌，推动.NET 跨平台，微软终于舍得割肉求生。&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Your Potential. Our Passion.&lt;/code&gt;
也许，以后有机会，在 Linux 和 Mac 上，释放微软技术的光彩。&lt;/p&gt;</description>
      <author>chrisloong</author>
      <pubDate>Thu, 13 Nov 2014 11:31:51 +0800</pubDate>
      <link>https://ruby-china.org/topics/22642</link>
      <guid>https://ruby-china.org/topics/22642</guid>
    </item>
    <item>
      <title>[深圳] QingCloud 实践课堂 第一课</title>
      <description>&lt;p&gt;云计算确实正在改变研发工作。
作为开发者，在评估语言、数据库、操作系统这些方面以外，更需要对云服务进行评估：
IaaS 用什么？阿里云？AWS？......
存储用什么？七牛？又拍？......
IM 服务用什么？环信？融云？......
......&lt;/p&gt;

&lt;p&gt;云服务的租用特点，可以以极低的成本，快速构建 niubility 的应用。
现在的创业产品，可能都会优先考虑云服务，其实互联网里的创业公司去用云，还远远不够。
可能在若干年后，金融、电信等传统行业里面那些系统，都会构建在云上。
正处在云变革的过渡期，想想就有点小激动呀&lt;img title=":alien:" alt="👽" src="https://twemoji.ruby-china.com/2/svg/1f47d.svg" class="twemoji"&gt;。&lt;/p&gt;

&lt;p&gt;之前在深圳南山的 3w 咖啡，参加过两次云计算相关的聚会：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; 去年底的&lt;a href="http://www.ecug.org/" rel="nofollow" target="_blank" title=""&gt;实效云计算用户组&lt;/a&gt;会议&lt;/li&gt;
&lt;li&gt; 今年初的&lt;a href="http://aws.amazon.com/cn/" rel="nofollow" target="_blank" title=""&gt;aws 中国&lt;/a&gt;研讨会&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;上面两次参会的收获都挺多。这次青云的线下聚会，也推荐给大家。有兴趣的可以&lt;a href="https://www.qingcloud.com/workshop/" rel="nofollow" target="_blank" title=""&gt;免费报名参加&lt;/a&gt;。&lt;/p&gt;

&lt;p&gt;在去年，我们花了两个月时间，评估国内各家 IaaS 服务，
看上 QingCloud 的秒级计费以及 SDN，才决定把友好速搭部署在上面。
至今部署中小型主机总计 30 多台，真心点赞。这次聚会也会分享下 QingCloud 网络层的使用经验。&lt;/p&gt;

&lt;p&gt;现在像粉 Ruby 一样，粉 QingCloud &lt;img title=":heart:" alt="❤" src="https://twemoji.ruby-china.com/2/svg/2764.svg" class="twemoji"&gt;。
上次去北京参加 RubyConfChina，也顺便去 QingCloud 参观了下，里面的人和办公环境一样，都特有范&lt;img title=":revolving_hearts:" alt="💞" src="https://twemoji.ruby-china.com/2/svg/1f49e.svg" class="twemoji"&gt;。&lt;/p&gt;</description>
      <author>chrisloong</author>
      <pubDate>Tue, 11 Nov 2014 00:56:54 +0800</pubDate>
      <link>https://ruby-china.org/topics/22597</link>
      <guid>https://ruby-china.org/topics/22597</guid>
    </item>
    <item>
      <title>域名免备案的解决方法</title>
      <description>&lt;p&gt;对于建站方面的 SaaS 产品，绑定域名是用户的基本需求，所以是一项基础功能。
在技术层面，本不是个问题。但是，由于国内的政策限制，反而成为一个麻烦的问题。&lt;/p&gt;

&lt;p&gt;之前在论坛&lt;a href="https://ruby-china.org/topics/15289" title=""&gt;有个帖子&lt;/a&gt;提到了一种方案，挺好的。
就是在域名的 DNS 中，用 CNAME 解析，通过境外的服务器做反向代理。
使用 CNAME 的另外一个好处，还可以屏蔽 IP 变化，万一 IP 被屏蔽，再换个就好，CNAME 的值可以保持不变。&lt;/p&gt;

&lt;p&gt;但是这种方案的最大弊端，就是性能：
*CNAME 导致访问域名时，需要做两次解析，才能获得实际的 IP。
*请求数据，需要经过两层 web server：境外 nginx &amp;lt;-&amp;gt; 大陆 nginx &amp;lt;-&amp;gt; 大陆 app server。&lt;/p&gt;

&lt;p&gt;最初我们在产品中，没有强制要求用户备案。
但是，最近已经接到通知，服务商需要配合有关部门，强制进行域名备案审查。
长远来看，只要域名解析到大陆境内 IP，都是需要备案的。
此外，国内的通管局要求，对部分国别域名（比如.tt 和.la 等），不允许备案和使用。&lt;/p&gt;

&lt;p&gt;所以，不得已，还是要想办法解决这个政策问题。&lt;/p&gt;

&lt;p&gt;我们的解决方案，是依赖&lt;a href="https://qingcloud.com" rel="nofollow" target="_blank" title=""&gt;青云&lt;/a&gt;构建的。
用过青云的都知道，它的网络层做的非常好。网络的计费方式，也很灵活，可以固定带宽，也可以按流量。
它有个非常重要的功能，叫&lt;a href="https://docs.qingcloud.com/guide/gre.html#id2" rel="nofollow" target="_blank" title=""&gt;三层 GRE 隧道&lt;/a&gt;，可以实现任意两个路由网络互联。&lt;/p&gt;

&lt;p&gt;碰巧，最近青云开放了亚太区，它的机房网络，包括国际和大陆 BGP 两大类，所以国内访问速度非常好。
后面我们是怎么做的，想必大家应该猜到了。&lt;/p&gt;

&lt;p&gt;就是在亚太区部署一台 web server，通过隧道技术直连国内的 app server：境外 nginx &amp;lt;-&amp;gt; 大陆 app server。&lt;/p&gt;

&lt;p&gt;看看网速，基本和大陆的机房网络差不多：
&lt;img src="https://l.ruby-china.com/photo/2014/11d81ca09484c4696579ec05d9ac817a.jpg" title="" alt=""&gt;
成本是一天 6 元，网络按流量计费。&lt;/p&gt;

&lt;p&gt;另外，做个宣传，我们通过这种网络方案，实现了小型 CDN，便宜且灵活，所有静态资源，都会分发到南北两个机房：
&lt;img src="https://l.ruby-china.com/photo/2014/9cc644f554092f88f7aa26f0f18ed7d4.jpg" title="" alt=""&gt;&lt;/p&gt;</description>
      <author>chrisloong</author>
      <pubDate>Wed, 05 Nov 2014 21:27:50 +0800</pubDate>
      <link>https://ruby-china.org/topics/22510</link>
      <guid>https://ruby-china.org/topics/22510</guid>
    </item>
    <item>
      <title>新的 Ruby app server：Raptor</title>
      <description>&lt;p&gt;最近 ruby 社区冒出一款新的 app server，叫&lt;a href="http://www.rubyraptor.org/" rel="nofollow" target="_blank" title=""&gt;Raptor&lt;/a&gt;，宣称性能非常好。&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.rubyinside.com/raptor-a-new-ruby-web-server-for-faster-app-deployment-6168.html" rel="nofollow" target="_blank" title=""&gt;RubyInside 里有一篇介绍&lt;/a&gt;，介绍了 Raptor 部分技术实现：采用了 node 的 http-parser；应用了 zero-copy、concurrent、evented 架构；此外还实现了内置缓存，无需依赖 redis 或 memcached。&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.akitaonrails.com/2014/10/19/the-new-kid-on-the-block-for-ruby-servers-raptor#.VEdVfvmSxb8" rel="nofollow" target="_blank" title=""&gt;Fabio Akita 发了一篇性能测试&lt;/a&gt;，下面是性能结果截图：
如果一直是这个性能，不仅能蹂躏其它 ruby app server，都可以完爆 node 啦：
&lt;img src="https://l.ruby-china.com/photo/2014/b3226d7c8e46ed5ac8bec06e82f3ee65.png" title="" alt=""&gt;
不过，稍微增加一点数据，就没啥惊喜：
&lt;img src="https://l.ruby-china.com/photo/2014/e53c9e9bd68b26e8f35da31fd4825adc.png" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;看了以后疑问很多，纯 ruby 实现么？依赖 rack 么？fork 和 thread 一起用么？......
不过它要在 11 月 25 号才会在 github 公布代码&lt;img title=":heartbeat:" alt="💓" src="https://twemoji.ruby-china.com/2/svg/1f493.svg" class="twemoji"&gt;。
这年代技术社区都搞饥饿营销了&lt;img title=":broken_heart:" alt="💔" src="https://twemoji.ruby-china.com/2/svg/1f494.svg" class="twemoji"&gt;。&lt;/p&gt;</description>
      <author>chrisloong</author>
      <pubDate>Wed, 22 Oct 2014 15:35:56 +0800</pubDate>
      <link>https://ruby-china.org/topics/22191</link>
      <guid>https://ruby-china.org/topics/22191</guid>
    </item>
    <item>
      <title>SSLv3 的 POODLE 漏洞</title>
      <description>&lt;p&gt;Google 的员工在 SSLv3 的协议中，发现了一个漏洞，命名为&lt;a href="https://www.imperialviolet.org/2014/10/14/poodle.html" rel="nofollow" target="_blank" title=""&gt;POODLE&lt;/a&gt;。
可以利用这个漏洞，窃取用户经 HTTPS 传输的 Cookie 内容。这个漏洞是 SSLv3 的协议层缺陷导致，所以没有补丁包。&lt;/p&gt;

&lt;p&gt;不过危害没有 Heartbleed 和 Shellshock 大。防患未然的话，就在 web server 中禁用 SSLv3。&lt;/p&gt;

&lt;p&gt;在 Nginx 中的关闭 SSLv3 的配置：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;#before: ssl_protocols SSLv3 TLSv1.2 TLSv1.1 TLSv1;&lt;/span&gt;
&lt;span class="n"&gt;ssl_protocols&lt;/span&gt; &lt;span class="no"&gt;TLSv1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="no"&gt;TLSv1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="no"&gt;TLSv1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;检测方法：&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;openssl s_client &lt;span class="nt"&gt;-connect&lt;/span&gt; ruby-china.org:443 &lt;span class="nt"&gt;-ssl3&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;启用 SSLv3 的结果：
&lt;img src="https://l.ruby-china.com/photo/2014/26d64934300444e365bbab1b56ca851a.png" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;禁用 SSLv3 以后握手通信失败：
&lt;img src="https://l.ruby-china.com/photo/2014/18daa5bce7462b4c444ed10ab5df9275.png" title="" alt=""&gt;&lt;/p&gt;</description>
      <author>chrisloong</author>
      <pubDate>Wed, 15 Oct 2014 22:47:07 +0800</pubDate>
      <link>https://ruby-china.org/topics/22064</link>
      <guid>https://ruby-china.org/topics/22064</guid>
    </item>
    <item>
      <title>友好速搭的技术栈 for Ruby off Rails</title>
      <description>&lt;p&gt;&lt;a href="https://youhaosuda.com/" rel="nofollow" target="_blank" title=""&gt;友好速搭&lt;/a&gt;是一款 SaaS 电商建站工具，目前国内的电商建站市场，用 &lt;a href="/saberma" class="user-mention" title="@saberma"&gt;&lt;i&gt;@&lt;/i&gt;saberma&lt;/a&gt; 的话说，就是“比较混乱”。那么，电商建站哪家强呢？&lt;img title=":smile:" alt="😄" src="https://twemoji.ruby-china.com/2/svg/1f604.svg" class="twemoji"&gt;&lt;/p&gt;
&lt;h2 id="友好速搭创建的网店性能，大体是这样的："&gt;友好速搭创建的网店性能，大体是这样的：&lt;/h2&gt;
&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2014/f34cb8dfc01a99e20cb0e54ce84701de.png" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;我们团队是今年 3 月份，才聚到深圳一起开发，在 6 月份上线 beta 版，改进完善了 3 个月，终于在 9 月份开放使用。
产品中大量使用开源技术，把开源的代码拿走，剩下都是难看的业务代码，比如：经常过百行的 ruby 函数 :neckbeard:，300 多行的 sql &lt;img title=":cold_sweat:" alt="😰" src="https://twemoji.ruby-china.com/2/svg/1f630.svg" class="twemoji"&gt;，嵌套很多层的 js callback &lt;img title=":broken_heart:" alt="💔" src="https://twemoji.ruby-china.com/2/svg/1f494.svg" class="twemoji"&gt;。&lt;/p&gt;

&lt;p&gt;还是来分享些轻松的内容，对 ruby off rails 的开发有些帮助 &lt;img title=":sparkles:" alt="✨" src="https://twemoji.ruby-china.com/2/svg/2728.svg" class="twemoji"&gt;。&lt;/p&gt;
&lt;h2 id="编程语言:"&gt;编程语言：&lt;/h2&gt;
&lt;p&gt;主要是 ruby，javascript 以及 sql。&lt;/p&gt;
&lt;h2 id="前端框架："&gt;前端框架：&lt;/h2&gt;
&lt;p&gt;前端最重的库，就是 angularjs，店铺后台的 UI，都是基于 ng 实现。初期搭脚手架多费些时间，后面在脚手架基础上的开发，非常方便，我们的前端小组正准备一些内容，将来和大家分享下。&lt;/p&gt;
&lt;h2 id="Web框架:"&gt;Web 框架：&lt;/h2&gt;
&lt;p&gt;以 padrino 为主，sinatra 和 express(nodejs) 为辅。&lt;/p&gt;

&lt;p&gt;用 sinatra 实现一些轻量 app，比如这个&lt;a href="http://shop.upicart.com/pages/G000001" rel="nofollow" target="_blank" title=""&gt;预约功能&lt;/a&gt;，以及&lt;a href="http://asset.ibanquan.com/image/5402adc74321305966000002/%E4%BA%A7%E5%93%81%E5%9B%BE.jpg?1409461703" rel="nofollow" target="_blank" title=""&gt;资源应用&lt;/a&gt;。&lt;/p&gt;

&lt;p&gt;用 express 实现一些涉及外部网络请求的功能，比如&lt;a href="http://api.ibanquan.com/shot?url=http://baidu.com" rel="nofollow" target="_blank" title=""&gt;网页截图（返回 base64）&lt;/a&gt;，&lt;a href="http://api.ibanquan.com/dns?url=http://baidu.com" rel="nofollow" target="_blank" title=""&gt;
dns 查询&lt;/a&gt;等。&lt;/p&gt;

&lt;p&gt;padrino 是基于 sinatra 开发的，DSL 的写法很直白，开发 api 和全端应用都很方便。
在店铺的后台，后端提供的都是 api，在店铺前台 (liquid)，以及友好速搭本身 (haml)，就是全端的应用。
在友好速搭的&lt;a href="http://docs.youhaosuda.com" rel="nofollow" target="_blank" title=""&gt;子应用&lt;/a&gt;，就是用 padrino 的 mount 加载机制，可以实现代码，甚至 view 的复用。&lt;/p&gt;
&lt;h2 id="后台任务："&gt;后台任务：&lt;/h2&gt;
&lt;p&gt;友好速搭目前有 40 个后台任务，估计后面还会继续增加。&lt;/p&gt;

&lt;p&gt;之前用的是 resque，它是用进程 fork 的方式执行任务，但是内存消耗太厉害，如果要处理的任务比较多，2G 的内存很快耗尽，也尝试优化 resque 的加载项，减少内存占用，但效果不理想。&lt;/p&gt;

&lt;p&gt;在 beta 之后，就用了 sidekiq，它是用线程的方式执行任务，内存方面很友好，再也不用担心后台任务会死掉。
resque 和 sidekiq 都是基于 redis 实现的，两者替换很方便。&lt;/p&gt;

&lt;hr&gt;

&lt;p&gt;数据存储涉及三种类型的数据：关系型，文档型，缓存型。下面分别介绍下：&lt;/p&gt;
&lt;h2 id="PostgreSQL"&gt;PostgreSQL&lt;/h2&gt;
&lt;p&gt;部署的是主从集群，存储关系型数据。&lt;/p&gt;

&lt;p&gt;用&lt;a href="https://github.com/jeremyevans/sequel" rel="nofollow" target="_blank" title=""&gt;sequel&lt;/a&gt;操作，连接配置示例：&lt;/p&gt;

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

&lt;p&gt;sequel 是 github 上少见的零 issue 项目，品质可见。
它是一款小巧灵活的 ORM，即可用 ORM 式的面向对象写法，也可以很方便的执行 raw sql，支持多种关系型数据库，其中对 postgresql 支持最好。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;提醒：&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;由于主从之间的数据同步是异步，不是强同步的，所以对需要数据同步的场景，不要把 sequel 配置成读写分离。&lt;/li&gt;
&lt;li&gt;在 unicorn 的 before_fork 中，将 sequel 的连接断开，在 after_fork 中，不需要写重连代码，sequel 会自动重连。&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;MongoDB&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;部署了一个 replica set，存储所有文档型数据（例如主题文件，图片等），此外还存储 rack 的 session 数据。
用&lt;a href="https://github.com/mongomapper/mongomapper" rel="nofollow" target="_blank" title=""&gt;mongomapper&lt;/a&gt;操作，连接配置示例：
&lt;img src="https://l.ruby-china.com/photo/2014/977eea3c91439667d9c96398f545a120.png" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;在 ODM 的选择上，最初是用 mongomatic 来操作，发现太简单，业务代码不好写，后来又看了 mongoid，太强大了，没必要。
最后采用了 mongomapper，它正好介于前两者之间，用来操作文档型 model 很方便，但如果用于 model 之间较多关联的场景（比如论坛），就不如 mongoid 方便。
&lt;strong&gt;提醒：&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;replica set 中的节点，数据同步也是异步的，同 postgresql，需要数据同步的场景，不要开启 read_secondary。&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Redis&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;单机部署，Redis 的&lt;a href="http://antirez.com/news/79" rel="nofollow" target="_blank" title=""&gt;集群功能&lt;/a&gt;刚推出，twitter 的&lt;a href="https://github.com/twitter/twemproxy" rel="nofollow" target="_blank" title=""&gt;twemproxy&lt;/a&gt;在代理层面，也提供 redis 的集群支持。正在评估 redis 的集群方式，准备部署个集群，因为 Redis 太重要，要力保它的可靠性。
目前主要用在以下三方面：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;业务数据的缓存
Web 类型应用，通常都是读很多，为确保电商前台的浏览体验，我们把大部分的业务数据，都存在 redis，在后台发生数据变动时，去同步更新。由于业务对象比较多，我们封装了缓存的 model 层，redis 的读写操作逻辑，都在内部完成，可以叫 Object Redis-Cache Mapping &lt;img title=":yum:" alt="😋" src="https://twemoji.ruby-china.com/2/svg/1f60b.svg" class="twemoji"&gt;。&lt;/li&gt;
&lt;li&gt;后台任务队列
之前用的是 resque，后来换成了 sidekiq，上面已经说了。&lt;/li&gt;
&lt;li&gt;分布式锁
主要是用来解决重复提交的问题，所以我们的实现很简单，也有&lt;a href="http://redis.io/topics/distlock" rel="nofollow" target="_blank" title=""&gt;更强大的实现&lt;/a&gt;
，可以解决更复杂的问题。&lt;/li&gt;
&lt;/ol&gt;

&lt;hr&gt;

&lt;p&gt;好了，脱了外套给大伙 show 完内衣，想了解更多？那就&lt;a href="https://youhaosuda.com/jobs" rel="nofollow" target="_blank" title=""&gt;入伙吧&lt;/a&gt;。&lt;/p&gt;

&lt;p&gt;最后，我们的开发者文档正在准备，想用友好速搭给客户开发网站的，需要等一段时间。&lt;/p&gt;</description>
      <author>chrisloong</author>
      <pubDate>Fri, 10 Oct 2014 17:39:51 +0800</pubDate>
      <link>https://ruby-china.org/topics/21970</link>
      <guid>https://ruby-china.org/topics/21970</guid>
    </item>
    <item>
      <title>从 rack-cache 到 varnish，200 倍性能提升达成！</title>
      <description>&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2014/d5015bd917808a9d4d2f8513982a0c2f.png" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;使用 ruby 开发 web 应用之所以高效，ruby 语法友好是一方面，另外一方面就是社区资源，涉及 web 应用场景的 gem 有很多。&lt;/p&gt;

&lt;p&gt;比如连 HTTP 加速器&lt;a href="http://en.wikipedia.org/wiki/Web_accelerator" rel="nofollow" target="_blank" title=""&gt;HTTP accelerator&lt;/a&gt;这种产品，都有纯 ruby 的实现：&lt;a href="https://github.com/rtomayko/rack-cache" rel="nofollow" target="_blank" title=""&gt;rack-cache&lt;/a&gt;。&lt;/p&gt;

&lt;p&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;'rack/cache'&lt;/span&gt;

&lt;span class="n"&gt;use&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;Cache&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;:verbose&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;:metastore&lt;/span&gt;   &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'file:/var/cache/rack/meta'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;:entitystore&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'file:/var/cache/rack/body'&lt;/span&gt;

&lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;我们的产品中，所有上传图片，都是存储在 MongoDB，而且通过&lt;a href="https://github.com/akdubya/rack-thumb" rel="nofollow" target="_blank" title=""&gt;rack-thumb&lt;/a&gt;实现图片缩放功能，通过 url 中指定图片尺寸，就能获取对应尺寸的图片。&lt;/p&gt;

&lt;p&gt;通过 HTTP 加速器，一种尺寸的图片，只需要生成一次，以后就从加速器的缓存中返回。&lt;/p&gt;

&lt;p&gt;最初就是用简单的 rack-cache 来做 HTTP 加速，但很快就遇到瓶颈，&lt;/p&gt;

&lt;p&gt;首先是性能，使用 rack-cache 后，配置为硬盘存储，测试响应性能，仅提升 20%。将 rack-cache 的存储改为 heap 后，性能提升也不显著。&lt;/p&gt;

&lt;p&gt;其次是拓展，rack-cache 是 rack 的插件，必须跟着 app 走。部署多几台 app，那它们之间的缓存是无法共享的，除非将存储改为 Memcached，但是用内存来缓存静态资源，太奢侈！&lt;/p&gt;

&lt;p&gt;所以总体来说，rack-cache 性价比太低，在有规模的生产环境中用，很不划算。&lt;/p&gt;

&lt;p&gt;所以不得已，还是要跳出 ruby 的圈子，找业内通用的方案，首选肯定是名气最大的&lt;a href="https://www.varnish-cache.org/" rel="nofollow" target="_blank" title=""&gt;varnish&lt;/a&gt;。
安装的是最新版 v4.0，官方提供 CentOS 安装的 rpm，所以安装很方便。&lt;/p&gt;

&lt;p&gt;把存储配置为硬盘，测试响应性能，能带来 200 倍以上的性能提升，一个词来形容当时心情的话，那就是：惊喜。
通过对 vcl 的配置&lt;a href="https://www.varnish-cache.org/docs/trunk/users-guide/vcl-backends.html" rel="nofollow" target="_blank" title=""&gt;vcl-backends&lt;/a&gt;，支持多个 app 也很方便。&lt;/p&gt;

&lt;p&gt;不过 varnish 的在转发 request 到 app 时，只有两种策略：循环和随机，没有类似 nginx 的负载均衡功能，不过这点缺失影响不大。&lt;/p&gt;

&lt;p&gt;虽然 rack-cache 比较弱，但它有个优势：容易用。如果是小项目，可以先用，等遇到性能瓶颈，再升级方案，用 varnish。&lt;/p&gt;

&lt;p&gt;我们的 SaaS 产品友好速搭在内测期，用户数量是固定的，用了 4 台 rack-cache。之后上线开放，发现性能跟不上，很快就换成 varnish，配合一台处理缩略图的 app。
部署 varnish 的那台机器，4000req/s 的性能，应付 1000rpm 以内的压力，绰绰有余，此外，cpu 和内存也都很稳定，果然名不虚传。&lt;/p&gt;</description>
      <author>chrisloong</author>
      <pubDate>Thu, 04 Sep 2014 19:11:29 +0800</pubDate>
      <link>https://ruby-china.org/topics/21390</link>
      <guid>https://ruby-china.org/topics/21390</guid>
    </item>
    <item>
      <title>PostgreSQL 的异步操作接口，以及 Ruby 中对应实现</title>
      <description>&lt;p&gt;我们团队一直在用 padrino 框架做开发，数据库操作，是用 sequel 这个轻量级库。
在开发中遇到数据 IO 的瓶颈，就想把数据库操作改为异步的，来提升代码性能。&lt;/p&gt;

&lt;p&gt;原以为 sequel 默认都是同步方式来操作数据库，但看了源码和说明，才发现 sequel 默认都是在用异步接口：
&lt;img src="https://l.ruby-china.com/photo/2014/1ba010a00e62c1fd23a99274176b6f55.png" title="" alt=""&gt;
&lt;img src="https://l.ruby-china.com/photo/2014/74805e8810f7c40bdcd7459e1b83475e.png" title="" alt=""&gt;
那为啥在使用过程中，一点都没感到异步的快感？&lt;/p&gt;

&lt;p&gt;于是就扒了一下 sequel 依赖的那些库：
&lt;img src="https://l.ruby-china.com/photo/2014/0458373e7f3cad49d4f39b85bbff847f.png" title="" alt=""&gt;
libpq，是 Pg 官方提供的操作接口代码库，C 写的；
ruby-pg，是用 ruby 和 C 写的 gem，实现对 libpq 的拓展，从而实现 ruby 对 Pg 的操作接口；
sequel，是 ruby 写的轻量级 ORM，它实现了数据库连接管理，以及 sql 的生成。涉及数据库接口方面工作，都是依赖 ruby-pg。&lt;/p&gt;

&lt;p&gt;libpq 本身，确实支持同步和异步两种操作方式：
&lt;a href="http://www.postgresql.org/docs/current/static/libpq-async.html" rel="nofollow" target="_blank"&gt;http://www.postgresql.org/docs/current/static/libpq-async.html&lt;/a&gt;
一个数据库连接，就是一条 TCP 连接，libpq 是客户端，Pg 是服务端，
同步方式，libpq 将指令发送到 Pg，Pg 指令执行完成，将结果发回，libpq 收到结果后，才继续执行下面的代码：
&lt;img src="https://l.ruby-china.com/photo/2014/7f98348411b5accb85c35410a41f73a7.png" title="" alt=""&gt;
异步方式，libpq 只是把指令发送到 Pg，返回发送结果的标志，想要获取执行结果，需要自己去轮询：
&lt;img src="https://l.ruby-china.com/photo/2014/c672fc2861d1637a200afcde04822126.png" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;下面看看 ruby-pg：&lt;a href="https://github.com/ged/ruby-pg" rel="nofollow" target="_blank"&gt;https://github.com/ged/ruby-pg&lt;/a&gt;
ruby-pg 对 Pg 的操作，是依赖 libpq 实现的，其中也包含异步操作接口。
但是，经过 ruby-pg 的封装，异步接口，已经和同步效果一样，看代码：
&lt;a href="https://github.com/ged/ruby-pg/blob/master/ext/pg_connection.c#L3034" rel="nofollow" target="_blank"&gt;https://github.com/ged/ruby-pg/blob/master/ext/pg_connection.c#L3034&lt;/a&gt;
&lt;img src="https://l.ruby-china.com/photo/2014/75eb847fcee32b36b03899bfa65420e4.png" title="" alt=""&gt;
&lt;a href="https://github.com/ged/ruby-pg/blob/master/ext/pg_connection.c#L2997" rel="nofollow" target="_blank"&gt;https://github.com/ged/ruby-pg/blob/master/ext/pg_connection.c#L2997&lt;/a&gt;
&lt;img src="https://l.ruby-china.com/photo/2014/f48e7a8cf9384a086e1338492df026de.png" title="" alt=""&gt;
可以看到，在 send_query 之后，紧接着，就实现了一个轮询方法，去 get_result，这个轮询会导致调用程序阻塞，直到获得返回结果。
使用 Pg 中的 pg_sleep(seconds) 来模拟指令执行，通过代码来验证：
&lt;img src="https://l.ruby-china.com/photo/2014/b600af67c1848bd9c21df3725a128d9b.png" title="" alt=""&gt;
结果 exec 和 async_exec 都在 10 秒后结束，异步和同步的函数，确实都会阻塞 ruby 的解释器。&lt;/p&gt;

&lt;p&gt;也就是说，想要在 ruby 实现对 Pg 的异步操作数据库，ruby-pg 本身不支持。
还是要自己实现个 libpq 的拓展，就把 ruby-pg 中那个轮询的循环去掉就行。&lt;/p&gt;</description>
      <author>chrisloong</author>
      <pubDate>Wed, 03 Sep 2014 20:33:49 +0800</pubDate>
      <link>https://ruby-china.org/topics/21370</link>
      <guid>https://ruby-china.org/topics/21370</guid>
    </item>
  </channel>
</rss>
