協議
---------
Memcache客戶端通過TCP連接與服務器進行通信(UDP接口也是可用的,在下文的"UDP協議"部分有詳細描述)。Memcache服務器在一個(可配置的)端口上監聽;客戶端連接該端口,發送命令到服務器,讀取響應,最後關閉連接。
沒有必要發送命令來終止會話。如果不需要該連接,客戶端任何時候都可以將其關閉。但即便是這樣,客戶端最好還是緩存連接,而不要在它們要存取數據時再打開連接。這是由於memcache被特意設計成可以處理大量(數百個,需要的話可以上千個)打開的連接。緩存這些連接會減少建立TCP連接所帶來的開銷(相對於此,在服務器端建立一個新連接的準備工作所帶來的開銷,可以忽略不計).
在Memcache協議中發送的數據分兩種:文本行和非結構數據(unstructured data)。由客戶端發送的命令和服務器端的響應使用的是文本行。非結構數據用於客戶端存儲數據的時候。服務器會將接收到的非結構數據, 以字節流的形式原樣返回。服務器並不關心在非結構數據中的字節序的問題。對於非結構數據中的字符沒有任何限制,但數據的讀取方(客戶端或服務器)需要通過一個文本行數據,得知正在傳輸的數據塊的精確長度。
文本行總是以/r/n結束,非結構數據也總以/r/n結束, 但/r, /n或者其它的8位字符也可能出現在數據中,所以當客戶端從服務器讀取數據時,必須使用所提供數據長度來決定數據何時結束,而不是基於/r/n在數據塊的結束處,雖然確實是如此。
鍵(Keys)
----------
在Memcache中存儲的數據是以鍵來標識的。鍵是一個全局唯一的文本串標識,客戶端通過經來存取所需的數據。當前,鍵的長度限制是250個字符(當然,通常來說客戶端並不需要使用那麼長的鍵)。鍵不參包含控制字符和空格。
命令(Commands)
----------
存儲命令(有6個: "set", "add" ,"replace", "append", "prepend" 和 "cas")要求服務器存儲以鍵標識的數據。客戶端發送一個命令行,然後是一個數據塊;之後客戶端等待一個表示成功/失敗的響應行。
提取命令(有兩個:"get"和"gets") 要求服務器提取一個鍵集(一次請求一個或多個鍵)的數據。客戶端發送一個包含所有請求鍵的命令行。對於每一個數據項,服務器查找到後,發送一個響應行對客戶端,內含該數據項的信息,後跟該數據項的數據,直到服務器發送了一個"END"響應行,表示整個過程的結束。
命令行總是以命令行開頭,後跟以空格分隔的參數(如果有的話)。命令行是小寫的並且大小寫敏感。
過期時限(Expiration times)
----------
客戶端發送給服務器的某些命令可以帶有(一個數據項或一個客戶端請求操作的)過期時限信息。在這些情況下,發送的實際值可以是Unix時間(自1970年1月1日至今的秒數,32位值),或是從當前起的秒數。在後一種情況下,秒數不能超過60*60*24*30(30天的秒數)。如果客戶端發送的數值超過此值,服務器會認爲它是一個Unix時間值,而不是距當前時間的偏移值。
出錯字符串(Error strings)
------------
客戶端發送的每一個命令,服務器可能會發送一個出錯字符串作爲響應。這些出錯字符串有三種類型:
-- "ERROR/r/n"
表示客戶端發送了一個不存在的命令
-- "CLIENT_ERROR <error>/r/n"
表示客戶端的輸入行出現了某些錯誤,例如,輸入行沒有遵從協議。<error>是一個人可讀的錯誤描述。
-- "SERVER_ERROR <error>/r/n"
表示服務器的一些錯誤導致服務器不能執行該命令。<error>是一個人可讀的出錯描述字符串。如果出現了使服務器無法繼續爲客戶端服務的服務器錯誤(這一般不應發生),服務器在發送完錯誤字符串後會關閉連接。這是服務器端關閉客戶端連接的唯一情況。
在以下的每個命令描述中,錯誤行不會再次提及,但客戶端必須考慮到它們可能會出現。
存儲命令
--------------
首先,客戶端發送一個類似這樣的命令行:
<command name> <key> <flags> <exptime> <bytes> [noreply]/r/n
cas <key> <flags> <exptime> <bytes> <cas unique> [noreply]/r/n
--<command> 有 "set ", "add ", "replace", "append" 和 "prepend"
"set" 表示存儲這個數據
"add" 表示存儲這個數據,但只在服務器沒有存儲該Key的數據的情況下。
"replace" 表示存儲這個數據,但只在服務器存儲了該Key的數據的情況下。
"append"表示爲一個已存在的Key的數據在尾部追加該部分的數據。
"prepend"表示爲一個已存在的Key的數據在頭部添加該部分的數據。
append和prepend命令不接受flag和exptime。
它們更新已存數據,而忽略新的flag和exptime設置。
cas是一個檢查並設置的操作,意思是"存儲這個數據,但只有在自我上次取得該數據以來沒有人再更新該數據的情況下才存儲"。
--<key> 客戶端要求存儲的數據鍵值
--<flags> 是一個可選的16位無符串整數(以十進制形式寫入),服務器會在取回該數據項時一同原樣返回。客戶端可以將其用作一個位存儲域來存儲一些數據特徵信息。這個域對服務器是透明的。注意在memcached 1.2.1和更高版本,flags可以是32位的,而不是16位,不過你或許會限制使用16位來兼容舊版本。
--<exptime> 是過期時間。如果設置爲0, 則該數據項永不過期(儘管如此,它還是可能從緩存中被刪除掉,以爲其它數據項騰出空間)。如果它不爲0(或者是Unix 時間,或者是相當於當前時間的偏移值), 它可以保證在過期時間到後,客戶端不會存儲到該數據(用服務器時間度量)。
--<bytes> 是後跟數據的字節長度,沒有計算作爲分隔符的/r/n. <bytes>可能爲0 (在這種情況下,它後跟一個空的數據塊)。
--<cas unique> 是一個與已存數據條目相關的全局唯一的64位數。客戶端應該使用"gets"命令返回的該值來進行"cas"更新操作。
--"noreply" 可選項指示服務器不要回送響應。注意:如果請求行格式錯誤,服務器不一定能可靠地解析"noreply"選項。在此種情況下,它可能會發送錯誤信息給客戶端,如果客戶端沒有讀取該信息的話會帶來問題。客戶端應該只構造合法的請求。
在此行後,客戶端發送數據塊。
<data block>/r/n
- <data block>是一個任意的8位字節數據塊,長度爲前面一行所指定的數據長度<bytes>。
在發送了該命令行和數據塊後,客戶端等待可能的響應:
- "STORED/r/n", 指示成功
- "NOT_STORED/r/n"指示數據沒有被存儲,但不是出錯。這通常是表示"add"或"replace"的條件沒有滿足。
- "EXIST/r/n"指示使用"cas"命令所要更新的數據自你上次取過後已經過修改。
-"NO_FOUND/r/n"指示你用"cas"命令要修改的數據並不存在。
數據提取命令:
----------------
數據提取命令有"get"和"gets",如:
get <key>*/r/n
get <eky>*/r/n
-<key>*表示一個或多個由空格分隔的key串
在這個命令後,客戶端期待零個或多個數據項,每個接受到的數據項是一個文本行,後跟數據塊。當所有數據項傳送完後,服務器發送一個"END/r/n"指示響應的終止。
每一個由服務器發送的數據項如下所示:
VALUE <key> <flags> <bytes> [<cas unique>]/r/n
<data block>/r/n
- <key> 數據項的Key值
- <flags> 是由存儲命令設置的flags
- <bytes>是後跟數據塊的長度,沒有包括作爲分隔符的/r/n
- <cas unique>是一個64位整數,唯一標識了一個特定的數據項。
- <data block> 數據項的數據
如果有某些在請求中出現的Key沒有服務器沒有在數據項列表中回送,表示服務器沒有這些Key的數據項(因爲它們沒有被存儲過,或者刪除以爲其它數據項騰出空間,或者過期了,又或者被客戶端的delete 操作刪除了)。
刪除
----------
delete命令允許顯式刪除數據項:
delete <key> [noreply]/r/n
- <key> 客戶端要求服務器刪除的數據項的key值
- "norply" 可選參數指示服務器不要回送響應。參見存儲命令中對格式錯誤請求的說明。
這個命令的響應行可能是以下的一個:
--"DELETED/r/n" 指示成功
-- "NOT_FOUND/r/n" 指示Key所指的數據項不存在。
參見下文的"flush_all"命令,該命令使所有數據項立即無效。
遞增/遞減
-----------
incr和decr命令用來原地改變某些數據項,遞增或遞減其值。數據項的數據被看作是64位的無符號十進制整數。如果當前的數據值不能轉換爲這樣一種表示,則incr/decr命令返回一個錯誤(memcached <= 1.2.6將這種僞值(bogus value)看成是0, 這會導致混亂)。另外,這個數據項必須已存在使得 incr/decr能工作。這些命令不會假設一個不存在的key數值爲0,而是會失敗。
客戶端發送的命令行如下:
incr <key> <value> [noreply]/r/n
或
desc <key> <value> [noreply]/r/n
- <key> 客戶端想改變的數據項的key值
- <value> 客戶端要對數據項遞增/遞減的值。它是一個64位的無符號十進制整數。
- "norply" 可選參數指示服務器不要回送響應。參見存儲命令中對格式錯誤請求的說明。
響應可能是以下之一:
- "NOT_FOUND/r/n" 指示這個數據項找不到
-"<value>/r/n", 其中<value>是這個數據項在經過遞增/遞減操作後的新值
注意如果"desr"命令捕獲到下溢異常:如果客戶端嘗試將一個值減少到小於0, 新值將會是0. "incr"命令的上溢異常會經64位迴繞(wrap around the 64 bit mark)。【譯者注:即 (原值+value) & 0xffffffffffffffff】.
同樣要注意的是減少一個數值使得其實際長度減少了,但並不保證其返回長度值的減少。這個數值可能會在尾部加上空格,但這純屬一個實現上的優化手段,所以你不能依賴它。
統計
-----------
"stats" 命令用於查詢服務器維護的一些統計數據和內部數據。它有兩種形式。不用參數:
stats/r/n
它使服務器輸出常規統計和設置,下文中有說明。 另一種形式帶有參數:
stats <args>/r/n
根據 <args> ,服務器會返回不同的內部數據。參數的類型和發送的數據沒有在這個版本的協議中說明,這有利於memcache開發者(對代碼)進行更改。
常規統計
-------------
當接收到不帶參數的"stats"命令後, 服務器發送若干行數據,如下所示:
STAT <name> <value>/r/n
服務器用以下行作爲終結:
END/r/n
在每一行統計數據中, <name>是統計項的名稱,<value>是統計值。在以下的列表中有對"stats"命令響應的所有統計名稱,和這個統計項的類型,以及這個值的意義。
在下面的類型列中,"32u" 表示32位無符號整數,"64u"表示64位無符號整數,"32u.32.u"表示兩個由分號分隔的32位無符號整數(當作是浮點數)。
名稱 |
類型 |
含義 |
pid |
32u |
服務器進程的id |
uptime |
32u |
自服務器啓動以來的秒數 |
time |
32u |
服務器上的UNIX時間 |
version |
string |
服務器的版本 |
pointer_size |
32 |
主機操作系統的默認指針長度(一般是32或64) |
rusage_user |
32u.32u |
進程用戶空間的累計時長(秒:微秒) |
rusage_system |
32u.32u |
進程內核空間的累計時長 (秒:微秒) |
curr_items |
32u |
當前存儲的數據項數目 |
total_items |
32u |
自服務器啓動以來存儲的數據項總數(譯者注:其實就是成功執行存儲命令(STORED)的計數) |
bytes |
64u |
當前用於存儲數據項所用的字節數 |
curr_connections |
32u |
打開的連接數 |
total_connections |
32u |
自服務器啓動以來的打開的連接數 |
connection_structures |
32u |
服務器分配的連接結構的數目 |
cmd_get |
64u |
提取命令的累計數目 |
cmd_set |
64u |
存儲命令的累計數目(譯者注:也包括NOT_STORED的) |
get_hits |
64u |
請求並找到的數據項的數目 |
get_missed |
64u |
請求但找不到的數據項的數目 |
delete_missed |
64u |
刪除無效key的請求數 |
delete_hits |
64u |
使得數據項刪除的刪除請求數目 |
incr_missed |
64u |
沒有找到key的incr請求數 |
incr_hits |
64u |
成功的incr請求數 |
decr_misses |
64u |
沒有找到key的decr請求數 |
decr_hits |
64u |
成功的decr請求數 |
cas_misses |
64u |
沒有找到key的CAS請求數 |
cas_hits |
64u |
成功CAS請求數 |
cas_badval |
64u |
key存在但CAS值不匹配的CAS請求的數目 |
auth_cmds |
64u |
認證命令處理的次數,包括成功和失敗 |
auth_errors |
64u |
身份認證失敗的數目 |
evictions |
64u |
從緩存中移除數據項來爲新數據項騰出空間的數目 |
reclaimed |
64u |
利用一個過期數據條目來存儲新數據條目的數目 |
bytes_read |
64u |
本服務器從網絡中讀取的字節總數 |
bytes_written |
64u |
本服務器發送到網絡的字節總數 |
limit_maxbytes |
32u |
本服務器允許使用的內存字節數 |
threads |
64u |
請求的工作線程數(參見 doc/threads.txt) |
conn_yields |
64u |
由於達到-R選項指定數目的限制,一個連接的操作主動放棄讓給另一個連接的數目 |
設置項統計
----------------
警告:這部分所描述的統計項以後可能會有變更。
帶有"settings" 的 "stats"命令返回memcached的設置細節。這基本上就是由進程命令行的選項所組成的。
注意這裏不保證統計項的次序,列表也不一定是詳盡的。除此之外,它的返回結果與其它的stats命令是一樣的。
名稱 |
類型 |
含義 |
maxbytes |
size_t |
緩存中的最大字節數 |
maxconns |
32 |
最大的併發客戶端數 |
tcpport |
32 |
TCP監聽端口 |
udpport |
32 |
UDP監聽端口 |
inter |
string |
監聽地址 |
verbosity |
32 |
0=無, 1=部分, 2=很多 |
oldest |
32u |
最老對象的時長 |
evictions |
on/off |
當爲off時,LRU清除策略禁用 |
domain_socket |
string |
Unix socket的文件路徑 |
umask |
32 (oct) |
Unix socket 的屏蔽字 |
growth_factor |
float |
Chunk大小的增長因子 |
chunk_size |
32 |
爲 key+ value + flag分配的最小空間 |
num_threads |
32 |
線程數(包括分派線程) |
stat_key_prefix |
char |
統計前綴分隔符 |
detail_enabled |
bool |
如果爲真,啓用統計細節 |
reqs_per_event |
32 |
在一個事件處理裏的最大IO請求數 |
cas_enabled |
bool |
當爲假時,CAS會被禁用 |
tcp_backlog |
32 |
TCP 監聽backlog值 |
auth_enabled_sasl |
yes/no |
是否使用SASL |
數據項統計
----------------
警告: 這部分所描述的統計項以後可能會有變更。
帶有“items”選項的"stats"命令返回每個slab class的item存儲信息。返回的數據格式:
STAT items:<slabclass>:<stat> <value>/r/n
服務器使用以下行終止這個列表:
END/r/n
<slabclass>和 "stats slabs"命令使用的類id是一致的。"stats slabs"描述內存的大小和使用率, "stats items"描述更上一層的信息。
以下的項的值被定義爲
名稱 |
含義 |
number |
當前存儲在這個class中的item數.過期的item不會自動排除 |
age |
在LRU中最老的item |
evicted |
不得不從LRU中移除未過期item的次數 |
evicted_nonzero |
過期時間設置不爲0,但不得不從LRU中稱除該未過期的item的次數 |
evicted_time |
自最後一次清除過期item起所經歷的秒數。用這個來判斷數據被移除的最近時間 |
outofmemory |
slab class爲新item分配空間失敗的次數。這意味着你運行時帶上了-M或者移除操作失敗 |
tailrepairs |
自解決slab 引用泄漏問題的次數。如果這個計數器增長很多,請將你的情況告訴開發者 |
reclaimed |
用一個過期的數據條目存儲新一個數據條目的次數 |
注意僅僅會顯示存在的slab的信息,因此對於空的緩存會返回空集。
Item大小統計
----------------------
警告: 這部分所描述的統計項以後可能會有變更。
帶有"sizes"選項的"stats"命令返回緩存中全部數據的一般大小和數目。
警告:這個命令會對緩存上鎖!它會遍歷每一個數據項並檢查其大小。儘管這個操作很快,但如果你有很多數據項,你會阻止其它的請求幾秒。
數據的返回格式如下所示:
<size> <count>/r/n
服務器以下面的行來終止列表:
END/r/n
"size"是數據項的大約大小,在32字節內
"count"是在該32字節範圍的數據項的數目。
這使我們瞭解到對於所有的item,是否都有一個相應32字節長度內的slab class。你可以以此來決定如何調整slab增長因子來減少內存開銷。例如:如果大部分的item都小於200字節,在小容量的範圍中產生更多的class可以使得item在slab中的分配更緊湊。
Slab 統計
------------------
警告: 這部分所描述的統計項以後可能會有變更。
帶有"slabs"選項的"stats"命令返回在運行期memcache建立的每一個slab的信息。這包括每個slab的信息和一些總計信息。返回數據的格式爲:
STAT <slabclass>:<stat> <value>/r/n
STAT <stat> <value>/r/n
服務器以下面的行終止列表:
END/r/n
名稱 |
含義 |
chunk_size |
每一個chunk佔用的空間。一個item會使用一個合適大小的chunk來存儲 |
chunk_per_page |
一個頁中有多少個chunk.一個頁的大小默認是小於等於1M。Slab在頁中分配,然後分割成chunk |
total_pages |
爲該slab class分配的頁數 |
total_chunks |
爲該slab class分配的chunk數 |
get_hits |
在該class中數據提取請求(命中)的總數 |
cmd_set |
在該class 中數據存儲請求的總數 |
delete_hits |
在該class 中成功刪除數據的總數 |
incr_hits |
在該class中遞增操作的總數 |
decr_hits | 在該class中遞減操作的總數 |
cas_hits | 在該class中CAS命令更新的總數 |
cas_badval |
在該class中因不匹配的CAS id而失敗而導致更新失敗 的CAS命令的總數 |
used_chunks | 有多少個chunk用於分配item |
free_chunks | 還沒有用於item分配,或因刪除變空閒的chunk數目 |
free_chunks_end | 在最近分配的Page尾部空閒chunk的數目 |
mem_requested | 在該slab 中申請分配的內存字節數 |
active_slabs |
slab class分配的總數 |
total_malloced | 分配的slab page內存量 |
Item存儲於與大於等於其大小的slab中。mem_request顯示在一個slab中所有內存請求的總大小(total_chunks * chunk_size)-mem_requestd 顯示該slab浪費的內存數。如果你看到有大量的浪費,考慮調slab 增長因子。
其它命令
----------------
"flush_all" 命令帶有一個可選的數目參數。它總是成功,服務器返回"OK/r/n"作爲響應(除非在最後一個參數中指定了"noreply")。它的作用是使得所有現存的item立即無效(默認)或者在一個指定的時間後無效。在失效操作後,不會有item作爲響應返回給數據提取命令(除非它在flush_all操作後又在相同的key中存儲了一次)。flush_all實際上並沒有釋放item佔用的所有的內存,它們會逐漸被用於存儲新的item。flush_all最精確的定義如下:它使得所有最後更新時間小於flush_all指定的時間的item在提取操作中被忽略。
帶延遲的flush_all的目的在於,當你設置了一個memcache服務池,而且要清除所有內容,你可以選擇不要同時重置所有的memcache服務(例如這會使所有客戶端原本從memcache中取得的數據,現在要由數據庫重新生成而導致數據庫負擔的突然加重)。
這個延遲選項允許你以10秒的間隔來重置它們(例如,第一個10秒後,第二個20秒後,第三個......)
"version"命令沒有參數:
version/r/n
在響應中,服務器返回:
"VERSION <version>/r/n", 其中<version>該服務器的版本字符串。
"verbosity"是一個帶一個數目參數的命令。它總是成功,服務器返回"OK/r/n"作爲響應(除非在最後一個參數指定了noreply).它的作用是設置日誌輸出的顯示級別。
"quit"命令沒有任何參數:
quit/r/n
當收到該命令時, 服務器端關閉連接。但客戶端也可以在它不需要該連接時將其簡單地關閉,不用發送任何命令。
UDP協議
------------------
對於客戶端的數目非常多的情況下,TCP連接數限制了擴展性。也有一個基於UDP的接口。UDP接口不提供可靠傳輸, 所以只應用於不需要保證成功的操作中;典型的情況是在"get"請求時,一個丟失或不完整的響應會簡單地被認爲是緩存不命中。
每一個UDP數據報包含一個簡單的幀頭,後跟與上述TCP協議一樣格式的數據。在當前的實現中,請求必須在一個UDP數據報中,但響應可以跨多個數據報(一般僅用於在多個key的"get"和"set"請求中。考慮到可靠性,這兩種請求其實還是用TCP傳輸比較合適)。
幀頭是8個字節的長度,如下所示(所有的值都是16位整數,網絡字節序,高位在前)
0-1 請求ID
2-3 序列號
4-5 該消息包含的數據報數目
6-7 保留字段,必須爲0
請求ID由客戶端提供,典型是使用一個基於某個隨機數的自增序列,但客戶端可以自由決定請求ID。服務器的響應中會包含與請求相同的ID。客戶端使用請求ID來區分不同來自同一個服務器的對不同請求的響應。那些帶有不能識別的請求ID的響應可能是對之前請求的延遲響應,應該丟棄。
序列號是範圍是從0到n-1, 這裏的n是該消息的數據報總數。客戶端應該將數據報的負載部分以序列號順序進行連接。合併字節流的結果與TCP協議(包含結束符/r/n)的格式一致。
本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/Jenkinslee/archive/2010/10/16/5946005.aspx