Memcached incr 与 decr 命令

Memcached incrdecr 命令详解(2025 版)

incr(increase)和 decr(decrease)是 Memcached 的 原子计数器操作,用于 高并发场景下的安全计数

核心优势:

  • 原子性:无需锁,避免竞态
  • 高性能:服务端直接操作,微秒级
  • 自动创建decr 时不存在可设初始值

1. 基本语法

incr — 原子加法

incr <key> <value> [noreply]\r\n

decr — 原子减法

decr <key> <value> [noreply]\r\n
参数说明
<key>计数器键名
<value>增减步长(正整数)
[noreply]异步操作

响应

  • <new_value>\r\n → 当前值(成功)
  • NOT_FOUND\r\n → key 不存在(incr 失败,decr 可自动创建)

2. telnet 完整示例

telnet 127.0.0.1 11211
# 1. 初始化计数器
set counter:views 0 0 1
0
STORED

# 2. 原子 +1
incr counter:views 1
1

# 3. 连续 +1
incr counter:views 1
2

# 4. 原子 -1
decr counter:views 1
1

# 5. key 不存在时 incr → 失败
incr missing:counter 1
NOT_FOUND

# 6. key 不存在时 decr → 自动创建为 0
decr missing:counter 1
0

# 7. 异步操作
incr counter:views 5 noreply
# 无响应

3. 客户端使用

Python(pymemcache)

from pymemcache.client.base import Client

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

# 初始化
client.set('likes:1001', 100)

# 原子 +1
new_val = client.incr('likes:1001', 1)
print(new_val)  # 101

# 原子 -1(最小 0)
new_val = client.decr('likes:1001', 1)
print(new_val)  # 100

# 异步
client.incr('clicks:home', 1, noreply=True)

PHP

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

$mc->set('visits', 1000);

// +5
$mc->increment('visits', 5);
// -3
$mc->decrement('visits', 3);

// 不存在时自动创建
$mc->increment('new:counter', 1);  // → 1
$mc->decrement('new:counter', 1);  // → 0

Java(XMemcached)

client.set("score", 0, "50");
long newVal = client.incr("score", 10);
long decVal = client.decr("score", 5);

4. incr vs decr 行为对比

操作key 不存在最小值
incrNOT_FOUND(失败)无限制
decr自动创建为 0不能低于 0
# decr 不会负数
decr counter 100
0   ← 即使原值为 50,减 100 也只到 0

5. 经典应用场景

场景推荐命令
页面浏览量incr pv:{page_id} 1
视频播放数incr play:{vid} 1
点赞/点踩incr like:{id} 1
库存扣减decr stock:{sku} 1
限流计数incr rate:{ip} 1 + 过期

库存扣减(防超卖)

def buy_sku(sku_id, qty=1):
    key = f'stock:{sku_id}'
    new_stock = client.decr(key, qty)
    if new_stock is None:
        # 首次购买,初始化库存
        if client.set(key, 100 - qty):  # 初始 100
            return True
        return False
    if new_stock >= 0:
        return True
    else:
        # 超卖,回滚
        client.incr(key, qty)
        return False

6. 与 CAS 对比

方式适用场景性能
incr/decr纯计数最高
CAS复杂修改(如结构体)稍低

推荐:能用 incr 就用 incr


7. 高级技巧

7.1 批量计数(客户端循环)

# Memcached 无原生批量 incr
for uid in user_ids:
    client.incr(f'online:{uid}', 1)

7.2 带初始值的 decr

# 模拟库存初始 100
client.delete('stock:123')  # 确保不存在
client.decr('stock:123', 0)  # → 创建为 0
client.incr('stock:123', 100)  # → 设置为 100

7.3 限流器(每分钟 100 次)

key = f'rate:{ip}:2025'
client.incr(key, 1)
client.expire(key, 60)  # 1 分钟过期
if client.get(key) > b'100':
    return "限流"

8. 监控与统计

echo "stats" | nc 127.0.0.1 11211
指标说明
cmd_incrincr 次数
cmd_decrdecr 次数
incr_hits成功次数
decr_hits成功次数
# 实时监控
watch -n 1 "echo 'stats' | nc 127.0.0.1 11211 | grep -E 'incr|decr'"

9. 常见错误

错误原因解决
NOT_FOUNDincr 时 key 不存在set
值不变步长为 0检查参数
负数decr 超过当前值正常(自动到 0)
字符串错误value 不是数字只能用于数字字符串

警告incr 只能对 数字字符串 操作

set str 0 0 5
hello
STORED
incr str 1
CLIENT_ERROR cannot increment non-numeric value

10. 最佳实践

建议说明
set 初始值避免 NOT_FOUND
decr 防超卖自动到 0
异步 noreply高并发计数
定期归档get → 落库 → delete
key 命名pv:page:123, stock:sku:456

11. 小结:incr/decr 速查

incr key value [noreply]  → 新值 或 NOT_FOUND
decr key value [noreply]  → 新值(≥0)或 0
项目推荐
用途计数器、库存、限流
初始值set key 0 0 1 + "0"
最小值decr 自动到 0
异步noreply=True

练习建议

  1. 用 telnet 实现 页面 PV 计数器
  2. 用 Python 实现 商品库存扣减(支持并发)
  3. 实现 IP 限流(每分钟 10 次)
  4. 写一个 实时排行榜incr 点赞 → zadd 排序)

需要 touch 延长过期、flush_all 清理、stats 监控?继续问我!

文章已创建 2481

发表回复

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

相关文章

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

返回顶部