使用规范
key 命名
分隔符
分隔符使用 :
而不是下划线,:
是一些可视化工具默认的分隔符,在可视化工具中可以清晰的查看。
可读性
以业务名为前缀,用冒号分隔,可使用业务名:子业务名:id的结构命名,子业务下多单词可再用下划线分隔
举例:消费金融订单审核锁,可命名为 ecm:product:lock:verify:{productSerialNid}
简洁性
保证语义的前提下,控制 key 的长度,当 key 较长时,内存占用也不容忽视
A few other rules about keys(关于 key 的一些其他规则):
- Very long keys are not a good idea. For instance a key of 1024 bytes is a bad idea not only memory-wise, but also because the lookup of the key in the dataset may require several costly key-comparisons. Even when the task at hand is to match the existence of a large value, hashing it (for example with SHA1) is a better idea, especially from the perspective of memory and bandwidth.
- Very short keys are often not a good idea. There is little point in writing “u1000flw” as a key if you can instead write “user:1000:followers”. The latter is more readable and the added space is minor compared to the space used by the key object itself and the value object. While short keys will obviously consume a bit less memory, your job is to find the right balance.
- Try to stick with a schema. For instance “object-type:id” is a good idea, as in “user:1000”. Dots or dashes are often used for multi-word fields, as in
comment:1234:reply.to
orcomment:1234:reply-to
. - The maximum allowed key size is 512 MB.
关于key有一些其他的规则:
- 非常长的key是不推荐的。一个
1024 bytes
是一个非常坏的注意,不仅仅是因为内存浪费,更是因为在数据集中搜索对比的时候需要耗费更多的成本。当要处理的是匹配一个非常大的值,从内存和带宽的角度来看,使用这个值的hash
值是更好的办法(比如使用SHA1
)。 - 特别短的key通常也是不推荐的。在写像u100flw这样的键的时候,有一个小小的要点,我们可以用
user:1000:followers
代替。可读性更好,对于key对象和value对象增加的空间占用与此相比来说倒是次要的。当短的key可以很明显减少空间占用的时候,你的工作就是找到正确的平衡 - 尝试去固定一个密室。比如
object-type:id
是一个好主意,-和.通常用于多个字符的域,就像comment:1234:reply.to
,或者comment:1234:reply-to
。 - 最大的
key
允许512MB
不包含转义字符
不包含空格、换行、单双引号以及其他转义字符
过期时间和淘汰策略
注意设置合理的过期时间
默认策略是 volatile-lru,即超过最大内存后,在过期键中使用lru算法进行key的剔除,保证不过期数据不被删除,但是可能会出现OOM问题。
其他策略如下:
- allkeys-lru:根据LRU算法删除键,不管数据有没有设置超时属性,直到腾出足够空间为止;
- allkeys-random:随机删除所有键,直到腾出足够空间为止;
- volatile-random:随机删除过期键,直到腾出足够空间为止;
- volatile-ttl:根据键值对象的ttl属性,删除最近将要过期数据。如果没有,回退到noeviction策略;
- noeviction:不会剔除任何数据,拒绝所有写入操作并返回客户端错误信息”(error) OOM command not allowed when used memory”,此时Redis只响应读操作;
安全
- 给 Redis 设置一个不简单的密码
- 修改默认端口号
命令使用
- 禁止使用 keys 命令,性能堪忧;
- 禁止使用 flushall、flushdb 命令,防止误删数据;
- O(N) 命令关注N的数量 hgetall、lrange、smembers、zrange、sinter 等并非不能使用,但是需要明确N的值。有遍历的需求可以使用hscan、sscan、zscan代替;
- 使用批量操作提高效率;
做好监控
Redis 在大多数情况下作为缓存和分布式锁使用,在项目初期每个 key
的作用还能凭借记忆来记住,等 key
多的时候,就不能可光靠某几个人记忆来记住了。当 key
无法被明确知道起什么作用的情况下,就会变成遗留代码(无人知道、无人敢改的代码)。良好的团队氛围应该去追踪每个 key
的使用。
跟踪格式示例
缓存 key
key | 占位符 | 场景 | ttl | 用途 |
---|---|---|---|---|
ecm:handholdIdCardInfo:retry:{requestNo} | 活体请求流水号 | 活体认证 | 30 分钟 | 保存同一个流水号手持身份认证已经重试了多少次 |
ecm:product:create:{userId} | 用户userId | 进件 | 5s | 保证一个用户5s内只能同时进一个订单,老版本,应该废弃 |
分布式锁 key
key | 占位符 | try 时间 | 最大ttl | 用途 |
---|---|---|---|---|
lock:product:verify:{productSerialNid} | 消金标号 | 0 | 10 分钟 | 锁定标的审核,同一个标的同时只能有一个审核 |
lock:redis:create_pre_loan_stage_handler:{productSerialNid} | 消金标号 | 30s | 防止用户 30s 内重复进行验密受托支付 |
其他问题
在使用缓存时还有其他问题,比如 缓存穿透、缓存击穿、缓存雪崩、热点 key,这些都是在编写程序时也应该注意的。