译一技术评论社的文章,是讲memcached的连载?a >fcicq同学说这个东西很有用Q希望大家喜Ƣ?/p>
发表日:(x)2008/7/2
作者:(x)镉K雅广(Masahiro Nagano)
原文链接Q?a >http://gihyo.jp/dev/feature/01/memcached/0001
我是mixi株式?x)?/a>开发部pȝq营l的镉K?
日常负责E序的运营。从今天开始,分几次针对最q在Web应用的可扩展性领?
的热门话题memcachedQ与我公司开发部研究开发组的前坂一P
说明其内部结构和使用?/p>
memcached
是以LiveJournal
旗下Danga Interactive
公司?a >Brad Fitzpatricmemcached是什么?
许多Web应用都将数据保存到RDBMS中,应用服务器从中读取数据ƈ在浏览器中显C? 但随着数据量的增大、访问的集中Q就?x)出现RDBMS的负担加重、数据库响应恶化? |站昄延迟{重大媄(jing)响?/p>
q时pmemcached大显w手?jin)。memcached是高性能的分布式内存~存服务器? 一般的使用目的是,通过~存数据库查询结果,减少数据库访问次敎ͼ以提高动态Web应用的速度? 提高可扩展性?/p>
? 一般情况下memcached的用?/p>
memcached作ؓ(f)高速运行的分布式缓存服务器Q具有以下的特点?/p>
memcached的服务器客户端通信q不使用复杂的XML{格式, 而用简单的Z文本行的协议。因此,通过telnet 也能在memcached上保存数据、取得数据。下面是例子?/p>
$ telnet localhost 11211
Trying 127.0.0.1...
Connected to localhost.localdomain (127.0.0.1).
Escape character is '^]'.
set foo 0 0 3 Q保存命令)(j)
bar Q数据)(j)
STORED Q结果)(j)
get foo Q取得命令)(j)
VALUE foo 0 3 Q数据)(j)
bar Q数据)(j)
协议文档位于memcached的源代码内,也可以参考以下的URL?/p>
libevent是个E序库,它将Linux的epoll、BSDcL作系l的kqueue{事件处理功? 装成统一的接口。即使对服务器的q接数增加,也能发挥O(1)的性能? memcached使用q个libevent库,因此能在Linux、BSD、Solaris{操作系l上发挥光性能? 关于事g处理q里׃再详l介l,可以参考Dan Kegel的The C10K Problem?/p>
Z(jin)提高性能Qmemcached中保存的数据都存储在memcached内置的内存存储空间中? ׃数据仅存在于内存?sh),因此重启memcached、重启操作系l会(x)D全部数据消失? 另外Q内容容量达到指定g后,基于LRU(Least Recently Used)法自动删除不用的~存? memcached本n是ؓ(f)~存而设计的服务器,因此q没有过多考虑数据的永久性问题? 关于内存存储的详l信息,本连载的W二讲以后前坂会(x)q行介绍Q请届时参考?/p>
memcached管?#8220;分布?#8221;~存服务器,但服务器端ƈ没有分布式功能? 各个memcached不会(x)互相通信以共享信息。那么,怎样q行分布式呢Q? q完全取决于客户端的实现。本q蝲也将介绍memcached的分布式?/p>
? memcached的分布式
接下来简单介l一下memcached的用方法?/p>
memcached的安装比较简单,q里E加说明?/p>
memcached支持许多q_?/p>
另外也能安装在Windows上。这里用Fedora Core 8q行说明?/p>
q行memcached需要本文开头介l的libevent库。Fedora 8中有现成的rpm包, 通过yum命o(h)安装卛_?/p>
$ sudo yum install libevent libevent-devel
memcached的源代码可以从memcached|站上下载。本文执W时的最新版本ؓ(f)1.2.5? Fedora 8虽然也包含了(jin)memcached的rpmQ但版本比较老。因为源代码安装q不困难Q? q里׃使用rpm?jin)?/p>
memcached安装与一般应用程序相同,configure、make、make installp?jin)?/p>
$ wget http://www.danga.com/memcached/dist/memcached-1.2.5.tar.gz
$ tar zxf memcached-1.2.5.tar.gz
$ cd memcached-1.2.5
$ ./configure
$ make
$ sudo make install
默认情况下memcached安装?usr/local/bin下?/p>
从终端输入以下命令,启动memcached?/p>
$ /usr/local/bin/memcached -p 11211 -m 64m -vv
slab class 1: chunk size 88 perslab 11915
slab class 2: chunk size 112 perslab 9362
slab class 3: chunk size 144 perslab 7281
中间省略
slab class 38: chunk size 391224 perslab 2
slab class 39: chunk size 489032 perslab 2
<23 server listening
<24 send buffer was 110592, now 268435456
<24 server listening (udp)
<24 server listening (udp)
<24 server listening (udp)
<24 server listening (udp)
q里昄?jin)调试信息。这样就在前台启动了(jin)memcachedQ监听TCP端口11211 最大内存(sh)用量?4M。调试信息的内容大部分是关于存储的信息, 下次q蝲时具体说明?/p>
作ؓ(f)daemon后台启动Ӟ只需
$ /usr/local/bin/memcached -p 11211 -m 64m -d
q里使用的memcached启动选项的内容如下?/p>
选项 | 说明 |
-p | 使用的TCP端口。默认ؓ(f)11211 |
-m | 最大内存大。默认ؓ(f)64M |
-vv | 用very vrebose模式启动Q调试信息和错误输出到控制台 |
-d | 作ؓ(f)daemon在后台启?/td> |
上面四个是常用的启动选项Q其他还有很多,通过
$ /usr/local/bin/memcached -h
命o(h)可以昄。许多选项可以改变memcached的各U行为, 推荐M诅R?/p>
许多语言都实C(jin)q接memcached的客L(fng)Q其中以Perl、PHPZ? 仅仅memcached|站上列出的语言有
{等?/p>
q里介绍通过mixi正在使用的Perl库链接memcached的方法?/p>
Perl的memcached客户端有
{几个CPAN模块。这里介l的Cache::Memcached是memcached的作者Brad Fitzpatric的作品, 应该是memcached的客L(fng)中应用最为广泛的模块?jin)?/p>
下面的源代码为通过Cache::Memcachedq接刚才启动的memcached的例子?/p>
#!/usr/bin/perl
use strict;
use warnings;
use Cache::Memcached;
my $key = "foo";
my $value = "bar";
my $expires = 3600; # 1 hour
my $memcached = Cache::Memcached->new({
servers => ["127.0.0.1:11211"],
compress_threshold => 10_000
});
$memcached->add($key, $value, $expires);
my $ret = $memcached->get($key);
print "$ret"n";
在这里,为Cache::Memcached指定?jin)memcached服务器的IP地址和一个选项Q以生成实例? Cache::Memcached常用的选项如下所C?/p>
选项 | 说明 |
servers | 用数l指定memcached服务器和端口 |
compress_threshold | 数据压羃时用的?/td> |
namespace | 指定d到键的前~ |
另外QCache::Memcached通过Storable模块可以Perl的复杂数据序列化之后再保存, 因此散列、数l、对象等都可以直接保存到memcached中?/p>
向memcached保存数据的方法有
它们的用方法都相同Q?/p>
my $add = $memcached->add( '?, '?, '期限' );
my $replace = $memcached->replace( '?, '?, '期限' );
my $set = $memcached->set( '?, '?, '期限' );
向memcached保存数据时可以指定期?U?。不指定期限Ӟmemcached按照LRU法保存数据? q三个方法的区别如下Q?/p>
选项 | 说明 |
add | 仅当存储I间中不存在键相同的数据时才保存 |
replace | 仅当存储I间中存在键相同的数据时才保?/td> |
set | 与add和replace不同Q无Z旉保存 |
获取数据可以使用get和get_multiҎ(gu)?/p>
my $val = $memcached->get('?);
my $val = $memcached->get_multi('?', '?', '?', '?', '?');
一ơ取得多条数据时使用get_multi。get_multi可以非同步地同时取得多个键| 光度要比循环调用get快数十倍?/p>
删除数据使用deleteҎ(gu)Q不q它有个独特的功能?/p>
$memcached->delete('?, 'd旉(U?');
删除W一个参数指定的键的数据。第二个参数指定一个时间|可以止使用同样的键保存新数据? 此功能可以用于防止缓存数据的不完整。但是要注意Q?strong>set函数忽视该阻塞,照常保存数据
可以memcached上特定的键g数器使用?/p>
my $ret = $memcached->incr('?);
$memcached->add('?, 0) unless defined $ret;
增一和减一是原子操作,但未讄初始值时Q不?x)自动赋?。因此, 应当q行错误(g)查,必要时加入初始化操作。而且Q服务器端也不会(x)? 过2<sup>32</sup>时的行ؓ(f)q行(g)查?/p>
q次单介l了(jin)memcachedQ以?qing)它的安装方法、Perl客户端Cache::Memcached的用法? 只要知道Qmemcached的用方法十分简单就_?jin)?/p>
下次由前坂来说明memcached的内部结构。了(jin)解memcached的内部构造, p知道如何使用memcached才能使Web应用的速度更上一层楼? Ƣ迎l箋阅读下一章?/p>
下面是《memcached全面剖析》的W二部分?/p>
发表日:(x)2008/7/9
作者:(x)前坂?Toru Maesaka)
原文链接Q?a >http://gihyo.jp/dev/feature/01/memcached/0002
我是mixi株式?x)?/a>研究开发组的前坂徹? 上次的文章介l了(jin)memcached是分布式的高速缓存服务器? 本次介lmemcached的内部构造的实现方式Q以?qing)内存的理方式? 另外Qmemcached的内部构造导致的q也将加以说明?/p>
最q的memcached默认情况下采用了(jin)名ؓ(f)Slab Allocator的机制分配、管理内存? 在该机制出现以前Q内存的分配是通过Ҏ(gu)有记录简单地q行malloc和free来进行的? 但是Q这U方式会(x)D内存片Q加重操作系l内存管理器的负担,最坏的情况下, ?x)导致操作系l比memcachedq程本nq慢。Slab Allocator是册问题而诞生的?/p>
下面来看看Slab Allocator的原理。下面是memcached文档中的slab allocator的目标:(x)
the primary goal of the slabs subsystem in memcached was to eliminate memory fragmentation issues totally by using fixed-size memory chunks coming from a few predetermined size classes.
也就是说QSlab Allocator的基本原理是按照预先规定的大,分配的内存分割成特定长度的块, 以完全解军_存碎片问题?/p>
Slab Allocation的原理相当简单?分配的内存分割成各U尺寸的块(chunkQ, q把寸相同的块分成l(chunk的集合)(j)Q图1Q?/p>
? Slab Allocation的构造图
而且Qslab allocatorq有重复使用已分配的内存的目的? 也就是说Q分配到的内存(sh)?x)释放,而是重复利用?/p>
Page
分配lSlab的内存空_(d)默认?MB。分配给Slab之后Ҏ(gu)slab的大切分成chunk?/p>
Chunk
用于~存记录的内存空间?/p>
Slab Class
特定大小的chunk的组?/p>
下面说明memcached如何针对客户端发送的数据选择slabq缓存到chunk中?/p>
memcachedҎ(gu)收到的数据的大小Q选择最适合数据大小的slabQ图2Q? memcached中保存着slab内空闲chunk的列表,Ҏ(gu)该列表选择chunkQ? 然后数据缓存(sh)其中?/p>
? 选择存储记录的组的方?/p>
实际上,Slab Allocator也是有利也有弊。下面介l一下它的缺炏V?/p>
Slab Allocator解决?jin)当初的内存片问题Q但新的机制也给memcached带来?jin)新的问题?/p>
q个问题是Q由于分配的是特定长度的内存Q因此无法有效利用分配的内存? 例如Q将100字节的数据缓存到128字节的chunk中,剩余?8字节浪费了(jin)Q图3Q?/p>
? chunkI间的?/p>
对于该问题目前还没有完美的解x(chng)案,但在文档中记载了(jin)比较有效的解x(chng)案?/p>
The most efficient way to reduce the waste is to use a list of size classes that closely matches (if that's at all possible) common sizes of objects that the clients of this particular installation of memcached are likely to store.
是_(d)如果预先知道客户端发送的数据的公用大,或者仅~存大小相同的数据的情况下, 只要使用适合数据大小的组的列表,可以减浪贏V?/p>
但是很遗憾,现在q(sh)能进行Q何调优,只能期待以后的版本了(jin)? 但是Q我们可以调节slab class的大的差别? 接下来说明growth factor选项?/p>
memcached在启动时指定 Growth Factor因子Q通过-f选项Q, 可以在某种E度上控制slab之间的差异。默认gؓ(f)1.25? 但是Q在该选项出现之前Q这个因子曾l固定ؓ(f)2Q称?#8220;powers of 2”{略?/p>
让我们用以前的设|,以verbose模式启动memcached试试看:(x)
$ memcached -f 2 -vv
下面是启动后的verbose输出Q?/p>
slab class 1: chunk size 128 perslab 8192
slab class 2: chunk size 256 perslab 4096
slab class 3: chunk size 512 perslab 2048
slab class 4: chunk size 1024 perslab 1024
slab class 5: chunk size 2048 perslab 512
slab class 6: chunk size 4096 perslab 256
slab class 7: chunk size 8192 perslab 128
slab class 8: chunk size 16384 perslab 64
slab class 9: chunk size 32768 perslab 32
slab class 10: chunk size 65536 perslab 16
slab class 11: chunk size 131072 perslab 8
slab class 12: chunk size 262144 perslab 4
slab class 13: chunk size 524288 perslab 2
可见Q从128字节的组开始,l的大小依次增大为原来的2倍? q样讄的问题是Qslab之间的差别比较大Q有些情况下q当浪费内存? 因此Qؓ(f)量减少内存?gu)费Q两q前q加?jin)growth factorq个选项?/p>
来看看现在的默认讄Qf=1.25Q时的输出(幅所限,q里只写到第10l)(j)Q?/p>
slab class 1: chunk size 88 perslab 11915
slab class 2: chunk size 112 perslab 9362
slab class 3: chunk size 144 perslab 7281
slab class 4: chunk size 184 perslab 5698
slab class 5: chunk size 232 perslab 4519
slab class 6: chunk size 296 perslab 3542
slab class 7: chunk size 376 perslab 2788
slab class 8: chunk size 472 perslab 2221
slab class 9: chunk size 592 perslab 1771
slab class 10: chunk size 744 perslab 1409
可见Q组间差距比因子?时小得多Q更适合~存几百字节的记录? 从上面的输出l果来看Q可能会(x)觉得有些计算误差Q? q些误差是ؓ(f)?jin)保持字节数的对齐而故意设|的?/p>
memcached引入产品Q或是直接用默认D行部|时Q? 最好是重新计算一下数据的预期q_长度Q调整growth factorQ? 以获得最恰当的设|。内存是珍贵的资源,费太可惜?jin)?/p>
接下来介l一下如何用memcached的stats命o(h)查看slabs的利用率{各U各L(fng)信息?/p>
memcached有个名ؓ(f)stats的命令,使用它可以获得各U各L(fng)信息? 执行命o(h)的方法很多,用telnet最为简单:(x)
$ telnet L?端口?/pre>q接到memcached之后Q输入stats再按回RQ即可获得包括资源利用率在内的各U信息? 此外Q输?stats slabs"?stats items"q可以获得关于缓存记录的信息? l束E序误入quit?/p>
q些命o(h)的详l信息可以参考memcached软g包内的protocol.txt文档?/p>
$ telnet localhost 11211
Trying ::1...
Connected to localhost.
Escape character is '^]'.
stats
STAT pid 481
STAT uptime 16574
STAT time 1213687612
STAT version 1.2.5
STAT pointer_size 32
STAT rusage_user 0.102297
STAT rusage_system 0.214317
STAT curr_items 0
STAT total_items 0
STAT bytes 0
STAT curr_connections 6
STAT total_connections 8
STAT connection_structures 7
STAT cmd_get 0
STAT cmd_set 0
STAT get_hits 0
STAT get_misses 0
STAT evictions 0
STAT bytes_read 20
STAT bytes_written 465
STAT limit_maxbytes 67108864
STAT threads 4
END
quit另外Q如果安装了(jin)libmemcachedq个面向C/C++语言的客L(fng)库,׃(x)安装 memstat q个命o(h)? 使用Ҏ(gu)很简单,可以用更的步骤获得与telnet相同的信息,q能一ơ性从多台服务器获得信息?/p>
$ memstat --servers=server1,server2,server3,...libmemcached可以从下面的地址获得Q?/p>
使用memcached的创造着Brad写的名ؓ(f)memcached-tool的Perl脚本Q可以方便地获得slab的用情? Q它?yu)memcached的返回值整理成Ҏ(gu)阅读的格式)(j)。可以从下面的地址获得脚本Q?/p>
使用Ҏ(gu)也极其简单:(x)
$ memcached-tool L?端口 选项
查看slabs使用状况时无需指定选项Q因此用下面的命令即可:(x)
$ memcached-tool L?端口
获得的信息如下所C:(x)
# Item_Size Max_age 1MB_pages Count Full?
1 104 B 1394292 s 1215 12249628 yes
2 136 B 1456795 s 52 400919 yes
3 176 B 1339587 s 33 196567 yes
4 224 B 1360926 s 109 510221 yes
5 280 B 1570071 s 49 183452 yes
6 352 B 1592051 s 77 229197 yes
7 440 B 1517732 s 66 157183 yes
8 552 B 1460821 s 62 117697 yes
9 696 B 1521917 s 143 215308 yes
10 872 B 1695035 s 205 246162 yes
11 1.1 kB 1681650 s 233 221968 yes
12 1.3 kB 1603363 s 241 183621 yes
13 1.7 kB 1634218 s 94 57197 yes
14 2.1 kB 1695038 s 75 36488 yes
15 2.6 kB 1747075 s 65 25203 yes
16 3.3 kB 1760661 s 78 24167 yes
各列的含义ؓ(f)Q?/p>
?/td> | 含义 |
# | slab class~号 |
Item_Size | Chunk大小 |
Max_age | LRU内最旧的记录的生存时?/td> |
1MB_pages | 分配lSlab的页?/td> |
Count | Slab内的记录?/td> |
Full? | Slab内是否含有空闲chunk |
从这个脚本获得的信息对于调优非常方便Q强烈推荐用?/p>
本次单说明了(jin)memcached的缓存机制和调优Ҏ(gu)? 希望读者能理解memcached的内存管理原理及(qing)其优~点?/p>
下次l说明LRU和Expire{原理,以及(qing)memcached的最新发展方向—? 可扩充体p(pluggable architecherQ)(j)?/p>
下面是《memcached全面剖析》的W三部分?/p>
发表日:(x)2008/7/16
作者:(x)前坂?Toru Maesaka)
原文链接Q?a >http://gihyo.jp/dev/feature/01/memcached/0003
memcached是缓存,所以数据不?x)永久保存在服务器上Q这是向pȝ中引入memcached的前提? 本次介绍memcached的数据删除机Ӟ以及(qing)memcached的最新发展方向——二q制协议QBinary ProtocolQ? 和外部引擎支持?/p>
上次介绍q, memcached不会(x)释放已分配的内存。记录超时后Q客L(fng)无法再看见该记录(invisibleQ透明Q, 其存储空间即可重复用?/p>
memcached内部不会(x)监视记录是否q期Q而是在get时查看记录的旉戻I(g)查记录是否过期? q种技术被UCؓ(f)lazyQ惰性)(j)expiration。因此,memcached不会(x)在过期监视上耗费CPU旉?/p>
memcached?x)优先用已时的记录的I间Q但即如此Q也?x)发生追加新记录时空间不的情况Q? 此时p使用名ؓ(f) Least Recently UsedQLRUQ机制来分配I间? 思义Q这是删?#8220;最q最?#8221;的记录的机制? 因此Q当memcached的内存空间不x(chng)Q无法从slab class 获取到新的空间时Q,׃最q未被用的记录中搜索,q将其空间分配给新的记录? 从缓存的实用角度来看Q该模型十分理想?/p>
不过Q有些情况下LRU机制反倒会(x)造成ȝ(ch)。memcached启动旉过“-M”参数可以止LRUQ如下所C:(x)
$ memcached -M -m 1024
启动时必L意的是,写?#8220;-m”选项是用来指定最大内存大的。不指定具体数值则使用默认?4MB?/p>
指定“-M”参数启动后,内存用尽时memcached?x)返回错误? 话说回来Qmemcached毕竟不是存储器,而是~存Q所以推荐用LRU?/p>
memcached的roadmap上有两个大的目标。一个是二进制协议的{划和实玎ͼ另一个是外部引擎的加载功能?/p>
使用二进制协议的理由是它不需要文本协议的解析处理Q得原本高速的memcached的性能更上一层楼Q? q能减少文本协议的漏z。目前已大部分实玎ͼ开发用的代码库中已包含?jin)该功能? memcached的下载页面上有代码库的链接?/p>
协议的包?4字节的Q其后面是键和无l构数据QUnstructured DataQ? 实际的格式如下(引自协议文档Q:(x)
Byte/ 0 | 1 | 2 | 3 |
/ | | | |
|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|
+---------------+---------------+---------------+---------------+
0/ HEADER /
/ /
/ /
/ /
+---------------+---------------+---------------+---------------+
24/ COMMAND-SPECIFIC EXTRAS (as needed) /
+/ (note length in th extras length header field) /
+---------------+---------------+---------------+---------------+
m/ Key (as needed) /
+/ (note length in key length header field) /
+---------------+---------------+---------------+---------------+
n/ Value (as needed) /
+/ (note length is total body length header field, minus /
+/ sum of the extras and key length body fields) /
+---------------+---------------+---------------+---------------+
Total 24 bytes
如上所C,包格式十分简单。需要注意的是,占据?6字节的头?HEADER)分ؓ(f) h_(d)Request HeaderQ和响应_(d)Response HeaderQ两U? 头部中包含了(jin)表示包的有效性的Magic字节、命令种cR键长度、值长度等信息Q格式如下:(x)
Request Header
Byte/ 0 | 1 | 2 | 3 |
/ | | | |
|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|
+---------------+---------------+---------------+---------------+
0| Magic | Opcode | Key length |
+---------------+---------------+---------------+---------------+
4| Extras length | Data type | Reserved |
+---------------+---------------+---------------+---------------+
8| Total body length |
+---------------+---------------+---------------+---------------+
12| Opaque |
+---------------+---------------+---------------+---------------+
16| CAS |
| |
+---------------+---------------+---------------+---------------+
Response Header
Byte/ 0 | 1 | 2 | 3 |
/ | | | |
|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|
+---------------+---------------+---------------+---------------+
0| Magic | Opcode | Key Length |
+---------------+---------------+---------------+---------------+
4| Extras length | Data type | Status |
+---------------+---------------+---------------+---------------+
8| Total body length |
+---------------+---------------+---------------+---------------+
12| Opaque |
+---------------+---------------+---------------+---------------+
16| CAS |
| |
+---------------+---------------+---------------+---------------+
如希望了(jin)解各个部分的详细内容Q可以checkout出memcached的二q制协议的代码树(wi)Q? 参考其中的docs文g夹中的protocol_binary.txt文档?/p>
看到HEADER格式后我的感x(chng)Q键的上限太大了(jin)Q现在的memcached规格中,键长度最大ؓ(f)250字节Q? 但二q制协议中键的大用2字节表示。因此,理论上最大可使用65536字节Q?<sup>16</sup>Q长的键? 管250字节以上的键q不?x)太常用Q二q制协议发布之后可以用巨大的键了(jin)?/p>
二进制协议从下一版本1.3pd开始支持?/p>
我去q曾l试验性地memcached的存储层攚w成?jin)可扩展的(pluggableQ?/p>
MySQL的Brian Aker看到q个攚w之后,将代码发到?jin)memcached的邮件列表?
memcached的开发者也十分感兴,放C(jin)roadmap中。现在由我和
memcached的开发者Trond Norbye协同开发(规格设计、实现和试Q?
和国外协同开发时时差是个大问题,但抱着相同的愿景,
最后终于可以将可扩展架构的原型公布?jin)?
代码库可以从memcached的下载页?/a>
上访问?/p>
世界上有许多memcached的派生YӞ其理由是希望怹保存数据、实现数据冗余等Q?
即牺牲一些性能也在所不惜。我在开发memcached之前Q在mixi的研发部也曾l?
考虑q重新发明memcached?/p>
外部引擎的加载机制能装memcached的网l功能、事件处理等复杂的处理?
因此Q现阶段通过强制手段或重新设计等方式使memcached和存储引擎合作的困难
׃(x)烟消云散Q尝试各U引擎就?x)变得轻而易举了(jin)?/p>
该项目中我们最重视的是API设计。函数过多,?x)引擎开发者感到麻?ch)?
q于复杂Q实现引擎的门槛׃(x)q高。因此,最初版本的接口函数只有13个?
具体内容限于幅Q这里就省略?jin),仅说明一下引擎应当完成的操作Q?/p>
对详l规格有兴趣的读者,可以checkout engine目的代码,阅读器中的engine.h?/p>
memcached支持外部存储的难Ҏ(gu)Q网l和事g处理相关的代码(核心(j)服务器)(j)?
内存存储的代码紧密关联。这U现象也UCؓ(f)tightly coupledQ紧密耦合Q?
必须内存存储的代码从核?j)服务器中独立出来,才能灉|地支持外部引擎?
因此Q基于我们设计的APIQmemcached被重构成下面的样子:(x) 重构之后Q我们与1.2.5版、二q制协议支持版等q行?jin)性能Ҏ(gu)Q证实了(jin)它不?x)造成性能影响?/p>
在考虑如何支持外部引擎加蝲Ӟ让memcachedq行q行控制Qconcurrency controlQ的Ҏ(gu)是最为容易的Q?
但是对于引擎而言Qƈ行控制正是性能的真谛,因此我们采用?jin)将多线E支持完全交l引擎的设计Ҏ(gu)?/p>
以后的改q,?x)得memcached的应用范围更为广泛?/p>
本次介绍?jin)memcached的超时原理、内部如何删除数据等Q在此之上又介绍?jin)二q制协议?
外部引擎支持{memcached的最新发展方向。这些功能要?.3版才?x)支持,敬请期待Q?/p>
q是我在本连载中的最后一。感谢大安L的文章! 下次由长野来介绍memcached的应用知识和应用E序兼容性等内容?/p>
发表日:(x)2008/7/23 外部引擎支持的必要?/h3>
单API设计的成功的关键
重新审视现在的体p?/h3>
ȝ
4. memcached的分布式法
作者:(x)镉K雅广(Masahiro Nagano)
原文链接Q?a >http://gihyo.jp/dev/feature/01/memcached/0004
我是Mixi的长野?
W??/a>?
W??/a>
由前坂介l了(jin)memcached的内部情c(din)本ơ不再介lmemcached的内部结构,
开始介lmemcached的分布式?/p>
正如W??/a>中介l的那样Q?
memcached虽然UCؓ(f)“分布?#8221;~存服务器,但服务器端ƈ没有“分布?#8221;功能?
服务器端仅包?
W??/a>?
W??/a>
前坂介绍的内存存储功能,其实现非常简单?
至于memcached的分布式Q则是完全由客户端程序库实现的?
q种分布式是memcached的最大特炏V?/p>
q里多次使用?#8220;分布?#8221;q个词,但ƈ未做详细解释?
现在开始简单地介绍一下其原理Q各个客L(fng)的实现基本相同?/p>
下面假设memcached服务器有node1~node3三台Q?
应用E序要保存键名ؓ(f)“tokyo”“kanagawa”“chiba”“saitama”“gunma”
的数据?/p>
? 分布式简介:(x)准备 首先向memcached中添?#8220;tokyo”。将“tokyo”传给客户端程序库后,
客户端实现的法׃(x)Ҏ(gu)“?#8221;来决定保存数据的memcached服务器?
服务器选定后,卛_令它保存“tokyo”?qing)其倹{?/p>
? 分布式简介:(x)d?/p>
同样Q?#8220;kanagawa”“chiba”“saitama”“gunma”都是先选择服务器再保存?/p>
接下来获取保存的数据。获取时也要要获取的键“tokyo”传递给函数库?
函数库通过与数据保存时相同的算法,Ҏ(gu)“?#8221;选择服务器?
使用的算法相同,p选中与保存时相同的服务器Q然后发送get命o(h)?
只要数据没有因ؓ(f)某些原因被删除,p获得保存的倹{?/p>
? 分布式简介:(x)获取?/p>
q样Q将不同的键保存C同的服务器上Q就实现?jin)memcached的分布式?
memcached服务器增多后Q键׃(x)分散Q即使一台memcached服务器发生故?
无法q接Q也不会(x)影响其他的缓存,pȝ依然能l运行?/p>
接下来介l?a >W??/a>
中提到的Perl客户端函数库Cache::Memcached实现的分布式Ҏ(gu)?/p>
Perl的memcached客户端函数库Cache::Memcached?
memcached的作者Brad Fitzpatrick的作品,可以说是原装的函数库?jin)?/p>
该函数库实现?jin)分布式功能Q是memcached标准的分布式Ҏ(gu)?/p>
Cache::Memcached的分布式Ҏ(gu)单来_(d)是“Ҏ(gu)服务器台数的余数q行分散”?
求得键的整数哈希|再除以服务器台数Q根据其余数来选择服务器?/p>
下面Cache::Memcached化成以下的Perl脚本来进行说明?/p>
Cache::Memcached在求哈希值时使用?jin)CRC?/p>
首先求得字符串的CRC|Ҏ(gu)该值除以服务器节点数目得到的余数决定服务器?
上面的代码执行后输入以下l果Q?/p>
Ҏ(gu)该结果,“tokyo”分散到node2Q?#8220;kanagawa”分散到node3{?
多说一句,当选择的服务器无法q接ӞCache::Memcached?x)将q接ơ数
d到键之后Q再ơ计哈希值ƈ试q接。这个动作称为rehash?
不希望rehash时可以在生成Cache::Memcached对象时指?#8220;rehash => 0”选项?/p>
余数计算的方法简单,数据的分散性也相当优秀Q但也有其缺炏V?
那就是当d或移除服务器Ӟ~存重组的代L(fng)当巨大?
d服务器后Q余数就?x)生巨变,q样无法获取与保存时相同的服务器,
从而媄(jing)响缓存的命中率。用Perl写段代码来验证其代h(hun)?/p>
q段Perl脚本演示?jin)?#8220;a”?#8220;z”的键保存到memcachedq访问的情况?
其保存?sh)mod.plq执行?/p>
首先Q当服务器只有三台时Q?/p>
l果如上Qnode1保存a、c、d、e……Qnode2保存g、i、k……Q?
每台服务器都保存?sh)?个到10个数据?/p>
接下来增加一台memcached服务器?/p>
d?jin)node4。可见,只有d、i、k、p、r、y命中?jin)。像q样Q添加节点后
键分散到的服务器?x)发生巨大变化?6个键中只有六个在讉K原来的服务器Q?
其他的全都移C(jin)其他服务器。命中率降低?3%。在Web应用E序中用memcachedӞ
在添加memcached服务器的瞬间~存效率?x)大q度下降Q负载会(x)集中到数据库服务器上Q?
有可能会(x)发生无法提供正常服务的情c(din)?/p>
mixi的Web应用E序q用中也有这个问题,D无法dmemcached服务器?
但由于用了(jin)新的分布式方法,现在可以轻而易丑֜dmemcached服务器了(jin)?
q种分布式方法称?Consistent Hashing?/p>
关于Consistent Hashing的思想Qmixi株式?x)社的开发blog{许多地斚w介绍q,
q里只简单地说明一下?/p>
Consistent Hashing如下所C:(x)首先求出memcached服务器(节点Q的哈希|
q将光|到0?32的圆QcontinuumQ上?
然后用同L(fng)Ҏ(gu)求出存储数据的键的哈希|q映到圆上?
然后从数据映到的位|开始顺旉查找Q将数据保存到找到的W一个服务器上?
如果过232仍然找不到服务器Q就?x)保存到W一台memcached服务器上?/p>
? Consistent HashingQ基本原?/p>
从上囄状态中d一台memcached服务器。余数分布式法׃保存键的服务器会(x)发生巨大变化
而媄(jing)响缓存的命中率,但Consistent Hashing中,只有在continuum上增加服务器的地炚w时针方向的
W一台服务器上的键会(x)受到影响?/p>
? Consistent HashingQ添加服务器 因此QConsistent Hashing最大限度地抑制?jin)键的重新分布?
而且Q有的Consistent Hashing的实现方法还采用?jin)虚拟节点的思想?
使用一般的hash函数的话Q服务器的映地点的分布非常不均匀?
因此Q用虚拟节点的思想Qؓ(f)每个物理节点Q服务器Q?
在continuum上分?00?00个点。这样就能抑制分布不均匀Q?
最大限度地减小服务器增减时的缓存重新分布?/p>
通过下文中介l的使用Consistent Hashing法的memcached客户端函数库q行试的结果是Q?
由服务器台数QnQ和增加的服务器台数QmQ计增加服务器后的命中率计公式如下:(x) (1 - n/(n+m)) * 100 本连载中多次介绍的Cache::Memcached虽然不支持Consistent HashingQ?
但已有几个客L(fng)函数库支持了(jin)q种新的分布式算法?
W一个支持Consistent Hashing和虚拟节点的memcached客户端函数库?
名ؓ(f)libketama的PHP库,由last.fm开发?/p>
至于Perl客户端,q蝲?a >W??/a>
中介l过的Cache::Memcached::Fast和Cache::Memcached::libmemcached支持
Consistent Hashing?/p>
两者的接口都与Cache::Memcached几乎相同Q如果正在用Cache::MemcachedQ?
那么可以方便地替换q来。Cache::Memcached::Fast重新实现?jin)libketamaQ?
使用Consistent Hashing创徏对象时可以指定ketama_points选项?/p>
另外QCache::Memcached::libmemcached 是一个用了(jin)Brain Aker开发的C函数库libmemcached的Perl模块?
libmemcached本n支持几种分布式算法,也支持Consistent HashingQ?
其Perll定也支持Consistent Hashing?/p>
本次介绍?jin)memcached的分布式法Q主要有memcached的分布式是由客户端函数库实现Q?
以及(qing)高效率地分散数据的Consistent Hashing法。下ơ将介绍mixi在memcached应用斚w的一些经验,
和相关的兼容应用E序?/p>
发表日:(x)2008/7/30 我是Mixi的长野。memcached的连载终于要l束?jin)?
?a >上次memcached的分布式
memcached的分布式是什么意思?
Cache::Memcached的分布式Ҏ(gu)
Ҏ(gu)余数计算分散
use strict;
use warnings;
use String::CRC32;
my @nodes = ('node1','node2','node3');
my @keys = ('tokyo', 'kanagawa', 'chiba', 'saitama', 'gunma');
foreach my $key (@keys) {
my $crc = crc32($key); # CRC?br />
my $mod = $crc % ( $#nodes + 1 );
my $server = $nodes[ $mod ]; # Ҏ(gu)余数选择服务?br />
printf "%s => %s"n", $key, $server;
}tokyo => node2
kanagawa => node3
chiba => node2
saitama => node1
gunma => node1Ҏ(gu)余数计算分散的缺?/h3>
use strict;
use warnings;
use String::CRC32;
my @nodes = @ARGV;
my @keys = ('a'..'z');
my %nodes;
foreach my $key ( @keys ) {
my $hash = crc32($key);
my $mod = $hash % ( $#nodes + 1 );
my $server = $nodes[ $mod ];
push @{ $nodes{ $server } }, $key;
}
foreach my $node ( sort keys %nodes ) {
printf "%s: %s"n", $node, join ",", @{ $nodes{$node} };
}$ mod.pl node1 node2 nod3
node1: a,c,d,e,h,j,n,u,w,x
node2: g,i,k,l,p,r,s,y
node3: b,f,m,o,q,t,v,z$ mod.pl node1 node2 node3 node4
node1: d,f,m,o,t,v
node2: b,i,k,p,r,y
node3: e,g,l,n,u,w
node4: a,c,h,j,q,s,x,zConsistent Hashing
Consistent Hashing的简单说?/h3>
支持Consistent Hashing的函数库
my $memcached = Cache::Memcached::Fast->new({
servers => ["192.168.0.1:11211","192.168.0.2:11211"],
ketama_points => 150
});ȝ
5. memcached的应用和兼容E序
作者:(x)镉K雅广(Masahiro Nagano)
原文链接Q?a >http://gihyo.jp/dev/feature/01/memcached/0005
mixi在提供服务的初期阶段׃用了(jin)memcached? 随着|站讉K量的急剧增加Q单Uؓ(f)数据库添加slave已无法满需要,因此引入?jin)memcached? 此外Q我们也从增加可扩展性的斚wq行?jin)验证,证明了(jin)memcached的速度和稳定性都能满需要? 现在Qmemcached已成为mixi服务中非帔R要的l成部分?/p>
? 现在的系l组?/p>
mixi使用?jin)许许多多服务器Q如数据库服务器、应用服务器、图片服务器? 反向代理服务器等。单单memcached有近200台服务器在运行? memcached服务器的典型配置如下Q?/p>
q些服务器以前曾用于数据库服务器{。随着CPU性能提升、内存(sh)h(hun)g降, 我们U极地将数据库服务器、应用服务器{换成了(jin)性能更强大、内存更多的服务器? q样Q可以抑制mixi整体使用的服务器数量的急剧增加Q降低管理成本? ׃memcached服务器几乎不占用CPUQ就换下来的服务器用作memcached服务器了(jin)?/p>
每台memcached服务器仅启动一个memcachedq程。分配给memcached的内存(sh)ؓ(f)3GBQ? 启动参数如下Q?/p>
/usr/bin/memcached -p 11211 -u nobody -m 3000 -c 30720
׃使用?jin)x86_64的操作系l,因此能分?GB以上的内存?2位操作系l中Q? 每个q程最多只能?GB内存。也曄考虑q启动多个分?GB以下内存的进E, 但这样一台服务器上的TCPq接数就?x)成倍增加,理上也变得复杂Q? 所以mixiq一使用?4位操作系l?/p>
另外Q虽然服务器的内存(sh)ؓ(f)4GBQ却仅分配了(jin)3GBQ是因ؓ(f)内存分配量超q这个|
有可能D内存?sh)?swap)。连载的W??/a>?
前坂讲解q了(jin)memcached的内存存?#8220;slab allocator”Q当时说q,memcached启动?
指定的内存分配量是memcached用于保存数据的量Q没有包?#8220;slab allocator”本n占用的内存?
以及(qing)Z(jin)保存数据而设|的理I间。因此,memcachedq程的实际内存分配量要比
指定的容量要大,q一点应当注意?/p>
mixi保存在memcached中的数据大部分都比较?yu)。这Pq程的大要?
指定的容量大很多。因此,我们反复改变内存分配量进行验证,
认?GB的大不?x)引发swapQ这是现在应用的数倹{?/p>
现在Qmixi的服务将200台左右的memcached服务器作Z个pool使用?
每台服务器的定w?GBQ那么全体就有了(jin)近600GB的巨大的内存数据库?
客户端程序库使用?jin)本q蝲中多ơ提到R的Cache::Memcached::FastQ?
与服务器q行交互。当?dng)~存的分布式法使用的是
W??/a>介绍q的
Consistent Hashing法?/p>
应用层上memcached的用方法由开发应用程序的工程师自行决定ƈ实现?
但是Qؓ(f)?jin)防止R轮再造、防止Cache::Memcached::Fast上的教训再次发生Q?
我们提供?jin)Cache::Memcached::Fast的wrap模块q用?/p>
Cache::Memcached的情况下Q与memcached的连接(文g句柄Q保存在Cache::Memcached包内的类变量中?
在mod_perl和FastCGI{环境下Q包内的变量不会(x)像CGI那样随时重新启动Q?
而是在进E中一直保持。其l果是不会(x)断开与memcached的连接,
减少?jin)TCPq接建立时的开销Q同时也能防止短旉内反复进行TCPq接、断开
而导致的TCP端口资源枯竭?/p>
但是QCache::Memcached::Fast没有q个功能Q所以需要在模块之外
Cache::Memcached::Fast对象保持在类变量中,以保证持久连接?/p>
上面的例子中QCache::Memcached::Fast对象保存到类变量$fast中?/p>
诸如mixi的主上的新闻这L(fng)所有用户共享的~存数据、设|信息等数据Q?
?x)占用许多页Q访问次C非常多。在q种条g下,讉K很容易集中到某台memcached服务器上?
讉K集中本nq不是问题,但是一旦访问集中的那台服务器发生故障导致memcached无法q接Q?
׃(x)产生巨大的问题?/p>
q蝲?a >W??/a>
中提刎ͼCache::Memcached拥有rehash功能Q即在无法连接保存数据的服务器的情况下,
?x)再ơ计hash|q接其他的服务器?/p>
但是QCache::Memcached::Fast没有q个功能。不q,它能够在q接服务器失败时Q?
短时间内不再q接该服务器的功能?/p>
在failure_timeoutU内发生max_failures以上ơ连接失败,׃再连接该memcached服务器?
我们的设|是1U钟3ơ以上?/p>
此外Qmixiq(sh)ؓ(f)所有用户共享的~存数据的键名设|命名规则,
W合命名规则的数据会(x)自动保存到多台memcached服务器中Q?
取得时从中仅选取一台服务器。创函数库后Q就可以使memcached服务器故?
不再产生其他影响?/p>
到此为止介绍?jin)memcached内部构造和函数库,接下来介l一些其他的应用l验?/p>
通常情况下memcachedq行得相当稳定,但mixi现在使用的最新版1.2.5
曄发生q几ơmemcachedq程L的情c(din)架构上保证?jin)即使有几台memcached故障
也不?x)?jing)响服务,不过对于memcachedq程L的服务器Q只要重新启动memcachedQ?
可以正常运行,所以采用了(jin)监视memcachedq程q自动启动的Ҏ(gu)?
于是使用?jin)daemontools?/p>
daemontools是qmail的作者DJB开发的UNIX服务理工具集,
其中名ؓ(f)supervise的程序可用于服务启动、停止的服务重启{?/p>
q里不介ldaemontools的安装了(jin)。mixi使用?jin)以下的run脚本来启动memcached?/p>
mixi使用?jin)名?#8220;nagios”的开源监视Y件来监视memcached?/p>
在nagios中可以简单地开发插Ӟ可以详细地监视memcached的get、add{动作?
不过mixi仅通过stats命o(h)来确认memcached的运行状态?/p>
此外Qmixistats目录的结果通过rrdtool转化成图形,q行性能监视Q?
q将每天的内存(sh)用量做成报表Q通过邮g与开发者共享?/p>
q蝲中已介绍q,memcached的性能十分优秀。我们来看看mixi的实际案例?
q里介绍的图表是服务所使用的访问最为集中的memcached服务器?/p>
? h?/p>
? 量 ? TCPq接?/p>
从上至下依次求数、流量和TCPq接数。请求数最大ؓ(f)15000qpsQ?
量辑ֈ400MbpsQ这时的q接数已过?0000个?
该服务器没有特别的硬Ӟ是开头介l的普通的memcached服务器?
此时的CPU利用率ؓ(f)Q?/p>
? CPU利用?/p>
可见Q仍然有idle的部分。因此,memcached的性能非常高,
可以作ؓ(f)Web应用E序开发者放?j)地保存(sh)时数据或缓存数据的地方?/p>
memcached的实现和协议都十分简单,因此有很多与memcached兼容的实现?
一些功能强大的扩展可以memcached的内存数据写到磁盘(sh)Q实现数据的持久性和冗余?
q蝲W??/a>
介绍q,以后的memcached的存储层变成可扩展的(pluggableQ,逐渐支持q些功能?/p>
q里介绍几个与memcached兼容的应用程序?/p>
mixi使用?jin)上q兼容应用程序中的Tokyo Tyrant。Tokyo Tyrant是^林开发的
Tokyo Cabinet DBM的网l接口。它有自q协议Q但也拥有memcached兼容协议Q?
也可以通过HTTPq行数据交换。Tokyo Cabinet虽然是一U将数据写到盘的实玎ͼ但速度相当快?/p>
mixiq没有将Tokyo Tyrant作ؓ(f)~存服务器,而是它作ؓ(f)保存键值对l合的DBMS来用?
主要作ؓ(f)存储用户上次讉K旉的数据库来用。它与几乎所有的mixi服务都有养I
每次用户讉K面旉要更新数据,因此负荷相当高。MySQL的处理十分笨重,
单独使用memcached保存数据又有可能?x)丢失数据,所以引入了(jin)Tokyo Tyrant?
但无需重新开发客L(fng)Q只需原封不动C用Cache::Memcached::Fast卛_Q?
q也是优点之一。关于Tokyo Tyrant的详l信息,请参考本公司的开发blog?/p>
到本ơؓ(f)止,“memcached全面剖析”pdq束了(jin)。我们介l了(jin)memcached的基、内部结构?
分散法和应用等内容。读完后如果(zhn)能对memcached产生兴趣Q就是我们的荣幸?
关于mixi的系l、应用方面的信息Q请参考本公司?a >开发blogmemcached使用Ҏ(gu)和客L(fng)
通过Cache::Memcached::Fastl持q接
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(@_);
}公共数据的处理和rehash
my $fast = Cache::Memcached::Fast->new({
max_failures => 3,
failure_timeout => 1
});memcached应用l验
通过daemontools启动
#!/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监视
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
}memcached的性能
兼容应用E序
Tokyo Tyrant案例
ȝ
Once you disable directory browsing, visitor will not able to browse your directory by accessing the directory directly (if there is no index.html file). This will protect your files from exposing to the public.
http://ubuntuforums.org/archive/index.php/t-234876.html