首页 > 代码库 > Memcached全面剖析–5. memcached的应用和兼容程序

Memcached全面剖析–5. memcached的应用和兼容程序

作者:长野雅广(Masahiro Nagano) 
原文链接:http://gihyo.jp/dev/feature/01/memcached/0005

我是Mixi的长野。memcached的连载最终要结束了。 到上次为止, 我们介绍了与memcached直接相关的话题,本次介绍一些mixi的案例和 实际应用上的话题,并介绍一些与memcached兼容的程序。

mixi案例研究

mixi在提供服务的初期阶段就使用了memcached。 随着站点訪问量的急剧添加?,单纯为数据库加入?slave已无法满足须要,因此引入了memcached。 此外,我们也从添加?可扩展性的方面进行了验证,证明了memcached的速度和稳定性都能满足须要。 如今,memcached已成为mixi服务中很重要的组成部分。


图1 如今的系统组件

server配置和数量

mixi使用了许很多多server,如数据库server、应用server、图片server、 反向代理server等。单单memcached就有将近200台server在执行。 memcachedserver的典型配置例如以下:

  • CPU:Intel Pentium 4 2.8GHz
  • 内存:4GB
  • 硬盘:146GB SCSI
  • 操作系统:Linux(x86_64)

这些server曾经曾用于数据库server等。随着CPU性能提升、内存价格下降, 我们积极地将数据库server、应用server等换成了性能更强大、内存很多其它的server。 这样,能够抑制mixi总体使用的server数量的急剧添加?,减少管理成本。 因为memcachedserver差点儿不占用CPU,就将换下来的server用作memcachedserver了。

memcached进程

每台memcachedserver仅启动一个memcached进程。分配给memcached的内存为3GB, 启动參数例如以下:

/usr/bin/memcached -p 11211 -u nobody -m 3000 -c 30720

因为使用了x86_64的操作系统,因此能分配2GB以上的内存。32位操作系统中, 每一个进程最多仅仅能使用2GB内存。也以前考虑过启动多个分配2GB下面内存的进程, 但这样一台server上的TCP连接数就会成倍添加?,管理上也变得复杂, 所以mixi就统一使用了64位操作系统。

另外,尽管server的内存为4GB,却仅分配了3GB,是由于内存分配量超过这个值, 就有可能导致内存交换(swap)。连载的第2次中 前坂解说过了memcached的内存存储“slab allocator”,当时说过,memcached启动时 指定的内存分配量是memcached用于保存数据的量,没有包含“slab allocator”本身占用的内存、 以及为了保存数据而设置的管理空间。因此,memcached进程的实际内存分配量要比 指定的容量要大,这一点应当注意。

mixi保存在memcached中的数据大部分都比較小。这样,进程的大小要比 指定的容量大非常多。因此,我们重复改变内存分配量进行验证, 确认了3GB的大小不会引发swap,这就是如今应用的数值。

memcached用法和client

如今,mixi的服务将200台左右的memcachedserver作为一个pool使用。 每台server的容量为3GB,那么全体就有了将近600GB的巨大的内存数据库。 client程序库使用了本连载中多次提到车的Cache::Memcached::Fast, 与server进行交互。当然,缓存的分布式算法使用的是 第4次介绍过的 Consistent Hashing算法。

  • Cache::Memcached::Fast - search.cpan.org

应用层上memcached的用法由开发应用程序的project师自行决定并实现。 可是,为了防止车轮再造、防止Cache::Memcached::Fast上的教训再次发生, 我们提供了Cache::Memcached::Fast的wrap模块并使用。

通过Cache::Memcached::Fast维持连接

Cache::Memcached的情况下,与memcached的连接(文件句柄)保存在Cache::Memcached包内的类变量中。 在mod_perl和FastCGI等环境下,包内的变量不会像CGI那样随时又一次启动, 而是在进程中一直保持。其结果就是不会断开与memcached的连接, 降低了TCP连接建立时的开销,同一时候也能防止短时间内重复进行TCP连接、断开 而导致的TCPport资源枯竭。

可是,Cache::Memcached::Fast没有这个功能,所以须要在模块之外 将Cache::Memcached::Fast对象保持在类变量中,以保证持久连接。

package Gihyo::Memcached;

use strict;
use warnings;
use Cache::Memcached::Fast;

my @server_list = qw/192.168.1.1:11211 192.168.1.1:11211/;
my $fast; ## 用于保持对象

sub new {
my $self = bless {}, shift;
if ( !$fast ) {
$fast = Cache::Memcached::Fast->new({ servers => \@server_list });
}
$self->{_fast} = $fast;
return $self;
}

sub get {
my $self = shift;
$self->{_fast}->get(@_);
}

上面的样例中,Cache::Memcached::Fast对象保存到类变量$fast中。

公共数据的处理和rehash

诸如mixi的主页上的新闻这种全部用户共享的缓存数据、设置信息等数据, 会占用很多页,訪问次数也非常多。在这种条件下,訪问非常easy集中到某台memcachedserver上。 訪问集中本身并非问题,可是一旦訪问集中的那台server发生问题导致memcached无法连接, 就会产生巨大的问题。

连载的第4次 中提到,Cache::Memcached拥有rehash功能,即在无法连接保存数据的server的情况下, 会再次计算hash值,连接其它的server。

