强曰为道
与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

Memcached 完全指南 / 第 10 章:通信协议

第 10 章:通信协议

10.1 协议总览

Memcached 支持三种协议:

协议版本状态说明
文本协议 (ASCII)1.0+稳定人类可读,调试方便
二进制协议 (Binary)1.4+稳定效率更高,1.6+ 可能移除
Meta 协议1.6+推荐精简高效,功能最强
# 启动时指定协议
memcached -B auto    # 自动检测(默认)
memcached -B ascii   # 只支持文本协议
memcached -B binary  # 只支持二进制协议

10.2 文本协议 (ASCII Protocol)

协议格式

请求格式:
<命令> <参数1> <参数2> ... <参数N>\r\n
[数据块]\r\n

响应格式:
<响应码> [数据长度]\r\n
[数据块]\r\n

行终止符: \r\n (CRLF)

命令分类

存储命令:
  set <key> <flags> <exptime> <bytes> [noreply]\r\n
  add <key> <flags> <exptime> <bytes> [noreply]\r\n
  replace <key> <flags> <exptime> <bytes> [noreply]\r\n
  append <key> <flags> <exptime> <bytes> [noreply]\r\n
  prepend <key> <flags> <exptime> <bytes> [noreply]\r\n
  cas <key> <flags> <exptime> <bytes> <cas_unique> [noreply]\r\n

检索命令:
  get <key> [key ...]\r\n
  gets <key> [key ...]\r\n

删除命令:
  delete <key> [noreply]\r\n

计数命令:
  incr <key> <value> [noreply]\r\n
  decr <key> <value> [noreply]\r\n

管理命令:
  flush_all [delay] [noreply]\r\n
  version\r\n
  verbosity <level> [noreply]\r\n
  quit\r\n

统计命令:
  stats [settings|items|slabs|sizes|conns|reset]\r\n
  stats cachedump <slab_id> <limit>\r\n

完整交互示例

客户端 → 服务端:
set user:1001 3 3600 27\r\n
{"name":"Alice","age":30}\r\n

服务端 → 客户端:
STORED\r\n

客户端 → 服务端:
get user:1001 user:1002\r\n

服务端 → 客户端:
VALUE user:1001 3 27\r\n
{"name":"Alice","age":30}\r\n
VALUE user:1002 3 25\r\n
{"name":"Bob","age":25}\r\n
END\r\n

10.3 二进制协议 (Binary Protocol)

协议头

请求包结构 (24 字节头部 + Body):
  Byte 0:     Magic (0x80 = Request)
  Byte 1:     Opcode (命令码)
  Byte 2-3:   Key 长度 (网络字节序)
  Byte 4:     Extras 长度
  Byte 5:     数据类型 (0x00 = Raw Bytes)
  Byte 6-7:   保留/状态码
  Byte 8-11:  Body 长度 (Key + Extras + Value)
  Byte 12-15: Opaque (客户端自定义,原样返回)
  Byte 16-23: CAS (8字节)

响应包结构 (24 字节头部 + Body):
  Byte 0:     Magic (0x81 = Response)
  Byte 1:     Opcode
  Byte 2-3:   Key 长度
  Byte 4:     Extras 长度
  Byte 5:     数据类型
  Byte 6-7:   状态码
  Byte 8-11:  Body 长度
  Byte 12-15: Opaque
  Byte 16-23: CAS

命令码 (Opcode)

Opcode名称说明
0x00GET获取
0x01SET设置
0x02ADD添加
0x03REPLACE替换
0x04DELETE删除
0x05INCREMENT自增
0x06DECREMENT自减
0x07QUIT退出
0x08FLUSH清空
0x09GETQ安静获取
0x0ANO-OP空操作
0x0BVERSION版本
0x0CGETK获取 Key
0x0DGETKQ安静获取 Key
0x0EAPPEND追加
0x0FPREPEND前置
0x10STAT统计
0x11SETQ安静设置
0x12ADDQ安静添加
0x13REPLACEQ安静替换
0x14DELETEQ安静删除
0x15INCREMENTQ安静自增
0x16DECREMENTQ安静自减
0x17QUITQ安静退出
0x18FLUSHQ安静清空
0x19APPENDQ安静追加
0x1APREPENDQ安静前置

状态码

