Memcached, despite its simplicity, has two distinct communication protocols, and understanding their performance differences can significantly impact your application’s throughput.

Let’s see the binary protocol in action. Imagine you have a Memcached instance running on localhost:11211. We’ll use netcat to simulate client requests.

First, the text protocol. It’s human-readable, which is great for debugging, but less efficient.

echo "set mykey 0 3600 5\r\nhello\r\n" | nc localhost 11211

This sends a set command. Memcached responds with STORED. Simple.

Now, the binary protocol. It’s more compact and machine-oriented. You can’t just echo arbitrary bytes and expect it to work. You need to construct the specific binary payload. Let’s say we want to set mykey to world with an expiration of 3600 seconds.

The binary protocol header is 24 bytes. For a set command (opcode 1), it looks something like this (simplified):

0x80 (magic byte for binary) 0x01 (set opcode) 0x00 0x08 (key length 8) 0x00 (extra length 0) 0x00 (data type 0) 0x00 0x00 (vbucket ID 0) 0x00 0x00 00 00 (total body length: key length + value length) 0x00 00 00 00 (opaque ID) 00 00 00 00 00 00 00 00 (cas value 0) + key + value.

Let’s construct a get request for mykey (which is 5 bytes long) using a tool that can generate binary. memcached-tool or a custom script would be used here, but for illustration, imagine the raw bytes representing:

0x80 0x00 0x00 0x05 0x00 0x00 0x00 0x00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 (header) + m y k e y (key)

This binary blob would then be sent to localhost:11211. Memcached responds with a similar binary structure indicating success or failure, followed by the value if it was a get.

The core problem Memcached solves is in-memory caching to reduce database load and latency. It provides a simple key-value store accessible over the network. The difference between protocols boils down to how that key-value data and commands are serialized and transmitted.

The text protocol is ASCII-based. Commands like get, set, delete are sent as plain text strings, terminated by \r\n. The server parses these strings. This makes it easy to read and write manually, but the parsing overhead on the server and the verbosity of ASCII characters (multiple bytes per character) add latency. For set mykey 0 3600 5\r\nhello\r\n, the server has to parse "set", then "mykey", then "0", then "3600", then "5", then read 5 bytes, all while managing the \r\n delimiters.

The binary protocol, on the other hand, uses a fixed-size header (24 bytes) followed by variable-length key, value, and extras. Each field in the header has a specific meaning and length. This allows for much more efficient parsing on the server. There’s no ambiguity about command type (it’s an opcode byte), lengths are explicitly stated, and data is sent in its raw byte form. This reduces CPU cycles spent on parsing and minimizes network bandwidth. For example, a get command for a key of length 5 with binary protocol is a compact 24-byte header + 5-byte key, whereas text protocol is get mykey\r\n which is 13 bytes, but the parsing is significantly more complex and less efficient.

The binary protocol also supports features like incr/decr more efficiently and has better error handling built into its response structure.

The primary performance benefit of the binary protocol comes from reduced CPU overhead on the Memcached server. Instead of parsing text strings, it’s directly reading fixed-size fields and byte lengths. This means the server can handle more requests per second. On the client side, less data is sent over the wire for the same operation, and the client’s serialization/deserialization logic is often simpler and faster. The difference is most pronounced under high load or with many small operations.

Most modern Memcached clients default to the binary protocol because the performance gains are substantial and the complexity of implementing it is hidden within the client library. Unless you have a very specific reason (like needing to manually inspect traffic with telnet or netcat for debugging), you should always use the binary protocol.

When you switch from a text protocol client to a binary protocol client, you’ll notice that your Memcached server’s CPU utilization drops for the same request rate, and your application’s latency for cache operations decreases. You might also see an increase in the number of requests per second your Memcached instance can handle.

The most surprising thing about the binary protocol is that its "magic byte" (0x80) signals the start of a request, and a different magic byte (0x81) signals the start of a response. This simple byte differentiates the entire communication flow and is the first thing the server or client checks to know if it’s receiving a request or a response, avoiding misinterpretation of data streams.

The next hurdle you’ll likely encounter is understanding how to leverage the cas (check-and-set) command, which is primarily supported and more robustly implemented in the binary protocol, to handle race conditions in distributed caching scenarios.

Want structured learning?

Take the full Memcached course →