应使用INCR而非SET+读取再加一,因其是原子操作可避免并发写覆盖;INCR返回新值而非增量,需直接使用;键名须绑定业务ID并避免注入;集群下单key操作安全,但批量操作需同slot。

为什么不用 SET + 读取再加一来更新访问量
因为会丢数据。并发请求同时读到旧值 100,各自加一后都写回 101,实际应为 102。这不是“偶尔出错”,而是高并发下必然发生的竞态条件。
INCR 是原子指令,Redis 服务端内部完成读-改-写,客户端无需参与中间状态。哪怕每秒上万次请求,INCR 也能保证结果准确。
- 不要在应用层做
GET→ 计算 →SET的三步操作 - 避免用
INCRBY传负数来“减访问量”,业务逻辑里不该有这种反向操作 - 如果需要初始化,直接用
SET article:123:views 0 NX(NX表示仅当 key 不存在时才设)
INCR 返回值怎么用才不踩坑
INCR 返回的是自增后的最新值,不是增量。很多人误以为它返回 1,结果把返回值当增量累加,导致计数翻倍。
典型错误:收到返回 105,又拿它去数据库再加一次 105;正确做法是直接拿这个 105 当当前总访问量用。
- 返回值类型是整数,不是字符串,别用
parseInt()多此一举(Node.js/Python 客户端已自动转) - 如果 key 不存在,
INCR会先设为0再加一,返回1—— 这是设计行为,不是 bug - 注意某些客户端(如旧版 jedis)对大整数返回可能截断,确保用较新版本(jedis ≥ 4.0,redis-py ≥ 4.0)
缓存键怎么设计才不容易冲突或爆炸
键名不是越短越好,而是要兼顾唯一性、可读性和生命周期管理。比如用 article:123:views 比 a123v 更稳妥。
关键点在于:必须和文章 ID 强绑定,且不能和其他业务共用同一级命名空间,否则 TTL 设置、批量清理都会出问题。
- 避免使用用户输入直接拼接键名,防止注入(如文章 ID 是
123; DEL article:*就危险) - 不要给访问量 key 单独设过期时间(
EXPIRE),它应该和文章元数据生命周期一致;若文章下线,一起删掉article:123:*相关所有 key - 如果文章有多个维度统计(如日活、总览),建议拆成不同 key:
article:123:daily_views、article:123:total_views,别塞进一个 hash
INCR 在 Redis 集群模式下还安全吗
安全,但有前提:key 必须落在同一个 slot 上。Redis Cluster 要求原子操作的多个 key 属于同一 slot,而单个 INCR 只操作一个 key,天然满足。
真正的问题是——如果你后续想用 MGET article:123:views article:456:views 批量查,而这两个 key 哈希后不在同个节点,就会报 CROSSSLOT Keys in request don't hash to the same slot 错误。
- 单 key 的
INCR、GET、EXPIRE全部兼容集群,放心用 - 批量操作前,用
{article:123}这种标签强制哈希到同一 slot(例如{article:123}:views和{article:123}:title) - 别依赖
KEYS article*:views做扫描,集群不支持;要用SCAN配合客户端过滤
最常被忽略的一点:INCR 不会自动创建带过期时间的 key。你得自己配 EXPIRE 或用 SET article:123:views 0 NX EX 86400 初始化,否则 key 会永久存在,哪怕文章早被删了。










