动态

详情 返回 返回

網絡協議之:memcached text protocol詳解 - 动态 详情

簡介

用過緩存系統的肯定都聽過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客户端來進行的,如果有細心的朋友可能會發現,客户端使用的命令和協議中的命令差別不大,這是因為客户端就是對這些底層協議的封裝,然後暴露給用户一個更加簡單易操作的接口。

更多內容請參考 http://www.flydean.com/23-memcached-text-protocol/

最通俗的解讀,最深刻的乾貨,最簡潔的教程,眾多你不知道的小技巧等你來發現!

歡迎關注我的公眾號:「程序那些事」,懂技術,更懂你!

user avatar journey_64224c9377fd5 头像 qngyun1029 头像 hello_5adf4e51b4f3e 头像 AmbitionGarden 头像 u_11365552 头像 HarmonyOS5 头像 ahahan 头像 lenve 头像 boxuegu 头像 wxweven 头像 litongjava 头像 hebeiniunai 头像
点赞 21 用户, 点赞了这篇动态!
点赞

Add a new 评论

Some HTML is okay.