Memcache Binary Protocol Six Apart, Ltd.548 4th StreetSan FranciscoCA94107USAaaron@serendipity.palo-alto.ca.us
Applications
memcache memcached cache
This memo explains the memcache binary protocol for informational purposes.
Memcache is a high performance key-value cache. It is intentionally a
dumb cache, optimized for speed only. Applications using memcache do
not rely on it for data -- a persistent database with guaranteed reliability
is strongly recommended -- but applications can run much faster when
cached data is available in memcache.
Memcache is a high performance key-value cache. It is intentionally a
dumb cache, optimized for speed only. Applications using memcache do
not rely on it for data -- a persistent database with guaranteed reliability
is strongly recommended -- but applications can run much faster when
cached data is available in memcache.
Memcache was originally written to make LiveJournal go faster.
It now powers all of the fastest web sites that you love.
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
"SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
document are to be interpreted as described in .
General format of a packet:
Byte/ 0 | 1 | 2 | 3 |
/ | | | |
|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|
+---------------+---------------+---------------+---------------+
0/ HEADER /
/ /
/ /
/ /
+---------------+---------------+---------------+---------------+
16/ COMMAND-SPECIFIC EXTRAS (as needed) /
+/ (note length in th extras length header field) /
+---------------+---------------+---------------+---------------+
m/ Key (as needed) /
+/ (note length in key length header field) /
+---------------+---------------+---------------+---------------+
n/ Value (as needed) /
+/ (note length is total body length header field, minus /
+/ sum of the extras and key length body fields) /
+---------------+---------------+---------------+---------------+
Total 16 bytes
Request header:
Byte/ 0 | 1 | 2 | 3 |
/ | | | |
|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|
+---------------+---------------+---------------+---------------+
0| Magic | Opcode | Key length |
+---------------+---------------+---------------+---------------+
4| Extras length | Data type | Reserved |
+---------------+---------------+---------------+---------------+
8| Total body length |
+---------------+---------------+---------------+---------------+
12| Message ID |
+---------------+---------------+---------------+---------------+
Total 16 bytes
Response header:
Byte/ 0 | 1 | 2 | 3 |
/ | | | |
|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|
+---------------+---------------+---------------+---------------+
0| Magic | Opcode | Status |
+---------------+---------------+---------------+---------------+
4| Extras length | Data type | Reserved |
+---------------+---------------+---------------+---------------+
8| Total body length |
+---------------+---------------+---------------+---------------+
12| Message ID |
+---------------+---------------+---------------+---------------+
Total 16 bytes
Header fields:
Magic number.Command code.Length in bytes of the text key that follows the command extras.Status of the response (non-zero on error).Length in bytes of the command extras.Reserved for future use (Sean is using this soon).Really reserved for future use (up for grabs).Length in bytes of extra + key + value.Will be copied back to you in the response.
FIXME: Can this be used to organize packets?Request packet for this protocol versionResponse packet for this protocol version
Magic byte / version. For each version of the protocol, we'll use a
different request/reponse value pair. This is useful for protocol
analyzers to know what a packet is in isolation from which direction
it is moving. Note that it is common to run a memcached instance on a
host that also runs an application server. Such a host will both send
and receive memcache packets.
The version should hopefully correspond only to different meanings of
the command byte. In an ideal world, we will not change the header
format. As reserved bytes are given defined meaning, the protocol
version / magic byte values should be incremented.
Traffic analysis tools are encouraged to identify memcache packets
and provide detailed interpretation if the magic bytes are recognized
and otherwise to provide a generic breakdown of the packet. Note that
the key and value positions can always be identified even if the magic
byte or command opcode are not recognized.
Possible values of this two-byte field:
No errorUnknown commandKey not foundKey exists
Possible values of the one-byte field:
GetSetAddReplaceDeleteIncrementDecrementQuitFlushGetQNo-opVersion
Possible values of the one-byte field:
Raw bytesMUST have extras.MUST have key.MUST NOT have value.4 byte flags8 byte data version checkExtra data for get/getq:
Byte/ 0 | 1 | 2 | 3 |
/ | | | |
|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|
+---------------+---------------+---------------+---------------+
0| Data version check |
| |
+---------------+---------------+---------------+---------------+
8| Flags |
+---------------+---------------+---------------+---------------+
Total 12 bytes
The get command gets a single key. The getq command is both mum
on cache miss and quiet, holding its response until a non-quiet
command is issued.
You're not guaranteed a response to a getq cache hit until
you send a non-getq command later, which uncorks the
server which bundles up IOs to send to the client in one go.
Clients should implement multi-get (still important for
reducing network roundtrips!) as n pipelined requests, the
first n-1 being getq, the last being a regular
get. that way you're guaranteed to get a response, and
you know when the server's done. you can also do the naive
thing and send n pipelined gets, but then you could potentially
get back a lot of "NOT_FOUND!" error code packets.
alternatively, you can send 'n' getqs, followed by an 'echo'
or 'noop' command.
MAY have extras (FIXME: Is it OK to issue a delete without extras?).MUST have key.MUST NOT have value.4 byte expiration timeExtra data for delete:
Byte/ 0 | 1 | 2 | 3 |
/ | | | |
|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|
+---------------+---------------+---------------+---------------+
0| Expiration |
+---------------+---------------+---------------+---------------+
Total 4 bytes
When allows you to 'reserve' a key. When 'when' is set
for, say, ten seconds in the future, the 'add' and 'replace' operations will fail for that key
until ten seconds from now. The 'set' operation will succeed regardless of any reserved deletes.
FIXME: Is the reservation also cancelled? Say there's a delete with a 10 second hold. Two seconds
later, an 'add' is received. It fails. Two second later, a 'set' is received. Is succeeds unconditionally.
What if another 'add' is received two more seconds later (a total of six seconds since the original
10 second delete-hold, thus still within its purview).
MUST have extras.MUST have key.MUST have value.4 byte flags4 byte expiration time8 byte data version checkExtra data for set/add/replace:
Byte/ 0 | 1 | 2 | 3 |
/ | | | |
|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|
+---------------+---------------+---------------+---------------+
0| Data version check |
| |
+---------------+---------------+---------------+---------------+
8| Flags |
+---------------+---------------+---------------+---------------+
12| Expiration |
+---------------+---------------+---------------+---------------+
Total 16 bytes
If the Data Version Check is present and nonzero, the set MUST succeed if the
key exists and has a version identifier identical to the provided value, and
MUST NOT succeed if the key does not exist or has a different version identifier.
The set response packet will include the same values in all three fields.
If the Data Version Check is zero, the set MUST succeed unconditionally.
The set response packet will include idential values for flags and expiration,
and a new value for Data Version Check, which the client SHOULD keep track of.
The key MAY be reserved according to ,
causing the set to fail.
MUST NOT have extras.MUST NOT have key.MUST NOT have value.
Used as a keep alive. Flushes outstanding getq's.
MUST have extras.MUST have key.MUST NOT have value.8 byte value to add / subtract (FIXME: Is this unsigned?)8 byte initial value (unsigned)4 byte expiration timeExtra data for incr/decr:
Byte/ 0 | 1 | 2 | 3 |
/ | | | |
|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|
+---------------+---------------+---------------+---------------+
0| Amount to add |
| |
+---------------+---------------+---------------+---------------+
8| Initial value |
| |
+---------------+---------------+---------------+---------------+
16| Expiration |
+---------------+---------------+---------------+---------------+
Total 20 bytes
incr/decr response body:
Byte/ 0 | 1 | 2 | 3 |
/ | | | |
|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|
+---------------+---------------+---------------+---------------+
0| 64-bit unsigned response. |
| |
+---------------+---------------+---------------+---------------+
Total 8 bytes
These commands will either add or remove the specified
amount to the requested counter.
If the counter does not exist, one of two things may happen:
If the expiration value is all one-bits (0xffffffff), the
operation will fail with NOT_FOUND.For all other expiration values, the operation will succeed
by seeding the value for this key with the provided initial
value to expire with the provided expiration time.
Note that in the creation case, flags will be set to zero
(FIXME: Should they be provided here as well?)
We start up our application, and it asks for the value associated with the 'Hello' key.
Get request:
Byte/ 0 | 1 | 2 | 3 |
/ | | | |
|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|
+---------------+---------------+---------------+---------------+
0| 0x80 | 0x00 | 5 in big endian (BE) |
+---------------+---------------+---------------+---------------+
| 12 in BE | 0x00 | |
+---------------+---------------+---------------+---------------+
| 17 in BE |
+---------------+---------------+---------------+---------------+
| 0xDEADBEEF |
+---------------+---------------+---------------+---------------+
16| 0x00000000 |
+---------------+---------------+---------------+---------------+
24| 0xDECAF 0x15 0xBAD 0xC0FFEE |
| |
+---------------+---------------+---------------+---------------+
28| 'H' 'e' 'l' 'l' |
| 'o' |
+---------------+
Total 33 bytes (16 header + 12 get-extras + 5 key)
Since nobody has set this key, it returns not found.
Get response:
Byte/ 0 | 1 | 2 | 3 |
/ | | | |
|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|
+---------------+---------------+---------------+---------------+
0| 0x81 | 0x00 | 0x0001 |
+---------------+---------------+---------------+---------------+
| 0 in BE | 0x00 | |
+---------------+---------------+---------------+---------------+
| 0 in BE |
+---------------+---------------+---------------+---------------+
| 0xDEADBEEF |
+---------------+---------------+---------------+---------------+
Total 16 bytes
Well, looks like we need to set the key! Let's set it to expire on
December 15, 2007 at 9:51:09 PM.
Set request:
Byte/ 0 | 1 | 2 | 3 |
/ | | | |
|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|
+---------------+---------------+---------------+---------------+
0| 0x80 | 0x01 | 5 in BE |
+---------------+---------------+---------------+---------------+
| 16 in BE | 0x00 | |
+---------------+---------------+---------------+---------------+
| 26 in BE |
+---------------+---------------+---------------+---------------+
| 0xDA7ABA5E |
+---------------+---------------+---------------+---------------+
16| 0x00000000 |
+---------------+---------------+---------------+---------------+
20| 0xDCCB4674 |
+---------------+---------------+---------------+---------------+
24| 0xDECAF 0x15 0xBAD 0xC0FFEE |
| |
+---------------+---------------+---------------+---------------+
32| 'H' 'e' 'l' 'l' |
| 'o' | 'W' 'o' 'r' |
| 'l' 'd' |
+---------------+---------------+
Total 42 bytes (16 header + 16 set-extras + 5 key + 5 value)
The set succeeds.
Set response:
Byte/ 0 | 1 | 2 | 3 |
/ | | | |
|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|
+---------------+---------------+---------------+---------------+
0| 0x81 | 0x01 | 0x0000 |
+---------------+---------------+---------------+---------------+
| 16 in BE | 0x00 | |
+---------------+---------------+---------------+---------------+
| 16 in BE |
+---------------+---------------+---------------+---------------+
| 0xDA7ABA5E |
+---------------+---------------+---------------+---------------+
16| 0x00000000 |
+---------------+---------------+---------------+---------------+
20| 0xDCCB4674 |
+---------------+---------------+---------------+---------------+
24| 0xDECAF 0x15 0xBAD 0xC0FFEE |
| |
+---------------+---------------+---------------+---------------+
Total 32 bytes (16 header + 16 set-extras)
If the original get request is sent again, the key would be found.
Get response:
Byte/ 0 | 1 | 2 | 3 |
/ | | | |
|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|
+---------------+---------------+---------------+---------------+
0| 0x81 | 0x00 | 0x00 | |
+---------------+---------------+---------------+---------------+
| 12 in BE | 0x00 | |
+---------------+---------------+---------------+---------------+
| 17 in BE |
+---------------+---------------+---------------+---------------+
| 0xDEADBEEF |
+---------------+---------------+---------------+---------------+
16| 0xDCCB4674 |
+---------------+---------------+---------------+---------------+
24| 0xDECAF 0x15 0xBAD 0xC0FFEE |
| |
+---------------+---------------+---------------+---------------+
28| 'W' 'o' 'r' 'l' |
| 'd' |
+---------------+
Total 33 bytes (16 header + 12 get-extras + 5 value)
Memcache has no authentication or security layers whatsoever. It is
RECOMMENDED that memcache be deployed strictly on closed, protected,
back-end networks within a single data center, within a single cluster of
servers, or even on a single host, providing shared caching for multiple
applications. Memcache MUST NOT be made available on a public network.
LJ NEEDS MOAR SPEEDDanga Interactivehttp://www.livejournal.com/
Thanks to Brad Fitzpatrick, Anatoly Vorobey, Steven Grimm, and Dustin
Sallings, for their work on the memcached server.
Thanks to Sean Chittenden, Jonathan Steinert, Brian Aker, Evan Martin,
Nathan Neulinger, Eric Hodel, Michael Johnson, Paul Querna, Jamie
McCarthy, Philip Neustrom, Andrew O'Brien, Josh Rotenberg, Robin H.
Johnson, Tim Yardley, Paolo Borelli, Eli Bingham, Jean-Francois
Bustarret, Paul G, Paul Lindner, Alan Kasindorf, Chris Goffinet, Tomash
Brechko, and others for their work reporting bugs and maintaining
memcached client libraries and bindings in many languages.