Memcached與Libmemcached介紹及其簡單使用
如何通過原始碼先大體學習庫忽略具體實現細節呢?
1、首先學會庫中開放出來程式設計師可呼叫函式API,學習其引數配置,大體先忽略被庫內部的呼叫大量函式。
2、找出管理資源超級重要的結構體,從其入手。
1、Memcached
介紹
memcached是一個高效能的記憶體快取物件系統,其實質為一個鍵值對的hashmap索引,其事件處理和網路通訊均是基於libevent。memcached區別於libevent,因為memcached是一個執行程式,不需要編譯成動態連線庫,供其他程式呼叫。memcached通常作為C/S模型中的S,也就是伺服器端,客戶端通過命令快取資料。
基本特點:
- 協議簡單:使用基於文字行的協議,二進位制協議使用比較少。
- 基於記憶體儲存:資料儲存在記憶體中,所以讀取速度很快。
- 事件處理:基於libevent開發,所以可以應對C10問題。
- 不互相通訊的分散式:多臺memcached伺服器之間不互相通訊,由客戶端實現分散式演算法,所以通常客戶端使用一致性hash策略,通常擁有快隔離,慢恢復的特性。
安裝與啟動
memcached區別於libevent,因為memcached是一個執行程式,不需要編譯成動態連線庫,供其他程式呼叫。所以不需要指定最後庫檔案生成的目錄,僅僅需要指定memcached應用程式放置的目錄,以及編譯過程中libevent庫檔案的目錄。
本機設定應用程式防止預設目錄/usr/local/bin
libevent庫目錄為
/usr/loacl/bin
。因此安裝很容易了。
ar -zxv -f memcached-1.4.21.tar.gz
cd memcached-1.4.21
./configure --with-libevent=/usr/local/bin CFLAGS="-g -O0"//指定libevent庫目錄以及 編譯成debug版本。
make
make install//install之後,在/usr/local/bin會出現memcached應用程式。
//下面是make install之後的輸出,可以看到。
1、memcached.1 放到了 '/usr/local/share/man/man1' ,以後可以通過man memcached訪問幫助文件。
2、protocol_binary.h協議標頭檔案放到了 '/usr/local/include/memcached'
memcached可執行檔案放到了'/usr/local/bin'
3、通常一個開原始碼,裡面會有man資料夾,也就是通過man程式可以開啟的文件,libmemcached-1.0.18裡面一樣有,通常make install會將這些檔案都放到Linux對應的資料夾,然後就可以通過man尋找幫助資訊了,很方便。
make install-recursive
make[1]: Entering directory '/home/wangjun/Desktop/memcached-1.4.21'
Making install in doc
make[2]: Entering directory '/home/wangjun/Desktop/memcached-1.4.21/doc'
make install-am
make[3]: Entering directory '/home/wangjun/Desktop/memcached-1.4.21/doc'
make[4]: Entering directory '/home/wangjun/Desktop/memcached-1.4.21/doc'
make[4]: Nothing to be done for 'install-exec-am'.
/bin/mkdir -p '/usr/local/share/man/man1'
/usr/bin/install -c -m 644 memcached.1 '/usr/local/share/man/man1'
make[4]: Leaving directory '/home/wangjun/Desktop/memcached-1.4.21/doc'
make[3]: Leaving directory '/home/wangjun/Desktop/memcached-1.4.21/doc'
make[2]: Leaving directory '/home/wangjun/Desktop/memcached-1.4.21/doc'
make[2]: Entering directory '/home/wangjun/Desktop/memcached-1.4.21'
make[3]: Entering directory '/home/wangjun/Desktop/memcached-1.4.21'
/bin/mkdir -p '/usr/local/bin'
/usr/bin/install -c memcached '/usr/local/bin'
/bin/mkdir -p '/usr/local/include/memcached'
/usr/bin/install -c -m 644 protocol_binary.h '/usr/local/include/memcached'
make[3]: Leaving directory '/home/wangjun/Desktop/memcached-1.4.21'
make[2]: Leaving directory '/home/wangjun/Desktop/memcached-1.4.21'
make[1]: Leaving directory '/home/wangjun/Desktop/memcached-1.4.21'
啟動:
簡單的啟動命令如下,設定-l和-p分別用來設定ip和監聽的埠。-vv是輸出一些執行資訊。
$memcached -l 192.168.1.112 -p 8888 -vv
-vv指示輸出相應的除錯資訊,看了原始碼就知道是怎麼回事了。
工具memcached-tool
#!/usr/bin/perl
#
# memcached-tool:
# stats/management tool for memcached.
#
# Author:
# Brad Fitzpatrick <[email protected]>
#
# License:
# public domain. I give up all rights to this
# tool. modify and copy at will.
#
use strict;
use IO::Socket::INET;
my $host = shift;
my $mode = shift || "display";
my ($from, $to);
if ($mode eq "display") {
undef $mode if @ARGV;
} elsif ($mode eq "move") {
$from = shift;
$to = shift;
undef $mode if $from < 6 || $from > 17;
undef $mode if $to < 6 || $to > 17;
print STDERR "ERROR: parameters out of range\n\n" unless $mode;
} elsif ($mode eq 'dump') {
;
} elsif ($mode eq 'stats') {
;
} else {
undef $mode;
}
undef $mode if @ARGV;
die
"Usage: memcached-tool <host[:port]> [mode]\n
memcached-tool 10.0.0.5:11211 display # shows slabs
memcached-tool 10.0.0.5:11211 # same. (default is display)
memcached-tool 10.0.0.5:11211 stats # shows general stats
memcached-tool 10.0.0.5:11211 move 7 9 # takes 1MB slab from class #7
# to class #9.
You can only move slabs around once memory is totally allocated, and only
once the target class is full. (So you can't move from #6 to #9 and #7
to #9 at the same itme, since you'd have to wait for #9 to fill from
the first reassigned page)
" unless $host && $mode;
$host .= ":11211" unless $host =~ /:\d+/;
my $sock = IO::Socket::INET->new(PeerAddr => $host,
Proto => 'tcp');
die "Couldn't connect to $host\n" unless $sock;
if ($mode eq "move") {
my $tries = 0;
while (1) {
print $sock "slabs reassign $from $to\r\n";
my $res = <$sock>;
$res =~ s/\s+//;
if ($res eq "DONE") {
print "Success.\n";
exit 0;
} elsif ($res eq "CANT") {
print "Error: can't move from $from to $to. Destination not yet full? See usage docs.\n";
exit;
} elsif ($res eq "BUSY") {
if (++$tries == 3) {
print "Failed to move after 3 tries. Try again later.\n";
exit;
}
print "Page busy, retrying...\n";
sleep 1;
}
}
exit;
}
if ($mode eq 'dump') {
my %items;
my $totalitems;
print $sock "stats items\r\n";
while (<$sock>) {
last if /^END/;
if (/^STAT items:(\d*):number (\d*)/) {
$items{$1} = $2;
$totalitems += $2;
}
}
print STDERR "Dumping memcache contents\n";
print STDERR " Number of buckets: " . scalar(keys(%items)) . "\n";
print STDERR " Number of items : $totalitems\n";
foreach my $bucket (sort(keys(%items))) {
print STDERR "Dumping bucket $bucket - " . $items{$bucket} . " total items\n";
print $sock "stats cachedump $bucket $items{$bucket} 1\r\n";
my %keyexp;
while (<$sock>) {
last if /^END/;
# return format looks like this
# ITEM foo [6 b; 1176415152 s]
if (/^ITEM (\S+) \[.* (\d+) s\]/) {
$keyexp{$1} = $2;
}
}
foreach my $k (keys(%keyexp)) {
my $val;
print $sock "get $k\r\n";
my $response = <$sock>;
$response =~ /VALUE (\S+) (\d+) (\d+)/;
my $flags = $2;
my $len = $3;
read $sock, $val , $len;
# get the END
$_ = <$sock>;
$_ = <$sock>;
print "add $k $flags $keyexp{$k} $len\r\n$val\r\n";
}
}
exit;
}
if ($mode eq 'stats') {
my %items;
print $sock "stats\r\n";
while (<$sock>) {
last if /^END/;
chomp;
if (/^STAT\s+(\S*)\s+(.*)/) {
$items{$1} = $2;
}
}
printf ("#%-17s %5s %11s\n", $host, "Field", "Value");
foreach my $name (sort(keys(%items))) {
printf ("%24s %12s\n", $name, $items{$name});
}
exit;
}
# display mode:
my %items; # class -> { number, age, chunk_size, chunks_per_page,
# total_pages, total_chunks, used_chunks,
# free_chunks, free_chunks_end }
print $sock "stats items\r\n";
while (<$sock>) {
last if /^END/;
if (/^STAT items:(\d+):(\w+) (\d+)/) {
$items{$1}{$2} = $3;
}
}
print $sock "stats slabs\r\n";
while (<$sock>) {
last if /^END/;
if (/^STAT (\d+):(\w+) (\d+)/) {
$items{$1}{$2} = $3;
}
}
print " # Item_Size Max_age 1MB_pages Count Full?\n";
foreach my $n (1..40) {
my $it = $items{$n};
next if (0 == $it->{total_pages});
my $size = $it->{chunk_size} < 1024 ? "$it->{chunk_size} B " :
sprintf("%.1f kB", $it->{chunk_size} / 1024.0);
my $full = $it->{free_chunks_end} == 0 ? "yes" : " no";
printf "%3d %8s %7d s %7d %7d %7s\n",
$n, $size, $it->{age}, $it->{total_pages},
$it->{number}, $full;
}
1、memcached-tool指令碼可以方便地獲得slab的使用情況。
2、使用方法也極其簡單:perl memcached-tool server_ip:prot option
。
3、有了這個工具就需要自己寫指令碼,連線客戶端,傳送相應的資訊了,這個就很容易使用了,其實獲取資訊的方法就是給伺服器端傳送相應的指令。
Memcached啟動命令列引數詳解
啟動Memcached時候,可以通過命令列引數配置。主要通過修改struct settings
中的變數值,修改整個memcached工作引數。以下介紹struct settings
結構體以及其預設初始值。
//原始碼內部使用的設定結構體
struct settings {
size_t maxbytes;
int maxconns;
int port;
int udpport;
char *inter;
int verbose;
rel_time_t oldest_live; /* ignore existing items older than this */
int evict_to_free;
char *socketpath; /* path to unix socket if using local socket */
int access; /* access mask (a la chmod) for unix domain socket */
double factor; /* chunk size growth factor */
int chunk_size;
int num_threads; /* number of worker (without dispatcher) libevent threads to run */
int num_threads_per_udp; /* number of worker threads serving each udp socket */
char prefix_delimiter; /* character that marks a key prefix (for stats) */
int detail_enabled; /* nonzero if we're collecting detailed stats */
int reqs_per_event; /* Maximum number of io to process on each
io-event. */
bool use_cas;
enum protocol binding_protocol;
int backlog;
int item_size_max; /* Maximum item size, and upper end for slabs */
bool sasl; /* SASL on/off */
bool maxconns_fast; /* Whether or not to early close connections */
bool lru_crawler; /* Whether or not to enable the autocrawler thread */
bool slab_reassign; /* Whether or not slab reassignment is allowed */
int slab_automove; /* Whether or not to automatically move slabs */
int hashpower_init; /* Starting hash power level */
bool shutdown_command; /* allow shutdown command */
int tail_repair_time; /* LRU tail refcount leak repair time */
bool flush_enabled; /* flush_all enabled */
char *hash_algorithm; /* Hash algorithm in use */
int lru_crawler_sleep; /* Microsecond sleep between items */
uint32_t lru_crawler_tocrawl; /* Number of items to crawl per run */
};
struct settings settings;//全域性結構體變數
//memcached的main函式啟動,首先會此函式,初始化預設設定。
static void settings_init(void) {
//開啟CAS業務,如果開啟了那麼在item裡面就會多一個用於CAS的欄位。可以在啟動memcached的時候通過-C選項禁用
settings.use_cas = true;
settings.access = 0700; //unix socket的許可權位資訊
settings.port = 11211;//memcached監聽的tcp埠
settings.udpport = 11211;//memcached監聽的udp埠
//memcached繫結的ip地址。如果該值為NULL,那麼就是INADDR_ANY。否則該值指向一個ip字串
settings.inter = NULL;
settings.maxbytes = 64 * 1024 * 1024; //memcached能夠使用的最大記憶體
settings.maxconns = 1024; //最多允許多少個客戶端同時線上。不同於settings.backlog
settings.verbose = 0;//執行資訊的輸出級別.該值越大輸出的資訊就越詳細
settings.oldest_live = 0; //flush_all命令的時間界限。插入時間小於這個時間的item刪除。
settings.evict_to_free = 1; //標記memcached是否允許LRU淘汰機制。預設是可以的。可以通過-M選項禁止
settings.socketpath = NULL;//unix socket監聽的socket路徑.預設不使用unix socket
settings.factor = 1.25; //item的擴容因子
settings.chunk_size = 48; //最小的一個item能儲存多少位元組的資料(set、add命令中的資料)
settings.num_threads = 4; //worker執行緒的個數
//多少個worker執行緒為一個udp socket服務 number of worker threads serving each udp socket
settings.num_threads_per_udp = 0;
settings.prefix_delimiter = ':'; //分隔符
settings.detail_enabled = 0;//是否自動收集狀態資訊
//worker執行緒連續為某個客戶端執行命令的最大命令數。這主要是為了防止一個客戶端霸佔整個worker執行緒
//,而該worker執行緒的其他客戶端的命令無法得到處理
settings.reqs_per_event = 20;
settings.backlog = 1024;//listen函式的第二個引數,不同於settings.maxconns
//使用者命令的協議,有檔案和二進位制兩種。negotiating_prot是協商,自動根據命令內容判斷
settings.binding_protocol = negotiating_prot;
settings.item_size_max = 1024 * 1024;//slab記憶體頁的大小。單位是位元組
settings.maxconns_fast = false;//如果連線數超過了最大同時線上數(由-c選項指定),是否立即關閉新連線上的客戶端。
//用於指明memcached是否啟動了LRU爬蟲執行緒。預設值為false,不啟動LRU爬蟲執行緒。
//可以在啟動memcached時通過-o lru_crawler將變數的值賦值為true,啟動LRU爬蟲執行緒
settings.lru_crawler = false;
settings.lru_crawler_sleep = 100;//LRU爬蟲執行緒工作時的休眠間隔。單位為微秒
settings.lru_crawler_tocrawl = 0; //LRU爬蟲檢查每條LRU佇列中的多少個item,如果想讓LRU爬蟲工作必須修改這個值
//雜湊表的長度是2^n。這個值就是n的初始值。可以在啟動memcached的時候通過-o hashpower_init
//設定。設定的值要在[12, 64]之間。如果不設定,該值為0。雜湊表的冪將取預設值16
settings.hashpower_init = 0; /* Starting hash power level */
settings.slab_reassign = false;//是否開啟調節不同型別item所佔的記憶體數。可以通過 -o slab_reassign選項開啟
settings.slab_automove = 0;//自動檢測是否需要進行不同型別item的記憶體調整,依賴於settings.slab_reassign的開啟
settings.shutdown_command = false;//是否支援客戶端的關閉命令,該命令會關閉memcached程序
//用於修復item的引用數。如果一個worker執行緒引用了某個item,還沒來得及解除引用這個執行緒就掛了
//那麼這個item就永遠被這個已死的執行緒所引用而不能釋放。memcached用這個值來檢測是否出現這種
//情況。因為這種情況很少發生,所以該變數的預設值為0(即不進行檢測)。
//在啟動memcached時,通過-o tail_repair_time xxx設定。設定的值要大於10(單位為秒)
//TAIL_REPAIR_TIME_DEFAULT 等於 0。
settings.tail_repair_time = TAIL_REPAIR_TIME_DEFAULT;
settings.flush_enabled = true;//是否執行客戶端使用flush_all命令
}
//然後通過命令列引數,修改對應的值。
while (-1 != (c = getopt(argc, argv,
"a:" /* access mask for unix socket */
"A" /* enable admin shutdown commannd */
"p:" /* TCP port number to listen on */
"s:" /* unix socket path to listen on */
"U:" /* UDP port number to listen on */
"m:" /* max memory to use for items in megabytes */
"M" /* return error on memory exhausted */
"c:" /* max simultaneous connections */
"k" /* lock down all paged memory */
"hi" /* help, licence info */
"r" /* maximize core file limit */
"v" /* verbose */
"d" /* daemon mode */
"l:" /* interface to listen on */
"u:" /* user identity to run as */
"P:" /* save PID in file */
"f:" /* factor? */
"n:" /* minimum space allocated for key+value+flags */
"t:" /* threads */
"D:" /* prefix delimiter? */
"L" /* Large memory pages */
"R:" /* max requests per event */
"C" /* Disable use of CAS */
"b:" /* backlog queue limit */
"B:" /* Binding protocol */
"I:" /* Max item size */
"S" /* Sasl ON */
"F" /* Disable flush_all */
"o:" /* Extended generic options */
))) {
switch (c) {
........
}
}
從上面分析流程可知,首先定義結構體變數,然後初始化其部分變數,最後通過迴圈處理命令列引數,設定對應的值。很簡單的過程,下面詳細解釋每個命令列引數對應的功能,加粗的部分是比較常用的指令,現在對於這些指令不太理解每關係,搞懂了後面的原始碼剖析,那麼命令就非常懂了。
- “A”:是否執行客戶端使用shutdown命令。預設是不允許的。該選項將允許。客戶端的shutdown命令會將memcached程序殺死。該選項會將
settings.shutdown_command
賦值為true
。 - “a”:unix socket的許可權位資訊(訪問掩碼)。該選項的引數賦值給
settings.access
。 - “U:”:大寫U。memcached監聽的UDP埠值,預設埠為11211。該選項的引數賦值給
settings.udpport
。 - “p:”:小寫p,memcached監聽的tcp埠。預設埠為11211, 該選項的引數賦值給
settings.port
。 - “s:”:小寫s。unix socket監聽的socket路徑。該選項的引數賦值給
settings.socketpath
。 - “m:”:小寫m。memcached能夠使用的最大記憶體值,預設是64MB。引數單位為MB。該引數賦值給
settings.maxbytes
。 - “M”:大寫M。預設情況下,當memcached的記憶體使用完後,將進行LRU機制淘汰item以騰出空間。如果使用本選項那麼將關閉LRU功能。當然關閉LRU不代表不能儲存新資料。如果memcached裡面存有過期失效的item,那麼就可以儲存新資料。否則將無法儲存。該選項將
settings.evict_to_free
賦值為0。 - “c:”:小寫c。每個執行緒最多允許多少個客戶端同時線上(這個值不等價於listen函式的第二個引數),該選項和後面的b選項有所不同。 預設值為1024個。該選項引數賦值給
settings.maxconns
。 - “h”:顯示幫助資訊。
- “i”:顯示memcached和libevent的版權資訊。
- “k”:小寫k。將memcached使用到的記憶體鎖定在記憶體中,不準OS把memcached的記憶體移動到虛擬記憶體。因為當OS把memcached的記憶體移動到虛擬記憶體可能會導致頁錯誤,降低memcached的響應時間。
- “v”:小寫v。輸出memcached執行時的一些資訊。-v -vv -vvv輸出的資訊依次增加。該選項會增加
settings.verbose
的值。 - “l:”:小寫L。memcached繫結的ip地址。如果不設定這個選項,那麼memcached將使用
INADDR_ANY
。如果想指定多個IP地址,那麼該選項的引數可以由多個ip組成,ip之間用逗號分隔。也可以多次使用這個選項,此時埠應該尾隨ip而不是單獨用-p選項指定。例如-l 127.0.0.1:8888,192.168.1.112:9999 或者 -l 127.0.0.1:8888 -l 192.168.1.112:9999該選項引數將賦值給settings.inter
。 - “d”:以守護程序的形式執行memcached。
- “r”:將core檔案大小設定為不受限制。
- “R:”:worker執行緒連續為某個客戶端執行命令的最大命令數。該選項的引數賦值給
settings.reqs_per_event
。 - “u:”:小寫u。當以root使用者啟動memcached的時候需要指定memcached的所屬使用者,其他使用者啟動memcached不需要此選項。
- “P:”:大寫p。該選項的引數指明memcached的pid儲存檔案。要和-d選項配合使用。注意執行的使用者是否有許可權寫對應的檔案。
- “f:”:item的擴容因子。預設值為1.25。該選項的引數值可以是小數但必須大於1.0。該選項引數將賦值給
settings.factor
。 - “n:”:設定最小的item(key+value+flags)能儲存多少位元組的資料。該選項引數賦值給
settings.chunk_size
。 - “t:”:該選項的引數用於指定worker執行緒的個數,不建議超過64個。如果不設定該選項預設有4個執行緒。該引數會賦值給
settings.num_threads
。 - “D:”:引數字元作為字首和ID的分隔符。使用了該選項才會自動收集狀態資訊。也可以在啟動memcached後,客戶端使用stats detail on命令開啟,此時預設的分隔符為冒號”:”。該選項引數會賦值為
settings.prefix_delimiter
,並將settings.detail_enabled
賦值為1。 - “L”:如果OS允許的話,那麼向OS申請更大的記憶體頁。OS的預設記憶體頁為4KB。大的記憶體頁可以有效降低頁表的大小,提高效率。此選項會使得memcached預先先OS全部所需的申請記憶體。當然這些記憶體儘量是用大記憶體頁分配的。
- “C:” :大寫C。memcached預設是使用CAS的,本選項是禁用CAS。本選項會將
settings.use_cas
賦值為false。 - “b:”:listen函式的第二個引數。該選項的引數賦值給settings.backlog。如果不設定該選項,那麼預設為1024。該選項和前面的c選項有所不同。
- “B:”:memcached支援文字協議和二進位制協議。該選項的引數用於指定使用的協議。預設情況下是根據客戶端的命令而自動判斷(也叫協商),引數只能取auto、binary、ascii這三個字串值。將引數將賦值給
settings.binding_protocol
。 - “I:”:大寫i。slab分配器中,每一個頁的大小。這個選項的引數是一個數值表示頁的大小。預設單位是B也可以在數值後面帶K或者M(大小寫都行),表示KB和MB。頁的大小小於1KB或者大於128MB都是不允許的。不推薦使用該選項。本選項引數會賦值給
settings.item_size_max
。 - “S”:大寫S。開啟sasl安全協議。會將settings.sasl賦值為true。
- “F”:禁止客戶端的
flush_all
命令。預設是允許客戶端的flush_all
命令的。該選項將settings.flush_enabled
賦值為false。 - “o:”:小寫o。啟動擴充套件選項,有下面幾個子選項可以設定。這個選項是用來優化的。
- maxconns_fast:如果連線數超過了最大同時線上數(由-c選項指定),立即關閉新連線上的客戶端。該選項將
settings.maxconns_fast
賦值為true。 - hashpower:雜湊表的長度是2^n。可以通過選項hashpower設定指數n的初始值。如果不設定將取預設值16。該選項必須有引數,引數取值範圍只能為[12, 64]。本選項引數值賦值給settings.hashpower_init。
- slab_reassign: 該選項沒有引數。用於調節不同型別的item所佔的記憶體。不同型別是指大小不同。某一類item已經很少使用了,但仍佔用著記憶體。可以通過開啟slab_reassign排程記憶體,減少這一類item的記憶體。如果使用了本選項,settings.slab_reassign賦值為true。
- slab_automove:依賴於slab_reassign。用於主動檢測是否需要進行記憶體排程。該選項的引數是可選的。引數的取值範圍只能為0、1、2。引數2是不建議的。本選項引數賦值給settings.slab_automove。如果本選項沒有引數,那麼settings.slab_automove賦值為1。
- hash_algorithm:用於指定雜湊演算法。該選項必須帶有引數。並且引數只能是字串jenkins或者murmur3。
- tail_repair_time:用於檢測是否有item被已死執行緒所引用。一般不會出現這種情況,所以預設不開啟這種檢測。如果需要開啟這種檢測,那麼需要使用本選項。本選項需要一個引數,引數值必須不小於10。該引數賦值給settings.tail_repair_time。
- lru_crawler:本選項用於啟動LRU爬蟲執行緒。該選項不需要引數。本選項會導致settings.lru_crawler賦值為true。
- lru_crawler_sleep:LRU爬蟲執行緒工作時的休眠間隔。本選項需要一個引數作為休眠時間,單位為微秒,取值範圍是[0, 1000000]。該引數賦值給settings.lru_crawler_sleep。
- lru_crawler_tocrawl:LRU爬蟲檢查每條LRU佇列中的多少個item。該選項帶有一個引數。引數會賦值給settings.lru_crawler_tocrawl。
- maxconns_fast:如果連線數超過了最大同時線上數(由-c選項指定),立即關閉新連線上的客戶端。該選項將
Memcached連線及儲存命令
////////////////////////////////////////1、啟動
memcached -m 64 -p 11211 -vvv //slabs大小 埠 列印資訊等級
////////////2、連線,客戶端和伺服器連線比較簡單,基於文字而不是二進位制,所以基於使telent即可
$ telnet localhost 11211 //連線
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
get foo //輸入指令
VALUE foo 0 2
hi
END
stats
STAT pid 8861
quit //telnet退出指令
///////////////////////////////3、命令介紹
First, the client sends a command line which looks like this:
<command name> <key> <flags> <exptime> <bytes> [noreply]\r\n
cas <key> <flags> <exptime> <bytes> <cas unique> [noreply]\r\n
<command name>是"set", "add", "replace", "append" or "prepend"
"set" :“儲存這個資料”,一般是更新已有的快取,也可以用於新增。
"add" :新增快取,快取中不存在新增的KEY。
"Replace":替換現有的快取,快取中一定已經儲存KEY
"Append":在現有的快取資料後新增快取資料。
"Prepend":在現有的快取資料前新增快取資料
"Cas":check and set操作,儲存快取,前提是在check後沒有其它人修改過資料,用於多客戶端同時設定相同的KEY時的原子操作。
"key":快取的KEY
"flags":最開始是16位的無符號整數,現在的版本一般是32位。使用者客戶端儲存自定義標記資料,客戶端自定義這個資料如何儲存,例如我經過壓縮儲存標記為1,那麼這個返回的時候flag會是1,然後就知道是經過壓縮的,那麼客戶端庫會反壓縮給應用使用。一種標記作用而已。具體如何處理,需要客戶端處理。
"exptime":快取過期時間。0表示不自動失效,可以是Unix time或當前伺服器時間的偏移量(秒為單位),如果你想設定當前時間後1分鐘過期,則此引數為60。
設定秒數:從設定開始數,第n秒後失效。
時間戳, 到指定的時間戳後失效。
"bytes":快取資料的長度
"cas unique":unique 64-bit value of an existing entry,cas操作的時候回傳的值,用於伺服器端判斷快取是否改變。
"noreply":伺服器不響應處理結果。
After this line, the client sends the data block:
<data block>\r\n //\r\n結束
After sending the command line and the data blockm the client awaits
the reply, which may be:
"STORED\r\n":表示儲存成功。
"NOT_STORED\r\n":表示未儲存,但並不是錯誤。如:對已經有的KEY使用add。
"EXISTS\r\n":表示使用cas命令設定資料未成功,在你最後一次獲取資料後,資料已經被其它人修改。
"NOT_FOUND\r\n":表示使用cas儲存資料時候,key不儲存。
//4、命令使用介紹
////////////////////////////////////////////////
delete刪除一個已經存在的鍵
get key
VALUE key 0 12
prepend12345
END
delete key
DELETED
get key
END
/////////////////////////////////////
add增加一個不存在的key
存在,則返回錯誤。
不存在則成功。
telnet localhost 11211
add key 0 0 5
12345
STORED
add key 0 0 1
1
NOT_STORED
/////////////////////////////////////
repalce替換已經存在的key值
不存在,則錯誤
存在,則修改
replace key 0 0 3
123
STORED
replace key1 0 0 3
123
NOT_STORED //key1不存在
///////////////////////////////////
set設定鍵
存在,則修改
不存在,則新增,總和add和repalce功能。
set key 0 0 2
12
STORED
/////////////////////////////////////
append :是在現有快取資料後面新增資料。如果 key 不存在,伺服器響應 NOT_STORED
get key
VALUE key 0 3
123
END
append key 0 0 2
45
STORED
get key
VALUE key 0 5
12345
END
prepend 是在現有快取資料前面新增資料。如果 key 不存在,伺服器響應 NOT_STORED
get key
VALUE key 0 5
12345
prepend key 0 0 7
prepend
STORED
get key
VALUE key 0 12
prepend12345
END
prepend key1 0 0 1
1
NOT_STORED
////////////////////////////////////////////////////////////////////
incr,decr 命令:增加/減少值的大小
如果快取資料中儲存的是數字形式的字串,則可以使用incr/decr對資料進行遞增和遞減操作,伺服器響應操作過的結果。操作後的值不會為負數。
格式: incr/decr key number\r\n
add key 0 0 2
10
STORED
incr key 1 // 遞增 1
11
decr key 2 // 遞減 2
9
add key1 0 0 2
aa
STORED
incr key1 1 // 對非數字的快取操作會返回錯誤
CLIENT_ERROR cannot increment or decrement non-numeric value
應用場景------秒殺功能,
一個人下單,要牽涉資料庫讀取,寫入訂單,更改庫存,及事務要求, 對於傳統型資料庫來說,
壓力是巨大的。
可以利用memcached的incr/decr功能, 在記憶體儲存count庫存量,秒殺1000臺
每人搶單主要在記憶體操作,速度非常快,搶到count<=1000 的號人,得一個訂單號,再去另一個頁面慢慢支付,相當於通過這個實現了一個原子操作,因為在memcached內部訪問同一個items是原子的,這種資料庫分離的操作使用起來很方便。
////////////////////////////////////////////////////////////////////
stats命令
用於把memcached當前的執行資訊全部統計出來。
stats item命令
用於檢視條目狀態。
stats slabs命令
檢視記憶體情況
stats命令的顯示如下圖:
2、Libmemcached
介紹
memcached通常以伺服器的形式執行,雖然稱memcached是分散式資料庫,但是其服務端本身不支援分散式業務,這就需要客戶端自己實現分佈管理以及記憶體池功能。Libmemcached是一個開源的Memcached客戶端庫,其內部實現了分散式管理、記憶體池等功能。通過API的形式提供出來,使用程式設計師可以專心上層業務邏輯,避免底層與memcached互動的細節,所以Libmemcached編譯,安裝之後就會以動態庫的方式提供出來給程式設計師呼叫。注意連結串列的時候必須指定-lmemcached
。如果是QT建立工程,那麼必須在*pro檔案裡面加入這句話LIBS += -L/usr/local/lib -lmemcached
。
Libmemcached特性:
- 非同步和同步傳輸支援。
- 支援一致性hash分散式演算法。
- 可調雜湊演算法來匹配金鑰。
- 訪問大物件支援。
- 本地複製。
- 提供了一些管理memcached伺服器的工具命令
安裝
下載最新版、解壓、./configure 、 make 、 make install
三步。
響應的庫檔案和標頭檔案分別位於/usr/local/lib、/usr/loacl/include/libmemcached
其中標頭檔案夾中包含有三個檔案。
1、memcached.h
:庫對應的c介面
2、memcached.hpp
:將對應的c介面封裝成c++介面,所以c++使用起來可能更加方便
3、util.h
:基於庫實現的一些高階功能,例如連線池的功能,就在這個標頭檔案中實現。
需要使用庫,包含上述響應的標頭檔案即可,可以肯定,庫的作者已經幫助我們做好了一切,我們僅僅需要呼叫,就可以和伺服器memcached通訊存值。
這裡寫程式碼片
基本函式呼叫說明
程式設計師可呼叫的函式標頭檔案全