Memcached replace 命令详解(2025 版)
replace 是 Memcached 的 “仅当 key 存在时更新” 命令,是 防止误创建 的原子操作。
与 set 区别:
set:存在覆盖,不存在创建
replace:存在才更新,不存在则失败
1. 基本语法
replace <key> <flags> <exptime> <bytes> [noreply]\r\n
<value>\r\n
参数 说明 <key>键名(≤ 250 字节) <flags>客户端自定义标志(0~65535) <exptime>过期时间(秒) <bytes>Value 字节数 [noreply]可选,异步写入 <value>实际数据
响应:
STORED\r\n → 成功(key 已存在)
NOT_STORED\r\n → 失败(key 不存在)
2. telnet 实际操作示例
telnet 127.0.0.1 11211
示例 1:key 存在 → replace 成功
# 先 set 一个 key
set user:1001 0 0 8
zhangsan
STORED
# 再 replace
replace user:1001 0 0 5
lisi
STORED
示例 2:key 不存在 → replace 失败
replace user:9999 0 0 5
wangwu
NOT_STORED
3. 客户端使用 replace
Python(pymemcache)
from pymemcache.client.base import Client
client = Client(('127.0.0.1', 11211))
# 先确保存在
client.set('config:version', 'v1.0.0')
# replace 返回 True/False
result = client.replace('config:version', 'v1.0.1', expire=3600)
print(result) # True
result = client.replace('config:unknown', 'v2.0.0')
print(result) # False(key 不存在)
PHP
$mc = new Memcached();
$mc->addServer('127.0.0.1', 11211);
$mc->set('counter:views', 100);
// 仅当存在时更新
if ($mc->replace('counter:views', 101)) {
echo "更新成功";
} else {
echo "key 不存在";
}
Java(XMemcached)
client.set("user:1", 0, "old");
// 仅当存在时替换
boolean ok = client.replace("user:1", 3600, "new");
System.out.println(ok); // true
4. replace vs set vs add
命令 key 不存在 key 存在 用途 addSTORED NOT_STORED 初始化 setSTORED STORED 通用写入 replaceNOT_STORED STORED 仅更新
# 演示对比
add newkey 0 0 3 → STORED
set newkey 0 0 3 → STORED(覆盖)
replace newkey 0 0 3 → STORED
replace missing 0 0 1 → NOT_STORED
5. 经典应用场景
5.1 防止误覆盖初始化数据
# 启动时只初始化一次
if not client.get('app:initialized'):
client.add('app:initialized', 'yes', expire=0)
init_database()
# 后续只能 replace,不能 add
client.replace('app:initialized', 'reloaded', expire=0)
5.2 缓存更新(防穿透)
def get_user(uid):
key = f'user:{uid}'
data = client.get(key)
if data is None:
data = db.query(uid)
client.add(key, data, 3600) # 首次写入
else:
# 已有缓存,可安全更新
client.replace(key, fresh_data, 3600)
return data
5.3 计数器更新(配合 incr)
# 初始化
add counter:page 0 0 1
0
STORED
# 后续只能 replace 或 incr
replace counter:page 0 0 1
5
STORED
# 推荐用 incr
incr counter:page 1
6
5.4 热点数据刷新
# 定时任务:仅当缓存存在时刷新
if client.get('hot:news'):
fresh = fetch_latest_news()
client.replace('hot:news', fresh, expire=300)
6. 高级技巧
6.1 replace + get 实现“存在即更新”
value = client.get('cache:key')
if value is not None:
new_value = update_value(value)
client.replace('cache:key', new_value, expire=3600)
6.2 noreply 异步 replace
client.replace('log:count', new_count, noreply=True)
7. 过期时间 exptime 详解
值 含义 0永不过期 3005 分钟后过期 1739431200绝对时间戳
8. 常见错误
错误 原因 解决 NOT_STOREDkey 不存在 先 set 或 add CLIENT_ERROR参数错误 检查格式 SERVER_ERROR内存不足 增加 -m
9. 最佳实践
建议 说明 用 replace 防止误创建 适合配置、状态更新 配合 add 做 初始化 + 更新 完整生命周期 热点数据用 replace 刷新 避免缓存穿透 不要用 replace 做首次写入 会失败 key 命名清晰 state:job:xx、cache:config:xx
10. 调试与统计
# 查看 replace 统计
echo "stats" | nc 127.0.0.1 11211 | grep cmd_replace
# cmd_replace: 15
# replace_hits: 12
# replace_misses: 3
小结:replace 命令速查
replace key flags exptime bytes [noreply]
└─> STORED(仅当 key 存在)
└─> NOT_STORED(key 不存在)
项目 推荐值 flags与原值一致 exptime300 ~ 3600bytes< 100KBnoreply高并发启用
练习建议
用 telnet 实现“只能更新已有 key”
用 Python 实现 配置热更新
模拟缓存重建:add → 正常运行 → replace 刷新
需要 CAS 乐观锁、append/prepend、或 flush_all 命令?继续问我!