bigywater.tech
Django · 94

Cache Key 的生成规则

cache.set("user:1", ...) 在 Redis 里到底存成什么 key?version 有什么用?key 有什么限制?多个项目共用一个 Redis 会不会互相踩?这篇直接看 Redis 里的 key。

shop:1:user:1
KEY_PREFIX=shop、VERSION=1 时,cache.set("user:1") 在 Redis 里的 key
VERSION
整体递增 VERSION 可以批量作废旧缓存
共用 Redis
不同项目必须用不同 KEY_PREFIX,否则同名 key 互相覆盖

key 的组成

实测 · 本机执行输出
make_key(default)  : shop:1:user:1
make_key(plain 没有前缀): :1:user:1
make_key(custom 自定义函数): k|v3|user:1
  Redis db0 里的 key(default(KEY_PREFIX=shop)): ['shop:1:user:1']
  Redis db1 里的 key(plain(无前缀)): [':1:user:1']
  Redis db2 里的 key(custom): ['k|v3|user:1']

缓存后端调用 make_key(key, version)。所以在 redis-cli 里排查缓存时,要带上前缀和版本号。

version

实测 · 本机执行输出
get('k') 默认版本 = v1  version=2: v2  version=3: None
incr_version("k") 返回 2  之后 version=2 的 = v1  version=3 的 = None  旧版本 1: None (incr_version 把 v1 移到了 v2,原来的 v2 被覆盖)

做代码升级时,如果新旧版本缓存的数据结构不兼容,提高 VERSION(或者在 key 里带版本)可以避免读到旧格式。

key 的限制

实测 · 本机执行输出
警告条数: 2 ['Cache key contains characters that will cause errors if used', "Cache key will cause errors if used with memcached: 'shop:1:"]
get('has space') = 1  get(300 字符 key) = 1  get(unicode键) = 1
<实验目录> CacheKeyWarning: Cache key contains characters that will cause errors if used with memcached: 'shop:1:has space'
  warnings.warn(warning, CacheKeyWarning)
<实验目录> CacheKeyWarning: Cache key will cause errors if used with memcached: 'shop:1:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' (longer than 250)
  warnings.warn(warning, CacheKeyWarning)

用户输入做 key 时要清洗(空格、过长):比如把用户名 md5 一下再放进 key。

隔离

实测 · 本机执行输出
同一个后端、同一个前缀下,另一个应用写同名 key 会覆盖: from-app-B
不同 KEY_PREFIX 互相隔离:default 与 custom 的 "shared" -> from-app-B / None

另外,cache.clear() 在共享 Redis 库上会清空整个数据库(本文没有测),生产里慎用。

分步演示:缓存 key

缓存 Key
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 / Python 3.14.7 / Django 6.1.1(默认用 SQLite,其它数据库会在文中注明),用 django.test.Client 或真实的本机服务器进程实测;计时用 time.perf_counter,数字每次运行会有小幅抖动。Redis 8.10.2 本机临时实例(端口 9462);key 用 redis-cli 风格的 KEYS 查看
    • 没有验证:memcached 的 key 限制实际报错、KEY_FUNCTION 在多进程中的稳定性、Redis Cluster 下的 key 分布、cache.clear() 的具体行为
    京ICP备2026067502号-1京公网安备11010502063487号