天天看點

網絡協定之:memcached text protocol詳解簡介memcached protocol介紹memcached支援的指令memcached伺服器的傳回值支援UDP協定總結

簡介

用過緩存系統的肯定都聽過memcached的大名,memcached是一個非常優秀的分布式記憶體緩存系統,應用非常的廣泛。Memcached不僅僅是Web緩存,它更是一個通用的資料緩存,基本上你可以将任何東西存入memcached中,它的分布式設計具有很好的可擴充性和靈活性。

Memcached是一個用戶端-伺服器端的架構模式。一般來說,在伺服器上搭建好Memcached的伺服器端,接下來就可以使用Memcached的用戶端和伺服器端進行交換了。

作為用戶端和伺服器端的模型,兩者的通訊肯定是有特定的協定的,适用于memcached的協定就叫做memcached protocol。

memcached的協定有兩種,分别是text協定和binary協定。本文将會詳細講解memcached text protocol的定義。

memcached protocol介紹

memcached可以看做是一個簡單的key-value的存儲系統,用戶端通過key來請求伺服器端的資料,伺服器端通過key的hash值來查找對應的資料,然後傳回給用戶端。

memcached中的key長度一般不能超過250個字元。key不能包含控制字元或空白字元。

為了保證用戶端和伺服器端的消息通訊順暢,一般來說都會制定特殊的用戶端和伺服器端的通訊協定,這個協定就叫做protocol。

什麼是protocol呢?protocol聽起來很高深很神秘,但是實際上protocol就是約定好的雙方互動的消息格式。

對于memcached來說,memcached同時支援UDP和TCP協定,并且提供了兩種協定方式,分别是“文本協定”和“二進制協定”。

其中文本協定是在第一個版本就支援的協定,而二進制協定是在v1.4之後才支援的。

文本協定和二進制協定都支援同樣的指令,兩者的唯一差別就是二進制協定具有更低的性能延遲和更好的可擴充性,而文本協定的有點就是它的可調試性能更好。

memcached text協定包含兩部分資料,文本行和非結構化資料。前者是來自用戶端的指令或來自伺服器的響應,後者代表用戶端通路的資料。指令以\r\n結尾,資料可以用\r、\n或\r\n,表示資料部分的結束。

memcached支援的指令

memcached支援三種指令,分别是存儲指令,讀取指令和其他指令。

存儲指令

memcached中的存儲指令總共有6個,分别是“set”、“add”、“replace”、“append”、"prepend" 和 "cas"。

首先,用戶端發送如下所示的指令行:

command key [flags] [exptime] length [noreply]
           

另外cas指令的格式和其他幾個不太一樣:

cas key [flags] [exptime] length [casunique] [noreply]
           

上面的指令中,command代表的是指令的名字,也就是上面的“set”、“add”、“replace”、“append”和"prepend"。

set表示給key設定一個值。

Add表示如果key不存在的話,就添加。

replace用來替換已知key的value。

append表示将提供的值附加到現有key的value之後,是一個附加操作。

prepend将目前key對應的value添加到提供的值後面。

cas是一個原子操作,隻有當casunique比對的時候,才會設定對應的值。

flags是一個非常有趣的參數,這個參數對于memcached server來說是透明的,這個參數隻是用來标記用戶端指令的類型,并不會被伺服器端識别。另外flags的長度在不同的memcached版本中也有所不同,在memcached 1.2.0或者根據低級的版本中,flags是一個16-bit的整數。在memcached 1.2.1或以上的版本,flags是一個32-bit的整數。

exptime是過期時間,0表示不會過期。

length是以byte表示的value的長度,這個值并不包含value中的結束符"\r\n"。

casunique是一個64-bit的現有entry的唯一值。

noreply告訴伺服器端,這是個不需要reply的指令。

在發送完指令行之後,用戶端還需要發送資料塊:

<data block>\r\n
           

舉個例子,我們想要将jack這個值設定到student這個key上,那麼對應的指令應該如下所示:

set student 0 0 4\r\njack\r\n
           

對應的用戶端收到的伺服器端的傳回可能有這些值:

  • "STORED\r\n",表示存儲成功。
  • "NOT_STORED\r\n" 表示資料因為某些錯誤未存儲成功。這通常意味着不滿足“add”或“replace”指令的條件。
  • "EXISTS\r\n" 表示要設定的值在上次進行cas操作之後已經被修改了。
  • "NOT_FOUND\r\n" 表示要設定的值用在cas。

讀取指令

memcached的讀取指令有4個,分别是“get”、“gets”、“gat”和“gats,這些指令的格式如下:

get <key>*\r\n
gets <key>*\r\n
gat <exptime> <key>*\r\n
gats <exptime> <key>*\r\n
           

