Redis 规范

Key 规范

  • 命名
    • 使用服务名、模块名作为 Key 的固定前缀防止冲突,层级之间使用冒号分隔,例如:order:invoice:{id} 订单服务发票模块信息缓存
    • 尽量简洁,在保证语义的前提下简化 Key 的长度,例如:user:{uid}:friends:messages:{mid} 简化为 u:{uid}:fr:m:{mid}
    • 不要包含特殊字符,例如空格、换行、单双引号以及其他转义字符
  • 有效期
    • 正常情况下所有的 Key 必须设置过期时间
    • 设置合理的有效期,避免集中到期导致雪崩
    • 不应该有超长有效期的Key,有效期超过一个月需要确认
    • 可针对热点 key 设置永不过期(需要审批)
  • 长度
    • 单个 Key 长度不超过 16K

性能规范

  • 数据结构值约束
    • 简单的 string 类型 Key,单 Key 对应 Value 大小不超过 10K, 建议 1K 之内,太大会影响性能、网卡流量、慢查询,导致分片不均,QPS 下降
      • 测试数据: 单 Key 对应 Value 不同时做 Set 操作,QPS 测试结果:
        • Size:100byte 1k 10k 50k 100k 500k
        • QPS:9.7w 7.8w 7.3w 6.8w 4.2w 6400
    • 复杂类型 hash、list、set、zset 单 Key 对应 Value 大小不超过 1M,Key 的元素个数不要超过 1000
      • 复杂类型的 bigkey 不要使用 del 删除,使用 hscan、sscan、zscan 方式渐进式删除,同时要注意防止 bigkey 过期时间自动删除问题,例如一个 200 万的 zset 设置 1 小时过期,会触发 del 操作,造成阻塞,而且该操作不会不出现在慢查询中(latency可查)
  • 多 Key 命令约束
    • 单个多 Key 命令(mset、mget、del)的并发度限制在 100 以内
    • 测试数据:预置单 KV 大小 100 字节的 string,测试 mget 命令在不同并发度的平响时间时 QPS 测试结果:
并发数1050100300500750
平响时间(ms)2.73.54.281039
QPS75005300420021001400950
  • 使用批量操作提高效率
    • 原生命令:例如 mget、mset
    • 非原生命令:可以使用 pipeline 提高效率
    • 原生是原子操作,pipeline 是非原子操作,pipeline 可以打包不同的命令,需要客户端和服务端同时支持
  • 流水线命令约束
    • 每个 pipeline 批次下 key 数量限制在 500 以内,最好控制在 100 以内
    • 流水线命令不保证事务,只是将多次执行的命令进行合并,减少客户端与集群网络建立连接的开销
  • 禁止同时操作多个 Set 的命令
  • 禁止同时操作多个 List 的命令
  • 尽量让 Value 是数字,而不是字符串
    • 因为数字存储空间远比字符串要小,当数字或字符串Value均可以满足业务需求时,优先使用 Value 是数字的方案
  • 使用 Hash 来替代内容是 JSON 的 String
    • 对于 JSON 格式存储 Key-Value 内容的 String,可以使用 Hash 来替换,将 Key 存储在 Field 中,这样的好处是增删改单个 Key-Value 不再需要更新整个 JSON,性能更好
    • hmset user:1 name tom age 19 favor football
  • 设置好最大内存淘汰策略,参考 Key 的生与死
  • 监控
    • 应用需要添加 Redis 平响监控

命令使用规范

  • O(N) 命令关注 N 的数量
    • hgetall、lrange、smembers、zrange、sinter 等并非不能使用,但是需要明确 N 的值。有遍历的需求可以使用 hscan、sscan、zscan 代替
  • 禁用命令
    • 禁止线上使用 keys、flushall、flushdb 等,通过 redis 的 rename 机制禁掉命令,或者使用 scan 的方式渐进式处理
  • 合理使用 select
    • redis 的多数据库较弱,使用数字进行区分,很多客户端支持较差,同时多业务用多数据库实际还是单线程处理,会有干扰
  • Redis 事务功能较弱,不建议过多使用
    • Redis 的事务功能较弱(不支持回滚),而且集群版本(自研和官方)要求一次事务操作的 Key 必须在一个 slot 上(可以使用hashtag功能解决)
  • Redis 集群版本在使用 Lua 上有特殊要求
    • 所有 Key 都应该由 KEYS 数组来传递,redis.call/pcall 里面调用的 redis 命令,key的位置,必须是 KEYS array, 否则直接返回 error,"-ERR bad lua script for redis cluster, all the keys that the script uses should be passed using the KEYS array"
    • 所有 Key,必须在 1 个 slot 上,否则直接返回 error, "-ERR eval/evalsha command keys must in same slot"
  • 必要情况下使用 monitor 命令时,要注意不要长时间使用

参考资料