用到memcached,記下
memcached中儲存的資料都儲存在memcached內建的記憶體儲存空間中。
由於資料僅存在於記憶體中,因此重啟memcached、重啟作業系統會導致全部資料消失。
另外,內容容量達到指定值之後,就基於LRU(Least Recently Used)演算法自動刪除不使用的緩衝。
memcached本身是為緩衝而設計的伺服器,因此並沒有過多考慮資料的永久性問題。
memcached是“分布式”快取服務器,但伺服器端並沒有分布式功能。
各個memcached不會互相通訊以共用資訊。進行分布式完全取決於用戶端的實現。
memcached需要 libevent庫 #yum install libevent libevent-devel
$ wget http://www.danga.com/memcached/dist/memcached-1.×.×.tar.gz
$ tar zxf memcached-1.×.×.tar.gz
$ cd memcached-1.×.×$ ./configure
$ make
$ sudo make install
#/usr/local/bin/memcached -p 11211 -m 64m -d
選項 |
說明 |
-p |
使用的TCP連接埠。預設為11211 |
-m |
最大記憶體大小。預設為64M |
-vv |
用very vrebose模式啟動,調試資訊和錯誤輸出到控制台 |
-d |
作為daemon在後台啟動 |
memcached用戶端API
:http://www.danga.com/memcached/apis.bml
Perl的memcached用戶端有
- Cache::Memcached
- Cache::Memcached::Fast
- Cache::Memcached::libmemcached
等幾個CPAN模組。
http://search.cpan.org/dist/Cache-Memcached/
#!/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地址和一個選項,以產生執行個體。
Cache::Memcached常用的選項如下所示。
選項 |
說明 |
servers |
用數組指定memcached伺服器和連接埠 |
compress_threshold |
資料壓縮時使用的值 |
namespace |
指定添加到鍵的首碼 |
另外,Cache::Memcached通過Storable模組可以將Perl的複雜資料序列化之後再儲存,
因此散列、數組、對象等都可以直接儲存到memcached中。
儲存資料
向memcached儲存資料的方法有
- add
- replace
- set
它們的使用方法都相同:
my $add = $memcached->add( '鍵', '值', '期限' );
my $replace = $memcached->replace( '鍵', '值', '期限' );
my $set = $memcached->set( '鍵', '值', '期限' );
向memcached儲存資料時可以指定期限(秒)。不指定期限時,memcached按照LRU演算法儲存資料。
這三個方法的區別如下:
選項 |
說明 |
add |
僅當儲存空間中不存在鍵相同的資料時才儲存 |
replace |
僅當儲存空間中存在鍵相同的資料時才儲存 |
set |
與add和replace不同,無論何時都儲存 |
擷取資料
擷取資料可以使用get和get_multi方法。
my $val = $memcached->get('鍵');
my $val = $memcached->get_multi('鍵1', '鍵2', '鍵3', '鍵4', '鍵5');
一次取得多條資料時使用get_multi。get_multi可以非同步地同時取得多個索引值,
其速度要比迴圈調用get快數十倍。
刪除資料
刪除資料使用delete方法,不過它有個獨特的功能。
$memcached->delete('鍵', '阻塞時間(秒)');
刪除第一個參數指定的鍵的資料。第二個參數指定一個時間值,可以禁止使用同樣的鍵儲存新資料。
此功能可以用於防止快取資料的不完整。但是要注意,set函數忽視該阻塞,照常儲存資料
增一和減一操作
可以將memcached上特定的索引值作為計數器使用。
my $ret = $memcached->incr('鍵');
$memcached->add('鍵', 0) unless defined $ret;
增一和減一是原子操作,但未設定初始值時,不會自動賦成0。因此,
應當進行錯誤檢查,必要時加入初始化操作。
Cache::Memcached的分布式方法
Perl的memcached用戶端函數庫Cache::Memcached是
memcached的作者Brad Fitzpatrick的作品,可以說是原裝的函數庫了。
- Cache::Memcached - search.cpan.org
該函數庫實現了分布式功能,是memcached標準的分布式方法。
根據餘數計算分散
Cache::Memcached的分布式方法簡單來說,就是“根據伺服器台數的餘數進行分散”。
求得鍵的整數雜湊值,再除以伺服器台數,根據其餘數來選擇伺服器。
下面將Cache::Memcached簡化成以下的Perl指令碼來進行說明。
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値
my $mod = $crc % ( $#nodes + 1 );
my $server = $nodes[ $mod ]; # 根據餘數選擇伺服器
printf "%s => %s/n", $key, $server;
}
Cache::Memcached在求雜湊值時使用了CRC。
- String::CRC32 - search.cpan.org
首先求得字串的CRC值,根據該值除以伺服器節點數目得到的餘數決定伺服器。
上面的代碼執行後輸入以下結果:
tokyo => node2
kanagawa => node3
chiba => node2
saitama => node1
gunma => node1
根據該結果,“tokyo”分散到node2,“kanagawa”分散到node3等。
多說一句,當選擇的伺服器無法串連時,Cache::Memcached會將串連次數
添加到鍵之後,再次計算雜湊值並嘗試串連。這個動作稱為rehash。
不希望rehash時可以在產生Cache::Memcached對象時指定“rehash => 0”選項。
根據餘數計算分散的缺點
餘數計算的方法簡單,資料的分散性也相當優秀,但也有其缺點。
那就是當添加或移除伺服器時,緩衝重組的代價相當巨大。
添加伺服器後,餘數就會產生巨變,這樣就無法擷取與儲存時相同的伺服器,
從而影響緩衝的命中率。用Perl寫段代碼來驗證其代價。
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} };
}
這段Perl指令碼示範了將“a”到“z”的鍵儲存到memcached並訪問的情況。
將其儲存為mod.pl並執行。
首先,當伺服器只有三台時:
$ 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
結果如上,node1儲存a、c、d、e……,node2儲存g、i、k……,
每台伺服器都儲存了8個到10個資料。
接下來增加一台memcached伺服器。
$ 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,z
添加了node4。可見,只有d、i、k、p、r、y命中了。像這樣,添加節點後
鍵分散到的伺服器會發生巨大變化。26個鍵中只有六個在訪問原來的伺服器,
其他的全都移到了其他伺服器。命中率降低到23%。在Web應用程式中使用memcached時,
在添加memcached伺服器的瞬間緩衝效率會大幅度下降,負載會集中到資料庫伺服器上,
有可能會發生無法提供正常服務的情況。
mixi的Web應用程式運用中也有這個問題,導致無法添加memcached伺服器。
但由於使用了新的分布式方法,現在可以輕而易舉地添加memcached伺服器了。
這種分布式方法稱為 Consistent Hashing。
Consistent Hashing
關於Consistent Hashing的思想,mixi株式會社的開發blog等許多地方都介紹過,
這裡只簡單地說明一下。
- mixi Engineers' Blog - スマートな分散で快適キャッシュライフ
- ConsistentHashing - コンシステント ハッシュ法
Consistent Hashing的簡單說明
Consistent Hashing如下所示:首先求出memcached伺服器(節點)的雜湊值,
並將其配置到0~232
的圓(continuum)上。
然後用同樣的方法求出儲存資料的鍵的雜湊值,並映射到圓上。
然後從資料對應到的位置開始順時針尋找,將資料儲存到找到的第一個伺服器上。
如果超過232
仍然找不到伺服器,就會儲存到第一台memcached伺服器上。
圖4 Consistent Hashing:基本原理
從的狀態中添加一台memcached伺服器。餘數分布式演算法由於儲存鍵的伺服器會發生巨大變化
而影響緩衝的命中率,但Consistent Hashing中,只有在continuum上增加伺服器的地點逆時針方向的
第一台伺服器上的鍵會受到影響。
圖5 Consistent Hashing:添加伺服器
因此,Consistent Hashing最大限度地抑制了鍵的重新分配。
而且,有的Consistent Hashing的實現方法還採用了虛擬節點的思想。
使用一般的hash函數的話,伺服器的映射地點的分布非常不均勻。
因此,使用虛擬節點的思想,為每個物理節點(伺服器)
在continuum上分配100~200個點。這樣就能抑制分布不均勻,
最大限度地減小伺服器增減時的緩衝重新分配。
通過下文中介紹的使用Consistent Hashing演算法的memcached用戶端函數庫進行測試的結果是,
由伺服器台數(n)和增加的伺服器台數(m)計算增加伺服器後的命中率計算公式如下:
(1 - n/(n+m)) * 100
支援Consistent Hashing的函數庫
本連載中多次介紹的Cache::Memcached雖然不支援Consistent Hashing,
但已有幾個用戶端函數庫支援了這種新的分布式演算法。
第一個支援Consistent Hashing和虛擬節點的memcached用戶端函數庫是
名為libketama的PHP庫,由last.fm開發。
- libketama - a consistent hashing algo for memcache clients – RJ ブログ - Users at Last.fm
至於Perl用戶端,連載的第1次
中介紹過的Cache::Memcached::Fast和Cache::Memcached::libmemcached支援
Consistent Hashing。
- Cache::Memcached::Fast - search.cpan.org
- Cache::Memcached::libmemcached - search.cpan.org
兩者的介面都與Cache::Memcached幾乎相同,如果正在使用Cache::Memcached,
那麼就可以方便地替換過來。Cache::Memcached::Fast重新實現了libketama,
使用Consistent Hashing建立對象時可以指定ketama_points選項。
my $memcached = Cache::Memcached::Fast->new({
servers => ["192.168.0.1:11211","192.168.0.2:11211"],
ketama_points => 150
});
另外,Cache::Memcached::libmemcached 是一個使用了Brain Aker開發的C函數庫libmemcached的Perl模組。
libmemcached本身支援幾種分布式演算法,也支援Consistent Hashing,
其Perl綁定也支援Consistent Hashing。
- Tangent Software: libmemcached
曆史上的今天:網站安全
2008-07-29收藏到:Del.icio.us