Memcached计数器操作 #

一、计数器概述 #

1.1 计数器命令 #

text
Memcached提供以下计数器命令:

incr - 递增计数器
decr - 递减计数器

1.2 计数器特点 #

text
计数器特点:

1. 原子操作
   - 线程安全
   - 无需加锁

2. 只能操作数字
   - 值必须是数字字符串
   - 非数字值会返回错误

3. 64位无符号整数
   - 范围:0 ~ 18446744073709551615
   - 溢出后回绕

4. 键不存在返回NOT_FOUND
   - 需要先初始化计数器

二、incr命令 #

2.1 命令说明 #

text
incr命令:
- 递增计数器
- 原子操作
- 返回递增后的值

语法:
incr <key> <value> [noreply]\r\n

响应:
<value>     - 递增后的新值
NOT_FOUND   - 键不存在
ERROR       - 值不是数字

2.2 基本使用 #

bash
# 初始化计数器
set counter 0 0 1
0
STORED

# 递增1
incr counter 1
1

# 递增5
incr counter 5
6

# 递增10
incr counter 10
16

# 查看当前值
get counter
VALUE counter 0 0 2
16
END

2.3 递增任意值 #

bash
# 初始化
set views 0 0 1
0
STORED

# 递增100
incr views 100
100

# 递增1000
incr views 1000
1100

# 递增1
incr views 1
1101

2.4 键不存在 #

bash
# 键不存在时返回NOT_FOUND
incr notexist 1
NOT_FOUND

# 需要先初始化
set notexist 0 0 1
0
STORED

incr notexist 1
1

2.5 非数字值 #

bash
# 存储非数字值
set text 0 0 5
hello
STORED

# 尝试递增
incr text 1
ERROR

# 需要先删除再初始化
delete text
DELETED

set text 0 0 1
0
STORED

incr text 1
1

三、decr命令 #

3.1 命令说明 #

text
decr命令:
- 递减计数器
- 原子操作
- 返回递减后的值

语法:
decr <key> <value> [noreply]\r\n

响应:
<value>     - 递减后的新值
NOT_FOUND   - 键不存在
ERROR       - 值不是数字

3.2 基本使用 #

bash
# 初始化计数器
set counter 0 0 2
10
STORED

# 递减1
decr counter 1
9

# 递减3
decr counter 3
6

# 递减5
decr counter 5
1

# 查看当前值
get counter
VALUE counter 0 0 1
1
END

3.3 递减边界 #

bash
# 初始化为5
set counter 0 0 1
5
STORED

# 递减3
decr counter 3
2

# 递减10(超过当前值)
decr counter 10
0

# Memcached不会出现负数
# 递减到0为止

3.4 递减任意值 #

bash
# 初始化
set stock 0 0 3
100
STORED

# 递减10
decr stock 10
90

# 递减50
decr stock 50
40

# 递减1
decr stock 1
39

四、计数器溢出 #

4.1 上溢 #

bash
# 64位无符号整数最大值
# 18446744073709551615

# 设置接近最大值
set counter 0 0 20
18446744073709551615
STORED

# 递增后溢出回绕
incr counter 1
0

# 继续递增
incr counter 1
1

4.2 下溢 #

bash
# 设置为0
set counter 0 0 1
0
STORED

# 递减(已经是0)
decr counter 1
0

# 不会出现负数
decr counter 100
0

五、应用场景 #

5.1 页面访问计数 #

bash
# 初始化页面访问计数
set page:views:home 0 0 1
0
STORED

# 每次访问递增
incr page:views:home 1
1
incr page:views:home 1
2
incr page:views:home 1
3

# 获取当前访问量
get page:views:home
VALUE page:views:home 0 0 1
3
END

5.2 API调用统计 #

bash
# 初始化API调用计数
set api:calls:weather 0 86400 1
0
STORED

# 每次调用递增
incr api:calls:weather 1
1
incr api:calls:weather 1
2

# 统计每日调用量(设置24小时过期)
set api:calls:weather:20240101 0 86400 1
0
STORED
incr api:calls:weather:20240101 1
1

5.3 点赞/踩统计 #

bash
# 初始化点赞数
set article:1001:likes 0 0 1
0
STORED

# 点赞
incr article:1001:likes 1
1

# 取消点赞
decr article:1001:likes 1
0

# 初始化踩数
set article:1001:dislikes 0 0 1
0
STORED

# 踩
incr article:1001:dislikes 1
1

5.4 库存管理 #

bash
# 初始化库存
set product:1001:stock 0 0 3
100
STORED

# 扣减库存
decr product:1001:stock 1
99

# 批量扣减
decr product:1001:stock 10
89

# 补充库存
incr product:1001:stock 50
139

# 检查库存
get product:1001:stock
VALUE product:1001:stock 0 0 3
139
END

5.5 限流计数 #

bash
# 用户限流(每分钟最多100次)
set rate:user:1001 0 60 1
0
STORED

# 每次请求递增
incr rate:user:1001 1
1

# 检查是否超过限制
get rate:user:1001
VALUE rate:user:1001 0 0 2
50
END

# 如果超过100,拒绝请求

5.6 分布式ID生成 #

bash
# 初始化ID序列
set global:user:id 0 0 1
0
STORED

# 生成新ID
incr global:user:id 1
1
incr global:user:id 1
2
incr global:user:id 1
3

# 批量生成ID
incr global:user:id 100
103

# 返回的值是递增后的值
# 所以ID范围是 4-103

5.7 在线人数统计 #

bash
# 初始化在线人数
set online:count 0 0 1
0
STORED

# 用户上线
incr online:count 1
1

# 用户下线
decr online:count 1
0

