Dalli -「译」

Dalli

Dalli 对于 memcached 服务是一个高性能的纯Ruby 客户端,它工作于 1.4+ 版本的 memcached,因为它使用了较新的二进制协议。它被认为是 memcache-client gem 的替代品。

这个名字是一位葡萄牙画家的有名画作的变种。

Dalli的最初版本是 CouchBase 赞助的,非常感谢他!

设计

在维护 memcache-client 两年后,因为一些特殊的原因我决定去写 Dalli。

  1. 代码太过老旧以及粗糙,大部分的代码是单独的 1000 行 .rb 文件
  2. 它的许多参数都很少被使用并且复杂化了代码库
  3. 实施监控钩子的时候没有单独的店
  4. 使用太旧的文本协议,降低了未处理的性能

所以有一些笔记,Dailli:

  1. 使用确切相同的算法去选择一个服务,因此存在的 memcached集群运行起 TB级的数据跟 memcache-client 一样
  2. 在 Ruby 1.9.2 中大约比 memcache-client 快百分之20
  3. 包含详细的“阻塞点”方法,能够处理所有请求;这些通过检测工具能够被 hook 来追踪 memcached的使用情况
  4. 在管理环境下支持 SASL
  5. 提供正确的故障切换和可调控的超时

支持 Ruby 版本

Dalli应该工作于:

  1. JRuby 1.6+
  2. Ruby 1.9.3+
  3. Rubinius 2.0

如果你有问题,请提 issue

安装和使用

记住,Dalli要求 memcached 1.4+,你可以通过 memcached -h 来检查版本。请注意 memcached 1.2.8 版本和 Mac OS X Snow Leopadrd 不兼容。通过 Homebrew 来安装 memacached 1.4.x

1
brew install memcached

在 Ubuntu 上你可以通过运行以下命令来安装:

1
apt-get install memcached

你可以使用下面这段代码来确认安装情况

1
gem install dalli
1
2
3
4
5
require 'dalli'
options = { :namespace => "app_v1", :compress => true }
dc = Dalli::Client.new('localhost:11211', options)
dc.set('abc', 123)
value = dc.get('abc')

这测试套件要求 memcached 1.4.3+ 和激活的 SASL。Dalli 没有运行时依赖并且以后也不会有。你可以自定义安装 ‘kgio’ gem 去给 Dalli 提升 百分之20到30的运行提升。

在 Rails3.X 和 Rails4.X 的使用

在你的 gemfile:

1
gem 'dalli'

config/environments/production.rb:

1
config.cache_store = :dalli_store

这里是一个更全面的例子,在这个 Rails App 中,设置了一天内的最大缓存,压缩过大的数据和对所有记录进行命名空间规划,如果你有多个 APP 并且要共享缓存的值,可以移除命名空间。

1
2
config.cache_store = :dalli_store, 'cache-1.example.com', 'cache-2.example.com',
  { :namespace => NAME_OF_RAILS_APP, :expires_in => 1.day, :compress => true }

如果你的服务器在ENV["MEMCACHE_SERVERS"]有特别的设置(比如在 Heroku使用第三方缓存服务时),在服务器中简单的提供nil

1
config.cache_store = :dalli_store, nil, { :namespace => NAME_OF_RAILS_APP, :expires_in => 1.day, :compress => true }

使用 Dalli 为了20分钟后 Rails 的 session 存储过期, 在config/initializers/session_store.rb中:

针对 Rails >= 3.2.4 :

 Rails.application.config.session_store ActionDispatch::Session::CacheStore, :expire_after => 20.minutes

针对 Rails 3.X :

1
2
require 'action_dispatch/middleware/session/dalli_store'
Rails.application.config.session_store :dalli_store, :memcache_server => ['host1', 'host2'], :namespace => 'sessions', :key => '_foundation_session', :expire_after => 20.minutes

Dalli 不支持 Rails 2.X。

Rails 和多线程

如果你使用 Puma 或者其他的多线程 APP SERVER,在 Dalli 2.7 中,你可以使用Dalli 客户端池,并且确认 Rails.cache 并不会变成多线程的资源。你必须添加 gem 'connection_pool 到你的 gemfile 中,以及加上 :pool_sizedalli_store 配置中:

1
config.cache_store = :dalli_store, 'cache-1.example.com', { :pool_size => 5 }

之后你可以像平常一样使用 Rails 的 cache,并且 Rails.cache 会使用连接池,或者你可以检验 Dalli 客户端指向:

1
2
3
4
5
6
7
8
Rails.cache.fetch('foo', :expires_in => 300) do
  'bar'
end

Rails.cache.dalli.with do |client|
  # client is a Dalli::Client instance which you can
  # use ONLY within this block
end

配置

Dalli:Client接受以下的参数,所有的时间都在几秒内。

expires_in : 全局默认 TTL 的 key 为 0,意味着不过期

namespace : 如果有规定,预先考虑每一个key和它的值提供一个简单的命名空间,默认是 nil

failover :boolean 值,如果为 true 并且当主要的服务崩溃时,Daill 将会切换到另一个服务,默认为 true

threadsafe : boolean 值,如果为 true,Dalli 会确保只有一个线程在给定的时间内使用socket,默认为 true, 设置为 false 是很危险的。

serializer : 能够使对象进行存储。

compress : boolean 值, 如果为true, Dalli 将会用 gzip 来压缩超过 1K 的数据,默认为 false

compression_min_size :当超过这个数值时就尝试压缩,默认为1K

compression_max_size :低于这个数值时才尝试压缩,默认为无限

compressor : 被压缩的对象将被存储,默认为 zlib,通过Dalli::Compressor来实现。如果正被压缩的数据使用 nginx 的 HttpMemcachedModule, 设置

memcached_gzip_flag 2 并且使用 Dalli::GzipCompressor

keepalive : boolean值,如果为 true, Dalli 将会使 socket 长久连接,默认为 true

socket_timeout : 所有的 socket 操作超时时间,默认为 0.5

socket_max_failures : 当socket 超时后,socket 操作失败,一个相同的操作将会重试,当处于一个非常缓慢的网络问题时,并不会即时去执行,默认为2

socket_failure_delay : 重试一个 socket 操作之前,这段时间进程将会睡眠,默认为 0.01,设置为 nil 将无延迟

down_retry_delay : 当一个服务因为许多失败明显的崩溃了,仅仅会在这段时间服务将会再次检查以求正常运行。不要将这个值设置得太低,不然每一个到达崩溃服务的请求也许会固定在最大的 socket_timeout,默认为 1 秒

监控

telnet 127.0.0.1 11211 连接上 memcache

输入 stats 获得状态

反省

第一次翻译,翻译得太生硬太渣了。。。

疑惑

看了官方文档,写着:“使用 memcached 来存储缓存时, Rails 会使用默认附带安装的 Dalli gem。” 但是我并没有看到有 Dalli gem 的安装,而且配置也跟 Dalli 有差别。

自带:

1
config.cache_store = :mem_cache_store, "cache-1.example.com", "cache-2.example.com"

Dalli:

1
config.cache_store = :dalli_store, "cache-1.example.com", "cache-2.example.com"

这是为毛- -!