状态码名称说明
0x0000SUCCESS成功
0x0001KEY_ENOENTKey 不存在
0x0002KEY_EEXISTSKey 已存在(CAS 失败)
0x0003E2BIGValue 过大
0x0004EINVAL无效参数
0x0005NOT_STORED未存储
0x0006DELTA_BADVAL自增值非法
0x0007AUTH_ERROR认证错误
0x0008AUTH_CONTINUE认证继续
0x0020AUTH_REQUIRED需要认证
0x0081UNKNOWN_COMMAND未知命令
0x0082ENOMEM内存不足

二进制 vs 文本协议性能

维度文本协议二进制协议
解析速度较慢(字符串解析)较快(固定偏移)
网络效率较差(数值转文本)较好(原生二进制)
可调试性极好(人类可读)差(需工具)
安静命令不支持支持(Q 后缀)
Opaque不支持支持
批量操作批量 get批量 get/getq

10.4 Meta 协议 (Meta Protocol)

Meta 协议是 Memcached 1.6 引入的新一代协议,旨在替代文本和二进制协议。

设计目标

Meta 协议设计原则:
1. 一条命令完成多项操作(减少往返)
2. 精简的命令格式(减少网络数据量)
3. 向后兼容文本协议
4. 支持更丰富的元数据操作

Meta 命令格式

ms <key> <datalen> [flags...]\r\n     ← Meta Set
<data>\r\n

mg <key> [flags...]\r\n              ← Meta Get

md <key> [flags...]\r\n              ← Meta Delete

ma <key> [flags...]\r\n              ← Meta Arithmetic

Meta Set 标志

标志说明示例
T<ttl>设置 TTLT3600 = 3600 秒
F<flags>客户端标志F3
I<cas>CAS 唯一值(条件写入)I123456789
NnoreplyN
c返回 CAS 值c
k返回 Keyk
q安静模式(不返回 STORED)q
O<opaque>Opaque 标记O1234
M<mode>模式(S=set, A=add, R=replace, E=cas, A=append, P=prepend)MA

Meta Get 标志

标志说明示例
v返回 Valuev
k返回 Keyk
f返回 flagsf
s返回大小s
c返回 CASc
T返回剩余 TTLT
h命中检查(不返回 Value)h
l返回 LRU 位置l
t返回 Item 类型t
N<ttl>更新 TTL(滑动过期)N3600
G<token>通过 Token 获取指定字节G0-100

Meta 协议交互示例

# 存储(带 TTL,返回 CAS)
ms user:1001 27 T3600 c\r\n
{"name":"Alice","age":30}\r\n
→ ST 123456789\r\n

# 获取(返回 Value、CAS、TTL、大小)
mg user:1001 v c T s\r\n
→ VA 27 c 123456789 T 3500 s 27\r\n
→ {"name":"Alice","age":30}\r\n

# 仅检查存在性
mg user:1001 h\r\n
→ HD\r\n   ← 存在

mg user:9999 h\r\n
→ NF\r\n   ← 不存在

# 条件删除(CAS 匹配)
md user:1001 E123456789\r\n
→ DE\r\n   ← 删除成功

# 原子自增(不存在则创建)
ma counter N1 J0 T3600 c\r\n
→ VA 1 c 987654321\r\n
→ 1\r\n

# 批量获取(安静 + 批量)
mg key1 v q\r\n
→ VA 5\r\nhello\r\n
mg key2 v q\r\n
→ VA 5\r\nworld\r\n
mg key3 h q\r\n
→ HD\r\n
mg key4 h q\r\n
→ EN\r\n  ← 所有命令已发送

10.5 libmemcached

libmemcached 是最完善的 C/C++ Memcached 客户端库。

安装

# Ubuntu/Debian
sudo apt-get install -y libmemcached-dev

# CentOS/RHEL
sudo yum install -y libmemcached-devel

# macOS
brew install libmemcached

# 源码编译
git clone https://github.com/memcached/libmemcached.git
cd libmemcached
./configure --enable-sasl
make -j$(nproc)
sudo make install

C 语言示例

#include <stdio.h>
#include <string.h>
#include <libmemcached/memcached.h>