# 获取当前在线人数
get online:count
VALUE online:count 0 0 1
5
END

六、高级用法 #

6.1 批量计数器 #

bash
# 初始化多个计数器
set counter:page:home 0 0 1
0
STORED
set counter:page:about 0 0 1
0
STORED
set counter:page:contact 0 0 1
0
STORED

# 批量递增
incr counter:page:home 1
1
incr counter:page:about 1
1
incr counter:page:contact 1
1

6.2 时间窗口计数 #

bash
# 按小时统计
set counter:hour:2024010110 0 86400 1
0
STORED
incr counter:hour:2024010110 1
1

# 按天统计
set counter:day:20240101 0 604800 1
0
STORED
incr counter:day:20240101 1
1

# 按月统计
set counter:month:202401 0 2592000 1
0
STORED
incr counter:month:202401 1
1

6.3 多维度统计 #

bash
# 按用户统计
set counter:user:1001:views 0 0 1
0
STORED
incr counter:user:1001:views 1
1

# 按类型统计
set counter:type:article:views 0 0 1
0
STORED
incr counter:type:article:views 1
1

# 按地区统计
set counter:region:beijing:views 0 0 1
0
STORED
incr counter:region:beijing:views 1
1

七、计数器初始化 #

7.1 使用set初始化 #

bash
# 标准初始化方法
set counter 0 0 1
0
STORED

incr counter 1
1

7.2 使用add初始化 #

bash
# 使用add避免覆盖已存在的计数器
add counter 0 0 1
0
STORED

# 如果已存在,add失败
add counter 0 0 1
0
NOT_STORED

# 然后直接incr
incr counter 1
1

7.3 自动初始化代码 #

python
def init_counter(key, default=0):
    # 尝试初始化
    result = client.add(key, str(default), noreply=True)
    
    # 无论如何都可以递增
    return client.incr(key, 1)

def safe_incr(key, delta=1, default=0):
    # 先尝试递增
    result = client.incr(key, delta)
    
    if result is None:
        # 键不存在,初始化后再递增
        client.set(key, str(default))
        result = client.incr(key, delta)
    
    return result

八、计数器最佳实践 #

8.1 键命名规范 #

bash
# 好的命名
counter:page:views:home
counter:api:calls:weather
counter:user:1001:likes

# 不好的命名
counter1
page_views
api-calls

8.2 过期时间设置 #

bash
# 永久计数器(不过期)
set counter:total:users 0 0 1
0

# 临时计数器(设置过期时间)
set counter:rate:user:1001 0 60 1
0

# 按时间窗口设置过期
set counter:hour:2024010110 0 86400 1
0

8.3 数值范围检查 #

python
def safe_decr(key, delta=1):
    # 先获取当前值
    value = client.get(key)
    
    if value is None:
        return 0
    
    current = int(value)
    
    # 检查是否会递减到负数
    if current < delta:
        # 设置为0
        client.set(key, "0")
        return 0
    
    # 正常递减
    return client.decr(key, delta)

8.4 并发安全 #

bash
# incr/decr是原子操作,天然支持并发

# 多个客户端同时递增
# 客户端A
incr counter 1
101

# 客户端B
incr counter 1
102

# 结果正确,不会丢失更新

九、性能优化 #

9.1 使用noreply #

bash
# 不等待响应,提高性能
incr counter 1 noreply
decr counter 1 noreply

# 适用于不需要立即获取结果的场景

9.2 批量操作 #

bash
# 使用Pipeline批量操作
# 客户端支持Pipeline时

pipeline = client.pipeline()
pipeline.incr("counter1", 1)
pipeline.incr("counter2", 1)
pipeline.incr("counter3", 1)
results = pipeline.execute()

9.3 本地缓存 #

python
# 对于频繁读取的计数器,可以使用本地缓存

class CachedCounter:
    def __init__(self, client, key, ttl=1):
        self.client = client
        self.key = key
        self.ttl = ttl
        self.cache = None
        self.last_update = 0
    
    def get(self):
        now = time.time()
        if now - self.last_update > self.ttl:
            self.cache = self.client.get(self.key)
            self.last_update = now
        return self.cache
    
    def incr(self, delta=1):
        result = self.client.incr(self.key, delta)
        self.cache = result
        self.last_update = time.time()
        return result

十、错误处理 #

10.1 常见错误 #

bash
# 1. 键不存在
incr notexist 1
NOT_FOUND

# 2. 值不是数字
set text 0 0 5
hello
STORED
incr text 1
ERROR

# 3. 递增值不是数字
incr counter abc
ERROR

10.2 错误处理代码 #

python
def safe_incr(key, delta=1, default=0):
    try:
        result = client.incr(key, delta)
        
        if result is None:
            # 键不存在,初始化
            client.set(key, str(default))
            result = client.incr(key, delta)
        
        return result
    except Exception as e:
        # 处理其他错误
        print(f"Error: {e}")
        return None

def safe_decr(key, delta=1):
    try:
        result = client.decr(key, delta)
        
        if result is None:
            return 0
        
        return result
    except Exception as e:
        print(f"Error: {e}")
        return None

十一、总结 #

计数器命令要点:

命令 说明 响应
incr 递增 新值/NOT_FOUND/ERROR
decr 递减 新值/NOT_FOUND/ERROR

计数器特点:

  1. 原子操作,线程安全
  2. 64位无符号整数
  3. 溢出后回绕
  4. 递减不会出现负数

应用场景:

  1. 访问计数
  2. API统计
  3. 点赞/踩
  4. 库存管理
  5. 限流
  6. 分布式ID

下一步,让我们学习Memcached的高级特性!

最后更新:2026-03-27