Memcached append 命令详解(2025 版)
append 是 Memcached 的 追加写入 命令,用于 在已有 value 末尾追加数据,常用于 日志、队列、构建大对象。
关键点:
- 仅当 key 已存在 时生效
- 不改变 flags 和 exptime
- 原子操作,线程安全
1. 基本语法
append <key> <flags> <exptime> <bytes> [noreply]\r\n
<value>\r\n
注意:
flags和exptime被忽略,仅为兼容性保留
| 参数 | 说明 |
|---|---|
<key> | 已有键名 |
<flags> | 被忽略 |
<exptime> | 被忽略 |
<bytes> | 要追加的数据字节数 |
[noreply] | 可选,异步 |
<value> | 要追加的内容 |
响应:
STORED\r\n→ 成功(key 存在)NOT_STORED\r\n→ 失败(key 不存在)
2. telnet 操作示例
telnet 127.0.0.1 11211
示例 1:首次创建 + 多次 append
# 1. 先 set 初始值
set log:access 0 0 11
2025-11-13
STORED
# 2. 追加访问记录
append log:access 0 0 20
| user:1001 | GET /
STORED
# 3. 再次追加
append log:access 0 0 21
| user:1002 | POST /login
STORED
# 4. 查看完整日志
get log:access
VALUE log:access 0 52
2025-11-13 | user:1001 | GET / | user:1002 | POST /login
END
3. 客户端使用 append
Python(pymemcache)
from pymemcache.client.base import Client
client = Client(('127.0.0.1', 11211))
# 初始化
client.set('queue:jobs', 'task1')
# 追加任务
client.append('queue:jobs', ',task2')
client.append('queue:jobs', ',task3')
print(client.get('queue:jobs')) # b'task1,task2,task3'
PHP
$mc = new Memcached();
$mc->addServer('127.0.0.1', 11211);
$mc->set('chat:room1', 'Alice: Hello');
$mc->append('chat:room1', "\nBob: Hi!");
$mc->append('chat:room1', "\nAlice: How are you?");
echo $mc->get('chat:room1');
Java(XMemcached)
client.set("buffer:data", 0, "part1");
client.append("buffer:data", "part2");
client.append("buffer:data", "part3");
System.out.println(client.get("buffer:data")); // part1part2part3
4. append vs prepend
| 命令 | 行为 |
|---|---|
append | 追加到末尾 |
prepend | 插入到开头 |
set msg 0 0 5
hello
STORED
append msg 0 0 6
world
STORED
# → "hello world"
prepend msg 0 0 8
dear
STORED
# → "dear hello world"
5. 经典应用场景
5.1 实时日志收集
def log_access(user, action):
entry = f" | {user} | {action}"
client.append('log:daily', entry)
所有服务器追加到同一 key,定期落盘
5.2 构建大对象(分片写入)
# 分片上传大文件
client.set('file:123:chunks', '')
for i, chunk in enumerate(chunks):
client.append('file:123:chunks', chunk)
避免单次写超 1MB 限制
5.3 简单消息队列(FIFO)
# 生产者
client.append('queue:jobs', json.dumps(task) + '\n')
# 消费者(配合 get + delete)
data = client.get('queue:jobs')
if data:
tasks = data.split(b'\n')
task = tasks[0]
# 处理完删除(需 CAS 或重建)
注意:非线程安全消费,推荐用 Redis List
5.4 聊天室消息历史
client.append('chat:room1', f"{user}: {msg}\n")
6. 重要限制与注意事项
| 限制 | 说明 |
|---|---|
| key 必须存在 | 否则 NOT_STORED |
| value ≤ 1MB | 追加后总大小不能超 1MB(可通过 -I 调整) |
| 不改变过期时间 | 原 exptime 保持不变 |
| 不改变 flags | 原 flags 保持不变 |
| 二进制安全 | 支持任意字节(包括 \0) |
超 1MB 报错示例
# 假设当前 0.9MB
append bigkey 0 0 200000
<200KB 数据>
ERROR # 或 SERVER_ERROR object too large
解决:分 key 存储,如
bigkey:1,bigkey:2
7. 最佳实践
| 建议 | 说明 |
|---|---|
先 set 空值初始化 | set key 0 0 0 + "" |
| 控制单 key 大小 < 800KB | 留出追加空间 |
| 定期归档 | get → 落盘 → delete |
| 避免高并发 append 同一 key | 可能导致热点 |
用 \n 分隔结构化数据 | 方便解析 |
8. 调试与监控
# 查看 append 统计
echo "stats" | nc 127.0.0.1 11211 | grep cmd_append
# cmd_append: 100
# append_hits: 95
# append_misses: 5
# 查看当前 value 长度
value = client.get('log:daily')
print(len(value)) # 字节数
9. 常见错误
| 错误 | 原因 | 解决 |
|---|---|---|
NOT_STORED | key 不存在 | 先 set |
SERVER_ERROR object too large | 超 1MB | 分片或增大 -I |
| 数据错乱 | 未加分隔符 | 用 \n 或 , 分隔 |
10. 小结:append 命令速查
append key 0 0 bytes [noreply]
<value>
└─> STORED(key 存在)
└─> NOT_STORED(key 不存在)
| 项目 | 推荐值 |
|---|---|
flags | 0(被忽略) |
exptime | 0(被忽略) |
bytes | < 100KB |
| 初始化 | set key 0 0 0 + "" |
练习建议
- 用 telnet 实现“访问日志追加”
- 用 Python 实现 聊天室消息推送
- 模拟分片上传 1.5MB 文件(用
append)
需要 prepend 命令、CAS 安全更新、大对象存储方案?继续问我!