译一技术评论社的文章,是讲memcached的连载?a >fcicq同学说这个东西很有用Q希望大家喜Ƣ?/p>
发表日:2008/7/2
作者:镉K雅广(Masahiro Nagano)
原文链接Q?a >http://gihyo.jp/dev/feature/01/memcached/0001
我是mixi株式会社开发部pȝq营l的镉K? 日常负责E序的运营。从今天开始,分几次针对最q在Web应用的可扩展性领? 的热门话题memcachedQ与我公司开发部研究开发组的前坂一P 说明其内部结构和使用?/p>
memcached 是以LiveJournal 旗下Danga Interactive 公司?a >Brad Fitzpatric 为首开发的一ƾY件。现在已成ؓ mixi? hatena? Facebook? Vox、LiveJournal{众多服务中 提高Web应用扩展性的重要因素?/p>
许多Web应用都将数据保存到RDBMS中,应用服务器从中读取数据ƈ在浏览器中显C? 但随着数据量的增大、访问的集中Q就会出现RDBMS的负担加重、数据库响应恶化? |站昄延迟{重大媄响?/p>
q时pmemcached大显w手了。memcached是高性能的分布式内存~存服务器? 一般的使用目的是,通过~存数据库查询结果,减少数据库访问次敎ͼ以提高动态Web应用的速度? 提高可扩展性?/p>
? 一般情况下memcached的用?/p>
memcached作ؓ高速运行的分布式缓存服务器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保存命令)
bar Q数据)
STORED Q结果)
get foo Q取得命令)
VALUE foo 0 3 Q数据)
bar Q数据)
协议文档位于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提高性能Qmemcached中保存的数据都存储在memcached内置的内存存储空间中? ׃数据仅存在于内存中,因此重启memcached、重启操作系l会D全部数据消失? 另外Q内容容量达到指定g后,基于LRU(Least Recently Used)法自动删除不用的~存? memcached本n是ؓ~存而设计的服务器,因此q没有过多考虑数据的永久性问题? 关于内存存储的详l信息,本连载的W二讲以后前坂会q行介绍Q请届时参考?/p>
memcached管?#8220;分布?#8221;~存服务器,但服务器端ƈ没有分布式功能? 各个memcached不会互相通信以共享信息。那么,怎样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安装卛_?/p>
$ sudo yum install libevent libevent-devel
memcached的源代码可以从memcached|站上下载。本文执W时的最新版本ؓ1.2.5? Fedora 8虽然也包含了memcached的rpmQ但版本比较老。因为源代码安装q不困难Q? q里׃使用rpm了?/p>
memcached安装与一般应用程序相同,configure、make、make installp了?/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里昄了调试信息。这样就在前台启动了memcachedQ监听TCP端口11211 最大内存用量?4M。调试信息的内容大部分是关于存储的信息, 下次q蝲时具体说明?/p>
作ؓdaemon后台启动Ӟ只需
$ /usr/local/bin/memcached -p 11211 -m 64m -d
q里使用的memcached启动选项的内容如下?/p>
选项 | 说明 |
-p | 使用的TCP端口。默认ؓ11211 |
-m | 最大内存大。默认ؓ64M |
-vv | 用very vrebose模式启动Q调试信息和错误输出到控制台 |
-d | 作ؓdaemon在后台启?/td> |
上面四个是常用的启动选项Q其他还有很多,通过
$ /usr/local/bin/memcached -h
命o可以昄。许多选项可以改变memcached的各U行为, 推荐M诅R?/p>
许多语言都实Cq接memcached的客LQ其中以Perl、PHPZ? 仅仅memcached|站上列出的语言有
{等?/p>
q里介绍通过mixi正在使用的Perl库链接memcached的方法?/p>
Perl的memcached客户端有
{几个CPAN模块。这里介l的Cache::Memcached是memcached的作者Brad Fitzpatric的作品, 应该是memcached的客L中应用最为广泛的模块了?/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指定了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Ҏ?/p>
my $val = $memcached->get('?);
my $val = $memcached->get_multi('?', '?', '?', '?', '?');
一ơ取得多条数据时使用get_multi。get_multi可以非同步地同时取得多个键| 光度要比循环调用get快数十倍?/p>
删除数据使用deleteҎ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不会自动赋?。因此, 应当q行错误查,必要时加入初始化操作。而且Q服务器端也不会? 过2<sup>32</sup>时的行ؓq行查?/p>
q次单介l了memcachedQ以及它的安装方法、Perl客户端Cache::Memcached的用法? 只要知道Qmemcached的用方法十分简单就_了?/p>
下次由前坂来说明memcached的内部结构。了解memcached的内部构造, p知道如何使用memcached才能使Web应用的速度更上一层楼? Ƣ迎l箋阅读下一章?/p>
下面是《memcached全面剖析》的W二部分?/p>
发表日:2008/7/9
作者:前坂?Toru Maesaka)
原文链接Q?a >http://gihyo.jp/dev/feature/01/memcached/0002
我是mixi株式会社研究开发组的前坂徹? 上次的文章介l了memcached是分布式的高速缓存服务器? 本次介lmemcached的内部构造的实现方式Q以及内存的理方式? 另外Qmemcached的内部构造导致的q也将加以说明?/p>
最q的memcached默认情况下采用了名ؓSlab Allocator的机制分配、管理内存? 在该机制出现以前Q内存的分配是通过Ҏ有记录简单地q行malloc和free来进行的? 但是Q这U方式会D内存片Q加重操作系l内存管理器的负担,最坏的情况下, 会导致操作系l比memcachedq程本nq慢。Slab Allocator是册问题而诞生的?/p>
下面来看看Slab Allocator的原理。下面是memcached文档中的slab allocator的目标:
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的集合)Q图1Q?/p>
? Slab Allocation的构造图
而且Qslab allocatorq有重复使用已分配的内存的目的? 也就是说Q分配到的内存不会释放,而是重复利用?/p>
Page
分配lSlab的内存空_默认?MB。分配给Slab之后Ҏslab的大切分成chunk?/p>
Chunk
用于~存记录的内存空间?/p>
Slab Class
特定大小的chunk的组?/p>
下面说明memcached如何针对客户端发送的数据选择slabq缓存到chunk中?/p>
memcachedҎ收到的数据的大小Q选择最适合数据大小的slabQ图2Q? memcached中保存着slab内空闲chunk的列表,Ҏ该列表选择chunkQ? 然后数据缓存于其中?/p>
? 选择存储记录的组的方?/p>
实际上,Slab Allocator也是有利也有弊。下面介l一下它的缺炏V?/p>
Slab Allocator解决了当初的内存片问题Q但新的机制也给memcached带来了新的问题?/p>
q个问题是Q由于分配的是特定长度的内存Q因此无法有效利用分配的内存? 例如Q将100字节的数据缓存到128字节的chunk中,剩余?8字节浪费了Q图3Q?/p>
? chunkI间的?/p>
对于该问题目前还没有完美的解x案,但在文档中记载了比较有效的解x案?/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.
是_如果预先知道客户端发送的数据的公用大,或者仅~存大小相同的数据的情况下, 只要使用适合数据大小的组的列表,可以减浪贏V?/p>
但是很遗憾,现在q不能进行Q何调优,只能期待以后的版本了? 但是Q我们可以调节slab class的大的差别? 接下来说明growth factor选项?/p>
memcached在启动时指定 Growth Factor因子Q通过-f选项Q, 可以在某种E度上控制slab之间的差异。默认gؓ1.25? 但是Q在该选项出现之前Q这个因子曾l固定ؓ2Q称?#8220;powers of 2”{略?/p>
让我们用以前的设|,以verbose模式启动memcached试试看:
$ 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ؓ量减少内存费Q两q前q加了growth factorq个选项?/p>
来看看现在的默认讄Qf=1.25Q时的输出(幅所限,q里只写到第10l)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可能会觉得有些计算误差Q? q些误差是ؓ了保持字节数的对齐而故意设|的?/p>
memcached引入产品Q或是直接用默认D行部|时Q? 最好是重新计算一下数据的预期q_长度Q调整growth factorQ? 以获得最恰当的设|。内存是珍贵的资源,费太可惜了?/p>
接下来介l一下如何用memcached的stats命o查看slabs的利用率{各U各L信息?/p>
memcached有个名ؓstats的命令,使用它可以获得各U各L信息? 执行命o的方法很多,用telnet最为简单:
$ telnet L?端口?/pre>q接到memcached之后Q输入stats再按回RQ即可获得包括资源利用率在内的各U信息? 此外Q输?stats slabs"?stats items"q可以获得关于缓存记录的信息? l束E序误入quit?/p>
q些命o的详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如果安装了libmemcachedq个面向C/C++语言的客L库,׃安装 memstat q个命o? 使用Ҏ很简单,可以用更的步骤获得与telnet相同的信息,q能一ơ性从多台服务器获得信息?/p>
$ memstat --servers=server1,server2,server3,...libmemcached可以从下面的地址获得Q?/p>
使用memcached的创造着Brad写的名ؓmemcached-tool的Perl脚本Q可以方便地获得slab的用情? Q它memcached的返回值整理成Ҏ阅读的格式)。可以从下面的地址获得脚本Q?/p>
使用Ҏ也极其简单:
$ memcached-tool L?端口 选项
查看slabs使用状况时无需指定选项Q因此用下面的命令即可:
$ memcached-tool L?端口
获得的信息如下所C:
# 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
各列的含义ؓQ?/p>
?/td> | 含义 |
# | slab class~号 |
Item_Size | Chunk大小 |
Max_age | LRU内最旧的记录的生存时?/td> |
1MB_pages | 分配lSlab的页?/td> |
Count | Slab内的记录?/td> |
Full? | Slab内是否含有空闲chunk |
从这个脚本获得的信息对于调优非常方便Q强烈推荐用?/p>
本次单说明了memcached的缓存机制和调优Ҏ? 希望读者能理解memcached的内存管理原理及其优~点?/p>
下次l说明LRU和Expire{原理,以及memcached的最新发展方向—? 可扩充体p(pluggable architecherQ)?/p>
下面是《memcached全面剖析》的W三部分?/p>
发表日:2008/7/16
作者:前坂?Toru Maesaka)
原文链接Q?a >http://gihyo.jp/dev/feature/01/memcached/0003
memcached是缓存,所以数据不会永久保存在服务器上Q这是向pȝ中引入memcached的前提? 本次介绍memcached的数据删除机Ӟ以及memcached的最新发展方向——二q制协议QBinary ProtocolQ? 和外部引擎支持?/p>
上次介绍q, memcached不会释放已分配的内存。记录超时后Q客L无法再看见该记录(invisibleQ透明Q, 其存储空间即可重复用?/p>
memcached内部不会监视记录是否q期Q而是在get时查看记录的旉戻I查记录是否过期? q种技术被UCؓlazyQ惰性)expiration。因此,memcached不会在过期监视上耗费CPU旉?/p>
memcached会优先用已时的记录的I间Q但即如此Q也会发生追加新记录时空间不的情况Q? 此时p使用名ؓ Least Recently UsedQLRUQ机制来分配I间? 思义Q这是删?#8220;最q最?#8221;的记录的机制? 因此Q当memcached的内存空间不xQ无法从slab class 获取到新的空间时Q,׃最q未被用的记录中搜索,q将其空间分配给新的记录? 从缓存的实用角度来看Q该模型十分理想?/p>
不过Q有些情况下LRU机制反倒会造成ȝ。memcached启动旉过“-M”参数可以止LRUQ如下所C:
$ memcached -M -m 1024
启动时必L意的是,写?#8220;-m”选项是用来指定最大内存大的。不指定具体数值则使用默认?4MB?/p>
指定“-M”参数启动后,内存用尽时memcached会返回错误? 话说回来Qmemcached毕竟不是存储器,而是~存Q所以推荐用LRU?/p>
memcached的roadmap上有两个大的目标。一个是二进制协议的{划和实玎ͼ另一个是外部引擎的加载功能?/p>
使用二进制协议的理由是它不需要文本协议的解析处理Q得原本高速的memcached的性能更上一层楼Q? q能减少文本协议的漏z。目前已大部分实玎ͼ开发用的代码库中已包含了该功能? memcached的下载页面上有代码库的链接?/p>
协议的包?4字节的Q其后面是键和无l构数据QUnstructured DataQ? 实际的格式如下(引自协议文档Q:
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)分ؓ h_Request HeaderQ和响应_Response HeaderQ两U? 头部中包含了表示包的有效性的Magic字节、命令种cR键长度、值长度等信息Q格式如下:
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 |
| |
+---------------+---------------+---------------+---------------+
如希望了解各个部分的详细内容Q可以checkout出memcached的二q制协议的代码树Q? 参考其中的docs文g夹中的protocol_binary.txt文档?/p>
看到HEADER格式后我的感xQ键的上限太大了Q现在的memcached规格中,键长度最大ؓ250字节Q? 但二q制协议中键的大用2字节表示。因此,理论上最大可使用65536字节Q?<sup>16</sup>Q长的键? 管250字节以上的键q不会太常用Q二q制协议发布之后可以用巨大的键了?/p>
二进制协议从下一版本1.3pd开始支持?/p>
我去q曾l试验性地memcached的存储层攚w成了可扩展的(pluggableQ?/p>
MySQL的Brian Aker看到q个攚w之后,将代码发到了memcached的邮件列表?
memcached的开发者也十分感兴,放Croadmap中。现在由我和
memcached的开发者Trond Norbye协同开发(规格设计、实现和试Q?
和国外协同开发时时差是个大问题,但抱着相同的愿景,
最后终于可以将可扩展架构的原型公布了?
代码库可以从memcached的下载页?/a>
上访问?/p>
世界上有许多memcached的派生YӞ其理由是希望怹保存数据、实现数据冗余等Q?
即牺牲一些性能也在所不惜。我在开发memcached之前Q在mixi的研发部也曾l?
考虑q重新发明memcached?/p>
外部引擎的加载机制能装memcached的网l功能、事件处理等复杂的处理?
因此Q现阶段通过强制手段或重新设计等方式使memcached和存储引擎合作的困难
׃烟消云散Q尝试各U引擎就会变得轻而易举了?/p>
该项目中我们最重视的是API设计。函数过多,会引擎开发者感到麻烦;
q于复杂Q实现引擎的门槛׃q高。因此,最初版本的接口函数只有13个?
具体内容限于幅Q这里就省略了,仅说明一下引擎应当完成的操作Q?/p>
对详l规格有兴趣的读者,可以checkout engine目的代码,阅读器中的engine.h?/p>
memcached支持外部存储的难ҎQ网l和事g处理相关的代码(核心服务器)?
内存存储的代码紧密关联。这U现象也UCؓtightly coupledQ紧密耦合Q?
必须内存存储的代码从核心服务器中独立出来,才能灉|地支持外部引擎?
因此Q基于我们设计的APIQmemcached被重构成下面的样子: 重构之后Q我们与1.2.5版、二q制协议支持版等q行了性能ҎQ证实了它不会造成性能影响?/p>
在考虑如何支持外部引擎加蝲Ӟ让memcachedq行q行控制Qconcurrency controlQ的Ҏ是最为容易的Q?
但是对于引擎而言Qƈ行控制正是性能的真谛,因此我们采用了将多线E支持完全交l引擎的设计Ҏ?/p>
以后的改q,会得memcached的应用范围更为广泛?/p>
本次介绍了memcached的超时原理、内部如何删除数据等Q在此之上又介绍了二q制协议?
外部引擎支持{memcached的最新发展方向。这些功能要?.3版才会支持,敬请期待Q?/p>
q是我在本连载中的最后一。感谢大安L的文章! 下次由长野来介绍memcached的应用知识和应用E序兼容性等内容?/p>
发表日:2008/7/23 外部引擎支持的必要?/h3>
单API设计的成功的关键
重新审视现在的体p?/h3>
ȝ
4. memcached的分布式法
作者:镉K雅广(Masahiro Nagano)
原文链接Q?a >http://gihyo.jp/dev/feature/01/memcached/0004
我是Mixi的长野?
W??/a>?
W??/a>
由前坂介l了memcached的内部情c本ơ不再介lmemcached的内部结构,
开始介lmemcached的分布式?/p>
正如W??/a>中介l的那样Q?
memcached虽然UCؓ“分布?#8221;~存服务器,但服务器端ƈ没有“分布?#8221;功能?
服务器端仅包?
W??/a>?
W??/a>
前坂介绍的内存存储功能,其实现非常简单?
至于memcached的分布式Q则是完全由客户端程序库实现的?
q种分布式是memcached的最大特炏V?/p>
q里多次使用?#8220;分布?#8221;q个词,但ƈ未做详细解释?
现在开始简单地介绍一下其原理Q各个客L的实现基本相同?/p>
下面假设memcached服务器有node1~node3三台Q?
应用E序要保存键名ؓ“tokyo”“kanagawa”“chiba”“saitama”“gunma”
的数据?/p>
? 分布式简介:准备 首先向memcached中添?#8220;tokyo”。将“tokyo”传给客户端程序库后,
客户端实现的法׃Ҏ“?#8221;来决定保存数据的memcached服务器?
服务器选定后,卛_令它保存“tokyo”及其倹{?/p>
? 分布式简介:d?/p>
同样Q?#8220;kanagawa”“chiba”“saitama”“gunma”都是先选择服务器再保存?/p>
接下来获取保存的数据。获取时也要要获取的键“tokyo”传递给函数库?
函数库通过与数据保存时相同的算法,Ҏ“?#8221;选择服务器?
使用的算法相同,p选中与保存时相同的服务器Q然后发送get命o?
只要数据没有因ؓ某些原因被删除,p获得保存的倹{?/p>
? 分布式简介:获取?/p>
q样Q将不同的键保存C同的服务器上Q就实现了memcached的分布式?
memcached服务器增多后Q键׃分散Q即使一台memcached服务器发生故?
无法q接Q也不会影响其他的缓存,pȝ依然能l运行?/p>
接下来介l?a >W??/a>
中提到的Perl客户端函数库Cache::Memcached实现的分布式Ҏ?/p>
Perl的memcached客户端函数库Cache::Memcached?
memcached的作者Brad Fitzpatrick的作品,可以说是原装的函数库了?/p>
该函数库实现了分布式功能Q是memcached标准的分布式Ҏ?/p>
Cache::Memcached的分布式Ҏ单来_是“Ҏ服务器台数的余数q行分散”?
求得键的整数哈希|再除以服务器台数Q根据其余数来选择服务器?/p>
下面Cache::Memcached化成以下的Perl脚本来进行说明?/p>
Cache::Memcached在求哈希值时使用了CRC?/p>
首先求得字符串的CRC|Ҏ该值除以服务器节点数目得到的余数决定服务器?
上面的代码执行后输入以下l果Q?/p>
Ҏ该结果,“tokyo”分散到node2Q?#8220;kanagawa”分散到node3{?
多说一句,当选择的服务器无法q接ӞCache::Memcached会将q接ơ数
d到键之后Q再ơ计哈希值ƈ试q接。这个动作称为rehash?
不希望rehash时可以在生成Cache::Memcached对象时指?#8220;rehash => 0”选项?/p>
余数计算的方法简单,数据的分散性也相当优秀Q但也有其缺炏V?
那就是当d或移除服务器Ӟ~存重组的代L当巨大?
d服务器后Q余数就会生巨变,q样无法获取与保存时相同的服务器,
从而媄响缓存的命中率。用Perl写段代码来验证其代h?/p>
q段Perl脚本演示了将“a”?#8220;z”的键保存到memcachedq访问的情况?
其保存为mod.plq执行?/p>
首先Q当服务器只有三台时Q?/p>
l果如上Qnode1保存a、c、d、e……Qnode2保存g、i、k……Q?
每台服务器都保存?个到10个数据?/p>
接下来增加一台memcached服务器?/p>
d了node4。可见,只有d、i、k、p、r、y命中了。像q样Q添加节点后
键分散到的服务器会发生巨大变化?6个键中只有六个在讉K原来的服务器Q?
其他的全都移C其他服务器。命中率降低?3%。在Web应用E序中用memcachedӞ
在添加memcached服务器的瞬间~存效率会大q度下降Q负载会集中到数据库服务器上Q?
有可能会发生无法提供正常服务的情c?/p>
mixi的Web应用E序q用中也有这个问题,D无法dmemcached服务器?
但由于用了新的分布式方法,现在可以轻而易丑֜dmemcached服务器了?
q种分布式方法称?Consistent Hashing?/p>
关于Consistent Hashing的思想Qmixi株式会社的开发blog{许多地斚w介绍q,
q里只简单地说明一下?/p>
Consistent Hashing如下所C:首先求出memcached服务器(节点Q的哈希|
q将光|到0?32的圆QcontinuumQ上?
然后用同LҎ求出存储数据的键的哈希|q映到圆上?
然后从数据映到的位|开始顺旉查找Q将数据保存到找到的W一个服务器上?
如果过232仍然找不到服务器Q就会保存到W一台memcached服务器上?/p>
? Consistent HashingQ基本原?/p>
从上囄状态中d一台memcached服务器。余数分布式法׃保存键的服务器会发生巨大变化
而媄响缓存的命中率,但Consistent Hashing中,只有在continuum上增加服务器的地炚w时针方向的
W一台服务器上的键会受到影响?/p>
? Consistent HashingQ添加服务器 因此QConsistent Hashing最大限度地抑制了键的重新分布?
而且Q有的Consistent Hashing的实现方法还采用了虚拟节点的思想?
使用一般的hash函数的话Q服务器的映地点的分布非常不均匀?
因此Q用虚拟节点的思想Qؓ每个物理节点Q服务器Q?
在continuum上分?00?00个点。这样就能抑制分布不均匀Q?
最大限度地减小服务器增减时的缓存重新分布?/p>
通过下文中介l的使用Consistent Hashing法的memcached客户端函数库q行试的结果是Q?
由服务器台数QnQ和增加的服务器台数QmQ计增加服务器后的命中率计公式如下: (1 - n/(n+m)) * 100 本连载中多次介绍的Cache::Memcached虽然不支持Consistent HashingQ?
但已有几个客L函数库支持了q种新的分布式算法?
W一个支持Consistent Hashing和虚拟节点的memcached客户端函数库?
名ؓ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重新实现了libketamaQ?
使用Consistent Hashing创徏对象时可以指定ketama_points选项?/p>
另外QCache::Memcached::libmemcached 是一个用了Brain Aker开发的C函数库libmemcached的Perl模块?
libmemcached本n支持几种分布式算法,也支持Consistent HashingQ?
其Perll定也支持Consistent Hashing?/p>
本次介绍了memcached的分布式法Q主要有memcached的分布式是由客户端函数库实现Q?
以及高效率地分散数据的Consistent Hashing法。下ơ将介绍mixi在memcached应用斚w的一些经验,
和相关的兼容应用E序?/p>
发表日:2008/7/30 我是Mixi的长野。memcached的连载终于要l束了?
?a >上次memcached的分布式
memcached的分布式是什么意思?
Cache::Memcached的分布式Ҏ
Ҏ余数计算分散
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 ]; # Ҏ余数选择服务?br />
printf "%s => %s"n", $key, $server;
}tokyo => node2
kanagawa => node3
chiba => node2
saitama => node1
gunma => node1Ҏ余数计算分散的缺?/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序
作者:镉K雅广(Masahiro Nagano)
原文链接Q?a >http://gihyo.jp/dev/feature/01/memcached/0005
mixi在提供服务的初期阶段׃用了memcached? 随着|站讉K量的急剧增加Q单Uؓ数据库添加slave已无法满需要,因此引入了memcached? 此外Q我们也从增加可扩展性的斚wq行了验证,证明了memcached的速度和稳定性都能满需要? 现在Qmemcached已成为mixi服务中非帔R要的l成部分?/p>
? 现在的系l组?/p>
mixi使用了许许多多服务器Q如数据库服务器、应用服务器、图片服务器? 反向代理服务器等。单单memcached有近200台服务器在运行? memcached服务器的典型配置如下Q?/p>
q些服务器以前曾用于数据库服务器{。随着CPU性能提升、内存hg降, 我们U极地将数据库服务器、应用服务器{换成了性能更强大、内存更多的服务器? q样Q可以抑制mixi整体使用的服务器数量的急剧增加Q降低管理成本? ׃memcached服务器几乎不占用CPUQ就换下来的服务器用作memcached服务器了?/p>
每台memcached服务器仅启动一个memcachedq程。分配给memcached的内存ؓ3GBQ? 启动参数如下Q?/p>
/usr/bin/memcached -p 11211 -u nobody -m 3000 -c 30720
׃使用了x86_64的操作系l,因此能分?GB以上的内存?2位操作系l中Q? 每个q程最多只能?GB内存。也曄考虑q启动多个分?GB以下内存的进E, 但这样一台服务器上的TCPq接数就会成倍增加,理上也变得复杂Q? 所以mixiq一使用?4位操作系l?/p>
另外Q虽然服务器的内存ؓ4GBQ却仅分配了3GBQ是因ؓ内存分配量超q这个|
有可能D内存交换(swap)。连载的W??/a>?
前坂讲解q了memcached的内存存?#8220;slab allocator”Q当时说q,memcached启动?
指定的内存分配量是memcached用于保存数据的量Q没有包?#8220;slab allocator”本n占用的内存?
以及Z保存数据而设|的理I间。因此,memcachedq程的实际内存分配量要比
指定的容量要大,q一点应当注意?/p>
mixi保存在memcached中的数据大部分都比较。这Pq程的大要?
指定的容量大很多。因此,我们反复改变内存分配量进行验证,
认?GB的大不会引发swapQ这是现在应用的数倹{?/p>
现在Qmixi的服务将200台左右的memcached服务器作Z个pool使用?
每台服务器的定w?GBQ那么全体就有了近600GB的巨大的内存数据库?
客户端程序库使用了本q蝲中多ơ提到R的Cache::Memcached::FastQ?
与服务器q行交互。当Ӟ~存的分布式法使用的是
W??/a>介绍q的
Consistent Hashing法?/p>
应用层上memcached的用方法由开发应用程序的工程师自行决定ƈ实现?
但是Qؓ了防止R轮再造、防止Cache::Memcached::Fast上的教训再次发生Q?
我们提供了Cache::Memcached::Fast的wrap模块q用?/p>
Cache::Memcached的情况下Q与memcached的连接(文g句柄Q保存在Cache::Memcached包内的类变量中?
在mod_perl和FastCGI{环境下Q包内的变量不会像CGI那样随时重新启动Q?
而是在进E中一直保持。其l果是不会断开与memcached的连接,
减少了TCPq接建立时的开销Q同时也能防止短旉内反复进行TCPq接、断开
而导致的TCP端口资源枯竭?/p>
但是QCache::Memcached::Fast没有q个功能Q所以需要在模块之外
Cache::Memcached::Fast对象保持在类变量中,以保证持久连接?/p>
上面的例子中QCache::Memcached::Fast对象保存到类变量$fast中?/p>
诸如mixi的主上的新闻这L所有用户共享的~存数据、设|信息等数据Q?
会占用许多页Q访问次C非常多。在q种条g下,讉K很容易集中到某台memcached服务器上?
讉K集中本nq不是问题,但是一旦访问集中的那台服务器发生故障导致memcached无法q接Q?
׃产生巨大的问题?/p>
q蝲?a >W??/a>
中提刎ͼCache::Memcached拥有rehash功能Q即在无法连接保存数据的服务器的情况下,
会再ơ计hash|q接其他的服务器?/p>
但是QCache::Memcached::Fast没有q个功能。不q,它能够在q接服务器失败时Q?
短时间内不再q接该服务器的功能?/p>
在failure_timeoutU内发生max_failures以上ơ连接失败,׃再连接该memcached服务器?
我们的设|是1U钟3ơ以上?/p>
此外Qmixiqؓ所有用户共享的~存数据的键名设|命名规则,
W合命名规则的数据会自动保存到多台memcached服务器中Q?
取得时从中仅选取一台服务器。创函数库后Q就可以使memcached服务器故?
不再产生其他影响?/p>
到此为止介绍了memcached内部构造和函数库,接下来介l一些其他的应用l验?/p>
通常情况下memcachedq行得相当稳定,但mixi现在使用的最新版1.2.5
曄发生q几ơmemcachedq程L的情c架构上保证了即使有几台memcached故障
也不会媄响服务,不过对于memcachedq程L的服务器Q只要重新启动memcachedQ?
可以正常运行,所以采用了监视memcachedq程q自动启动的Ҏ?
于是使用了daemontools?/p>
daemontools是qmail的作者DJB开发的UNIX服务理工具集,
其中名ؓsupervise的程序可用于服务启动、停止的服务重启{?/p>
q里不介ldaemontools的安装了。mixi使用了以下的run脚本来启动memcached?/p>
mixi使用了名?#8220;nagios”的开源监视Y件来监视memcached?/p>
在nagios中可以简单地开发插Ӟ可以详细地监视memcached的get、add{动作?
不过mixi仅通过stats命o来确认memcached的运行状态?/p>
此外Qmixistats目录的结果通过rrdtool转化成图形,q行性能监视Q?
q将每天的内存用量做成报表Q通过邮g与开发者共享?/p>
q蝲中已介绍q,memcached的性能十分优秀。我们来看看mixi的实际案例?
q里介绍的图表是服务所使用的访问最为集中的memcached服务器?/p>
? h?/p>
? 量 ? TCPq接?/p>
从上至下依次求数、流量和TCPq接数。请求数最大ؓ15000qpsQ?
量辑ֈ400MbpsQ这时的q接数已过?0000个?
该服务器没有特别的硬Ӟ是开头介l的普通的memcached服务器?
此时的CPU利用率ؓQ?/p>
? CPU利用?/p>
可见Q仍然有idle的部分。因此,memcached的性能非常高,
可以作ؓWeb应用E序开发者放心地保存临时数据或缓存数据的地方?/p>
memcached的实现和协议都十分简单,因此有很多与memcached兼容的实现?
一些功能强大的扩展可以memcached的内存数据写到磁盘上Q实现数据的持久性和冗余?
q蝲W??/a>
介绍q,以后的memcached的存储层变成可扩展的(pluggableQ,逐渐支持q些功能?/p>
q里介绍几个与memcached兼容的应用程序?/p>
mixi使用了上q兼容应用程序中的Tokyo Tyrant。Tokyo Tyrant是^林开发的
Tokyo Cabinet DBM的网l接口。它有自q协议Q但也拥有memcached兼容协议Q?
也可以通过HTTPq行数据交换。Tokyo Cabinet虽然是一U将数据写到盘的实玎ͼ但速度相当快?/p>
mixiq没有将Tokyo Tyrant作ؓ~存服务器,而是它作ؓ保存键值对l合的DBMS来用?
主要作ؓ存储用户上次讉K旉的数据库来用。它与几乎所有的mixi服务都有养I
每次用户讉K面旉要更新数据,因此负荷相当高。MySQL的处理十分笨重,
单独使用memcached保存数据又有可能会丢失数据,所以引入了Tokyo Tyrant?
但无需重新开发客LQ只需原封不动C用Cache::Memcached::Fast卛_Q?
q也是优点之一。关于Tokyo Tyrant的详l信息,请参考本公司的开发blog?/p>
到本ơؓ止,“memcached全面剖析”pdq束了。我们介l了memcached的基、内部结构?
分散法和应用等内容。读完后如果您能对memcached产生兴趣Q就是我们的荣幸?
关于mixi的系l、应用方面的信息Q请参考本公司?a >开发blogmemcached使用Ҏ和客L
通过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