memcached中的讀取指令後面不需要跟額外的資料塊。

伺服器端會根據接收到的key進行查詢,每個key傳回一條資料,格式如下:

VALUE <key> <flags> <bytes> [<cas unique>]\r\n
<data block>\r\n
           

在所有的資料都傳輸完畢之後,伺服器端會發送"END\r\n"表示傳輸完畢。

這裡的key表示查詢傳入的key。

flags是存儲指令傳入的flags。

bytes是後面data block的長度。

cas unique是目前item的唯一标記,在gets或者gats指令中傳回。

data block是目前item具體的傳回值。

上面我們提到了4個讀取的指令,那麼他們有什麼差別呢?

首先是get和gets的差別,get 用于擷取key的value值,若key不存在,傳回空。支援多個key。 gets 用于擷取key的帶有CAS令牌值的value值,若key不存在,傳回空。支援多個key。 他們的差別在于gets會傳回多一個cas unique值。

gat和get的差別是,gat是get+touch的指令綜合體,除了傳回目前值之外,還會更新key的過期時間。

常用的其他指令

除了存儲和擷取之外,還有一些常用的其他指令。為什麼這些指令被叫做第三類指令呢?這是因為這些指令隻需要一個指令行即可,并不需要向伺服器端傳入額外的資料塊。

下面是删除指令的格式:

delete <key> [noreply]\r\n
           

key是要删除的對象。

noreply表示是否需要收到伺服器的傳回值。

對應的伺服器端傳回值可能有兩個:

  • "DELETED\r\n" 表示删除成功
  • "NOT_FOUND\r\n" 表示要删除的對象并不存在。

下面是Increment/Decrement指令的格式:

incr <key> <value> [noreply]\r\n
decr <key> <value> [noreply]\r\n
           

key是要修改的對象。

value是要添加或者減少的值,它必須是一個64-bit無符号整數。

noreply表示是否需要收到伺服器的傳回值。

伺服器端的傳回可能有兩個:

  • "NOT_FOUND\r\n" 表示要修改的對象沒有找到
  • "value\r\n" 傳回修改成功之後的值

還有一個常用的是修改key過期時間的touch指令:

touch <key> <exptime> [noreply]\r\n
           

key是要修改的對象。

exptime是過期時間。

noreply表示是否需要收到伺服器的傳回值。

伺服器端的傳回值有兩種:

  • "TOUCHED\r\n" 表示修改成功。
  • "NOT_FOUND\r\n" 表示要修改的對象不存在。

當然memcached支援的指令遠不止上面所講的這些。我們隻是從中挑選出了最常用的一些指令進行講解。

memcached伺服器的傳回值

上面在講解具體的指令的時候有提到伺服器的傳回值,這裡再總結一下,memcached伺服器端的傳回值有下面幾種:

傳回值 說明

STORED

值存儲成功

NOT_STORED

值存儲失敗

EXISTS

cas中要存儲的對象已存在

NOT_FOUND

要修改的對象不存在

ERROR

送出了未知的指令

CLIENT_ERROR errorstring

用戶端輸入有誤,具體的錯誤資訊存放在

errorstring

SERVER_ERROR errorstring

伺服器端異常

VALUE keys flags length

傳回要查詢的key對應的對象

DELETED

對象已經被删除

STAT name value

統計資訊

END

伺服器端傳回結束

注意,上面所有的傳回值都以"\r\n"結尾。

支援UDP協定

上面我們講的都是TCP協定的封包格式。事實上memcached還支援UDP協定。

但是因為UDP不保證可靠性的特征,是以使用UDP的場合一般在做緩存的查詢應用中,即使查詢失敗,也隻是被看做是緩存沒有被命中而已,并不會影響到資料的準确性。

事實上UDP的資料包和TCP的資料包格式基本一樣,隻不過多了一個簡單的幀頭。并且所有的請求都必須在單個UDP資料包中完成。

注意,這裡隻有請求才有這個要求,伺服器端的傳回并沒有這個限制。

在UDP中幀頭長8個位元組,其中0-1個位元組表示的是請求ID,請求ID是由用戶端生成的一個單調遞增的值。伺服器端将會使用這個ID來标記是對哪個請求的響應。特别是在有伺服器端有多個響應的情況下。

2-3個位元組表示的是序列号,它的取值範圍是0到n-1,其中n是消息中總的封包個數,也就是4-5個位元組所表示的。

最後的6-7位元組是保留位元組,以備将來使用,現在設定為0。

總結

以上就是對memcached協定的介紹,通常來說我們使用memcached都是通過memcached用戶端來進行的,如果有細心的朋友可能會發現,用戶端使用的指令和協定中的指令差别不大,這是因為用戶端就是對這些底層協定的封裝,然後暴露給使用者一個更加簡單易操作的接口。