可是,Cache::Memcached::Fast没有这个功能。只是,它可以在连接server失败时, 短时间内不再连接该server的功能。

my $fast = Cache::Memcached::Fast->new({
max_failures => 3,
failure_timeout => 1
});

在failure_timeout秒内发生max_failures以上次连接失败,就不再连接该memcachedserver。 我们的设置是1秒钟3次以上。

此外,mixi还为全部用户共享的缓存数据的键名设置命名规则, 符合命名规则的数据会自己主动保存到多台memcachedserver中, 取得时从中仅选取一台server。创建该函数库后,就能够使memcachedserver故障 不再产生其它影响。

memcached应用经验

到此为止介绍了memcached内部构造和函数库,接下来介绍一些其它的应用经验。

通过daemontools启动

通常情况下memcached执行得相当稳定,但mixi如今使用的最新版1.2.5 以前发生过几次memcached进程死掉的情况。架构上保证了即使有几台memcached故障 也不会影响服务,只是对于memcached进程死掉的server,仅仅要又一次启动memcached, 就能够正常执行,所以採用了监视memcached进程并自己主动启动的方法。 于是使用了daemontools。

daemontools是qmail的作者DJB开发的UNIX服务管理工具集, 当中名为supervise的程序可用于服务启动、停止的服务重新启动等。

  • daemontools

这里不介绍daemontools的安装了。mixi使用了下面的run脚本来启动memcached。

#!/bin/sh

if [ -f /etc/sysconfig/memcached ];then
. /etc/sysconfig/memcached
fi

exec 2>&1
exec /usr/bin/memcached -p $PORT -u $USER -m $CACHESIZE -c $MAXCONN $OPTIONS

监视

mixi使用了名为“nagios”的开源监视软件来监视memcached。

  • Nagios: Home

在nagios中能够简单地开发插件,能够具体地监视memcached的get、add等动作。 只是mixi仅通过stats命令来确认memcached的执行状态。

define command {
command_name check_memcached
command_line $USER1$/check_tcp -H $HOSTADDRESS$ -p 11211 -t 5 -E -s ‘stats\r\nquit\r\n‘ -e ‘uptime‘ -M crit
}

此外,mixi将stats文件夹的结果通过rrdtool转化成图形,进行性能监视, 并将每天的内存使用量做成报表,通过邮件与开发人员共享。

memcached的性能

连载中已介绍过,memcached的性能十分优秀。我们来看看mixi的实际案例。 这里介绍的图表是服务所使用的訪问最为集中的memcachedserver。


图2 请求数


图3 流量


图4 TCP连接数

从上至下依次为请求数、流量和TCP连接数。请求数最大为15000qps, 流量达到400Mbps,这时的连接数已超过了10000个。 该server没有特别的硬件,就是开头介绍的普通的memcachedserver。 此时的CPU利用率为:


图5 CPU利用率

可见,仍然有idle的部分。因此,memcached的性能很高, 能够作为Web应用程序开发人员放心地保存暂时数据或缓存数据的地方。

兼容应用程序

memcached的实现和协议都十分简单,因此有非常多与memcached兼容的实现。 一些功能强大的扩展能够将memcached的内存数据写到磁盘上,实现数据的持久性和冗余。 连载第3次 介绍过,以后的memcached的存储层将变成可扩展的(pluggable),逐渐支持这些功能。

这里介绍几个与memcached兼容的应用程序。

repcached
为memcached提供复制(replication)功能的patch。
Flared
存储到QDBM。同一时候实现了异步复制和fail over等功能。
memcachedb
存储到BerkleyDB。还实现了message queue。
Tokyo Tyrant
将数据存储到Tokyo Cabinet。不仅与memcached协议兼容,还能通过HTTP进行訪问。

Tokyo Tyrant案例

mixi使用了上述兼容应用程序中的Tokyo Tyrant。Tokyo Tyrant是平林开发的 Tokyo Cabinet DBM的网络接口。它有自己的协议,但也拥有memcached兼容协议, 也能够通过HTTP进行数据交换。Tokyo Cabinet尽管是一种将数据写到磁盘的实现,但速度相当快。

mixi并没有将Tokyo Tyrant作为缓存server,而是将它作为保存键值对组合的DBMS来使用。 主要作为存储用户上次訪问时间的数据库来使用。它与差点儿全部的mixi服务都有关, 每次用户訪问页面时都要更新数据,因此负荷相当高。MySQL的处理十分笨重, 单独使用memcached保存数据又有可能会丢失数据,所以引入了Tokyo Tyrant。 但无需又一次开发client,仅仅需原封不动地使用Cache::Memcached::Fast就可以, 这也是长处之中的一个。关于Tokyo Tyrant的具体信息,请參考本公司的开发blog。

  • mixi Engineers‘ Blog - Tokyo Tyrantによる耐高負荷DBの構築
  • mixi Engineers‘ Blog - Tokyo (Cabinet|Tyrant)の新機能

总结

到本次为止,“memcached全面剖析”系列就结束了。我们介绍了memcached的基础、内部结构、 分散算法和应用等内容。读完后假设您能对memcached产生兴趣,就是我们的荣幸。 关于mixi的系统、应用方面的信息,请參考本公司的开发blog。 感谢您的阅读。

Memcached全面剖析–5. memcached的应用和兼容程序