###

alias hbin me

由 Pooling 所联想到的东西

池化技术是减少计算机某些昂贵开销的一种有效手段。 网络请求就是典型的一种情况。

Ruby程序员应该对 Faraday 这个 Gem 非常熟悉了, Faraday 将各种常用 HTTP client 包的接口抽象出来,这样我们就不需要去熟悉每一种包的用法, 只要替换 Adapter 就可以实现不同 Gem 直接无缝切换。

关于各种 HTTP client 的对比测试,这篇博文非常详尽:http://reevoo.github.io/blog/2014/09/12/http-shooting-party/ 结果如下图:

上图分别是非 Keep-Alive 和 Keep-Alive 的对比情况,结果对比悬殊,最快的 Curb 和 Excon 相差有 12 倍之巨! 即使同为 Faraday 支持的 Adapter,Patron 和 Excon 也相差 6.8 倍!

这放在有大量请求的时候,性能影响非常大,比如:Elasticsearch

The official (non-Java) clients written and supported by Elasticsearch all use HTTP under the hood to communicate with Elasticsearch.

如上所说 Elasticsearch 官方所有非 Java 的包都是通过 HTTP 的方式链接的。 所以选用一个更快的,可以保持连接(Keep-Alive) 的 HTTP clint 非常重要。感谢 Elasticsearch-ruby 作者,已经默默为我们做了这部分工作,如下代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# Auto-detect the best adapter (HTTP "driver") available, based on libraries
# loaded by the user, preferring those with persistent connections
# ("keep-alive") by default
#
# @return [Symbol]
#
# @api private
#
def __auto_detect_adapter
  case
  when defined?(::Patron)
    :patron
  when defined?(::Typhoeus)
    :typhoeus
  when defined?(::HTTPClient)
    :httpclient
  when defined?(::Net::HTTP::Persistent)
    :net_http_persistent
  else
    ::Faraday.default_adapter
  end
end

所以,我们需要做的只是:gem install patron boom!

但是这还不够!因为除了 Keep-Alive 还有一个更重要的池化(Pooling)! 从 Faraday 的 Patron Adapater 源码

1
2
3
4
5
6
7
8
# https://github.com/lostisland/faraday/blob/master/lib/faraday/adapter/patron.rb#L73-L78

def create_session
  session = ::Patron::Session.new
  session.insecure = true
  @block.call(session) if @block
  session
end

可以看到,这里只是简单新建一个链接,所以我们可以把这个连接池化(Pooling)。这里我们可以使用 connection_pooling 包, 所以一个简单的实现可以是:

1
2
3
4
5
6
7
8
# NOT TESTED, be caution to use it in production!

def create_session
  session = ConnectionPool::Wrapper.new(size: 5, timeout: 3) { ::Patron::Session.new }
  session.insecure = true
  @block.call(session) if @block
  session
end

当然,用 ConnectionPool::Wrapper 的方式相比 with 方式要慢一些,更好的的方式应该把 call 方法里对 session 的调用都用 with 包裹起来,参见 connection_pooling 的文档。

Comments