第 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 | 名称 | 说明 |
|---|
| 0x00 | GET | 获取 |
| 0x01 | SET | 设置 |
| 0x02 | ADD | 添加 |
| 0x03 | REPLACE | 替换 |
| 0x04 | DELETE | 删除 |
| 0x05 | INCREMENT | 自增 |
| 0x06 | DECREMENT | 自减 |
| 0x07 | QUIT | 退出 |
| 0x08 | FLUSH | 清空 |
| 0x09 | GETQ | 安静获取 |
| 0x0A | NO-OP | 空操作 |
| 0x0B | VERSION | 版本 |
| 0x0C | GETK | 获取 Key |
| 0x0D | GETKQ | 安静获取 Key |
| 0x0E | APPEND | 追加 |
| 0x0F | PREPEND | 前置 |
| 0x10 | STAT | 统计 |
| 0x11 | SETQ | 安静设置 |
| 0x12 | ADDQ | 安静添加 |
| 0x13 | REPLACEQ | 安静替换 |
| 0x14 | DELETEQ | 安静删除 |
| 0x15 | INCREMENTQ | 安静自增 |
| 0x16 | DECREMENTQ | 安静自减 |
| 0x17 | QUITQ | 安静退出 |
| 0x18 | FLUSHQ | 安静清空 |
| 0x19 | APPENDQ | 安静追加 |
| 0x1A | PREPENDQ | 安静前置 |
状态码
| 状态码 | 名称 | 说明 |
|---|
| 0x0000 | SUCCESS | 成功 |
| 0x0001 | KEY_ENOENT | Key 不存在 |
| 0x0002 | KEY_EEXISTS | Key 已存在(CAS 失败) |
| 0x0003 | E2BIG | Value 过大 |
| 0x0004 | EINVAL | 无效参数 |
| 0x0005 | NOT_STORED | 未存储 |
| 0x0006 | DELTA_BADVAL | 自增值非法 |
| 0x0007 | AUTH_ERROR | 认证错误 |
| 0x0008 | AUTH_CONTINUE | 认证继续 |
| 0x0020 | AUTH_REQUIRED | 需要认证 |
| 0x0081 | UNKNOWN_COMMAND | 未知命令 |
| 0x0082 | ENOMEM | 内存不足 |
二进制 vs 文本协议性能
| 维度 | 文本协议 | 二进制协议 |
|---|
| 解析速度 | 较慢(字符串解析) | 较快(固定偏移) |
| 网络效率 | 较差(数值转文本) | 较好(原生二进制) |
| 可调试性 | 极好(人类可读) | 差(需工具) |
| 安静命令 | 不支持 | 支持(Q 后缀) |
| Opaque | 不支持 | 支持 |
| 批量操作 | 批量 get | 批量 get/getq |
Meta 协议是 Memcached 1.6 引入的新一代协议,旨在替代文本和二进制协议。
设计目标
Meta 协议设计原则:
1. 一条命令完成多项操作(减少往返)
2. 精简的命令格式(减少网络数据量)
3. 向后兼容文本协议
4. 支持更丰富的元数据操作
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
| 标志 | 说明 | 示例 |
|---|
T<ttl> | 设置 TTL | T3600 = 3600 秒 |
F<flags> | 客户端标志 | F3 |
I<cas> | CAS 唯一值(条件写入) | I123456789 |
N | noreply | N |
c | 返回 CAS 值 | c |
k | 返回 Key | k |
q | 安静模式(不返回 STORED) | q |
O<opaque> | Opaque 标记 | O1234 |
M<mode> | 模式(S=set, A=add, R=replace, E=cas, A=append, P=prepend) | MA |
| 标志 | 说明 | 示例 |
|---|
v | 返回 Value | v |
k | 返回 Key | k |
f | 返回 flags | f |
s | 返回大小 | s |
c | 返回 CAS | c |
T | 返回剩余 TTL | T |
h | 命中检查(不返回 Value) | h |
l | 返回 LRU 位置 | l |
t | 返回 Item 类型 | t |
N<ttl> | 更新 TTL(滑动过期) | N3600 |
G<token> | 通过 Token 获取指定字节 | G0-100 |
# 存储(带 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 减少往返 |