Memcached add 命令

Memcached add 命令详解(2025 版)

add 是 Memcached 的 “仅当 key 不存在时写入” 命令,是 防止并发覆盖 的原子操作。

set 区别:

  • set存在则覆盖
  • add存在则失败(返回 NOT_STORED

1. 基本语法

add <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:第一次 add → 成功

add user:1001 0 0 8
zhangsan
STORED

示例 2:再次 add 同一 key → 失败

add user:1001 0 0 5
lisi
NOT_STORED

说明:user:1001 已存在,拒绝写入


3. 客户端使用 add

Python(pymemcache)

from pymemcache.client.base import Client

client = Client(('127.0.0.1', 11211))

# add 返回 True/False
result = client.add('config:version', 'v1.0.0', expire=3600)
print(result)  # True(首次成功)

result = client.add('config:version', 'v2.0.0')
print(result)  # False(已存在,失败)

PHP

$mc = new Memcached();
$mc->addServer('127.0.0.1', 11211);

if ($mc->add('lock:job123', 'running', 300)) {
    echo "任务锁获取成功";
} else {
    echo "任务正在运行中";
}

Java(XMemcached)

boolean success = client.add("counter:init", 3600, "0");
if (success) {
    System.out.println("初始化成功");
}

4. add vs set vs replace

命令key 不存在key 存在用途
addSTOREDNOT_STORED初始化、锁、防重
setSTOREDSTORED(覆盖)通用写入
replaceNOT_STOREDSTORED仅更新
# 演示对比
add    newkey 0 0 5     → STORED
set    newkey 0 0 3     → STORED(覆盖)
replace newkey 0 0 2    → STORED
add    newkey 0 0 1     → NOT_STORED(已存在)

5. 经典应用场景

5.1 分布式锁(防并发)

def acquire_lock(lock_id, timeout=60):
    return client.add(f"lock:{lock_id}", "1", expire=timeout)

def release_lock(lock_id):
    client.delete(f"lock:{lock_id}")

多个进程竞争:只有第一个 add 成功


5.2 初始化配置(防止覆盖)

add app:config:db_host 0 0 9
127.0.0.1
STORED

后续 add 失败 → 保证配置只初始化一次


5.3 防止重复提交(防重令牌)

token = "submit_abc123"
if client.add(f"token:{token}", "1", expire=300):
    # 允许提交
    process_form()
else:
    # 重复提交
    return "请勿重复操作"

5.4 计数器初始化

add counter:page_views 0 0 1
0
STORED

后续用 incr 累加


6. 高级技巧

6.1 add + get 实现“存在即返回”

value = client.get('cache:key')
if value is None:
    if client.add('cache:key', compute_expensive(), expire=3600):
        value = client.get('cache:key')  # 再次读取
return value

防止缓存穿透时的并发计算


6.2 noreply 异步 add(高吞吐)

client.add('log:event', 'click', noreply=True)
# 不等待响应,继续执行

7. 过期时间 exptime 详解

含义
0永不过期
6060 秒后过期
1739431200绝对时间戳(2025-02-13 00:00:00)

8. 常见错误

错误原因解决
NOT_STOREDkey 已存在改用 setreplace
CLIENT_ERROR参数格式错检查空格、换行、bytes
SERVER_ERROR out of memory内存不足增加 -m 参数

9. 最佳实践

建议说明
add初始化防止重复设置
add分布式锁简单高效
配合 expire 自动释放防止死锁
key 命名清晰init:config:xxlock:job:xx
不要用 add 做频繁更新性能差

10. 调试与验证

# 查看 key 是否存在
get user:1001

# 查看 add 统计
echo "stats" | nc 127.0.0.1 11211 | grep cmd_add
# cmd_add: 10
# add_hits: 5
# add_misses: 5

小结:add 命令速查

add key flags exptime bytes [noreply]
└─> STORED(仅当 key 不存在)
   └─> NOT_STORED(key 已存在)
项目推荐值
flags0 或类型标记
exptime60 ~ 3600
bytes< 100KB
noreply高并发启用

练习建议

  1. 用 telnet 实现“只能 add 一次”的配置
  2. 用 Python 实现 分布式任务锁
  3. 模拟 100 个并发请求,只允许 1 个初始化

需要 replace 命令、CAS 乐观锁、incr/decr 计数器?继续问我!

文章已创建 2481

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部