int main() {
    // 创建客户端实例
    memcached_st *mc = memcached_create(NULL);

    // 配置服务器
    memcached_server_st *servers = memcached_servers_parse("mc1:11211,mc2:11211");
    memcached_server_push(mc, servers);
    memcached_server_list_free(servers);

    // 配置一致性哈希
    memcached_behavior_set(mc, MEMCACHED_BEHAVIOR_DISTRIBUTION,
                           MEMCACHED_DISTRIBUTION_CONSISTENT);
    memcached_behavior_set(mc, MEMCACHED_BEHAVIOR_HASH,
                           MEMCACHED_HASH_MURMUR);

    // SET 操作
    memcached_return_t rc;
    rc = memcached_set(mc, "user:1001", 9,
                       "{\"name\":\"Alice\"}", 18,
                       (time_t)3600, (uint32_t)0);
    if (rc == MEMCACHED_SUCCESS) {
        printf("SET 成功\n");
    }

    // GET 操作
    size_t value_length;
    uint32_t flags;
    char *value = memcached_get(mc, "user:1001", 9,
                                &value_length, &flags, &rc);
    if (rc == MEMCACHED_SUCCESS) {
        printf("GET: %.*s\n", (int)value_length, value);
        free(value);
    }

    // 批量 GET
    const char *keys[] = {"user:1001", "user:1002", "user:1003"};
    size_t key_lengths[] = {9, 9, 9};
    rc = memcached_mget(mc, keys, key_lengths, 3);

    char return_key[MEMCACHED_MAX_KEY];
    size_t return_key_length;
    while ((value = memcached_fetch(mc, return_key, &return_key_length,
                                    &value_length, &flags, &rc)) != NULL) {
        printf("KEY: %s, VALUE: %.*s\n",
               return_key, (int)value_length, value);
        free(value);
    }

    // CAS 操作
    uint64_t cas_value;
    value = memcached_get_by_key(mc, NULL, 0, "balance", 7,
                                 &value_length, &flags, &cas_value, &rc);

    // 使用 CAS 更新
    rc = memcached_cas(mc, "balance", 7, "200", 3,
                       (time_t)0, (uint32_t)0, cas_value);
    if (rc == MEMCACHED_SUCCESS) {
        printf("CAS 更新成功\n");
    } else if (rc == MEMCACHED_DATA_EXISTS) {
        printf("CAS 冲突,需要重试\n");
    }

    // 清理
    memcached_free(mc);
    return 0;
}
# 编译
gcc -o mc_example mc_example.c -lmemcached
./mc_example

libmemcached 行为配置

// 常用行为配置
memcached_behavior_set(mc, MEMCACHED_BEHAVIOR_NO_BLOCK, 1);        // 非阻塞 I/O
memcached_behavior_set(mc, MEMCACHED_BEHAVIOR_TCP_NODELAY, 1);     // 禁用 Nagle
memcached_behavior_set(mc, MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE, 1024*1024); // 发送缓冲区
memcached_behavior_set(mc, MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE, 1024*1024); // 接收缓冲区
memcached_behavior_set(mc, MEMCACHED_BEHAVIOR_CONNECT_TIMEOUT, 1000); // 连接超时(ms)
memcached_behavior_set(mc, MEMCACHED_BEHAVIOR_POLL_TIMEOUT, 1000);   // 轮询超时(ms)
memcached_behavior_set(mc, MEMCACHED_BEHAVIOR_RETRY_TIMEOUT, 5);     // 重试超时(s)
memcached_behavior_set(mc, MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT, 3); // 失败阈值
memcached_behavior_set(mc, MEMCACHED_BEHAVIOR_REMOVE_FAILED_SERVERS, 1); // 自动移除故障节点

memcached CLI 工具

libmemcached 自带的命令行工具:

# 设置
memcset --servers=localhost:11211 --key=test --value=hello --expire=60

# 获取
memcget --servers=localhost:11211 --key=test

# 删除
memcdelete --servers=localhost:11211 --key=test

# 批量操作
memcslap --servers=localhost:11211 --concurrency=50 --initial-load=1000

# 性能测试
memcping --servers=localhost:11211

10.6 协议选型建议

选择协议:

需要调试 / 开发环境?
  └── 文本协议 ✓

需要最高性能 / 生产环境?
  └── Meta 协议(1.6+)✓

需要兼容旧客户端?
  └── 二进制协议 ✓

不确定?
  └── 文本协议(最通用)✓

扩展阅读

小结

要点内容
文本协议人类可读,调试方便,通用性最强
二进制协议效率更高,支持安静命令和 Opaque
Meta 协议1.6+ 推荐,一条命令完成多项操作
libmemcached最完善的 C/C++ 客户端库,内置一致性哈希
noreply批量写入时使用 noreply 减少往返