Memcached prepend 命令详解(2025 版)
prepend 是 Memcached 的 前置写入 命令,用于 在已有 value 开头插入数据,常用于 日志倒序、队列头部插入、构建大对象。
与
append区别:
append:追加到 末尾prepend:插入到 开头
1. 基本语法
prepend <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:初始化 + 多次 prepend
# 1. 初始化
set log:events 0 0 7
oldest
STORED
# 2. 前置新事件(倒序日志)
prepend log:events 0 0 8
event3
STORED
prepend log:events 0 0 8
event2
STORED
prepend log:events 0 0 8
event1
STORED
# 3. 查看结果(最新事件在前)
get log:events
VALUE log:events 0 31
event1event2event3oldest
END
结果:
event1event2event3oldest→ 最新在前
3. 客户端使用 prepend
Python(pymemcache)
from pymemcache.client.base import Client
client = Client(('127.0.0.1', 11211))
# 初始化队列
client.set('queue:priority', 'low')
# 高优先级任务前插
client.prepend('queue:priority', 'high,')
client.prepend('queue:priority', 'urgent,')
print(client.get('queue:priority')) # b'urgent,high,low'
PHP
$mc = new Memcached();
$mc->addServer('127.0.0.1', 11211);
$mc->set('timeline:user1', 'post:old');
$mc->prepend('timeline:user1', 'post:new3|');
$mc->prepend('timeline:user1', 'post:new2|');
$mc->prepend('timeline:user1', 'post:new1|');
echo $mc->get('timeline:user1');
// post:new1|post:new2|post:new3|post:old
Java(XMemcached)
client.set("buffer", 0, "end");
client.prepend("buffer", "middle");
client.prepend("buffer", "start");
System.out.println(client.get("buffer")); // startmiddleend
4. prepend vs append 对比
| 命令 | 插入位置 | 典型用途 |
|---|---|---|
prepend | 开头 | 倒序日志、优先队列头部 |
append | 末尾 | 正序日志、队列尾部 |
set msg 0 0 6
center
STORED
prepend msg 0 0 6
left
STORED
# → "leftcenter"
append msg 0 0 7
right
STORED
# → "leftcenterright"
5. 经典应用场景
5.1 倒序事件日志(最新在前)
def log_event(event):
entry = f"{event}|"
client.prepend('log:realtime', entry)
读取时直接
get即可看到最新事件
5.2 优先级队列(高优先级在前)
# 高优先级任务
client.prepend('queue:jobs', json.dumps(task) + '\n')
# 低优先级任务
client.append('queue:jobs', json.dumps(task) + '\n')
5.3 构建大对象(分片前插)
# 分片上传,用户最新上传在前
client.set('file:123', '')
for chunk in reversed(chunks): # 从新到旧
client.prepend('file:123', chunk)
5.4 用户动态时间线
client.prepend('timeline:user:1001', f"{post_id}|")
6. 重要限制与注意事项
| 限制 | 说明 |
|---|---|
| key 必须存在 | 否则 NOT_STORED |
| 总大小 ≤ 1MB | 追加后不能超限 |
| 不修改 flags / exptime | 原值保持不变 |
| 二进制安全 | 支持任意字节 |
| 性能开销略高 | 需内存移动数据 |
超限示例
# 当前 0.9MB
prepend bigkey 0 0 200000
<200KB 数据>
ERROR # object too large for cache
解决:分片存储
bigkey:part1,bigkey:part2
7. 最佳实践
| 建议 | 说明 |
|---|---|
先 set 空值初始化 | set key 0 0 0 + "" |
| 控制单 key < 800KB | 预留空间 |
| 用分隔符 | |, \n, , |
| 定期归档 | get → 落盘 → delete |
| 避免热点 key | 高频 prepend 可能影响性能 |
8. 调试与监控
# 查看 prepend 统计
echo "stats" | nc 127.0.0.1 11211 | grep cmd_prepend
# cmd_prepend: 50
# prepend_hits: 48
# prepend_misses: 2
# 检查长度
value = client.get('log:events')
print(f"当前长度: {len(value)} 字节")
9. 常见错误
| 错误 | 原因 | 解决 |
|---|---|---|
NOT_STORED | key 不存在 | 先 set |
SERVER_ERROR object too large | 超 1MB | 分片 |
| 数据错位 | 无分隔符 | 加 | 或 \n |
10. 小结:prepend 命令速查
prepend 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 文件(用
prepend倒序组装)
需要 CAS 安全更新、delete 命令、大对象分片方案?继续问我!