跳至主要內容

Redis-Key命名规范

微信公众号:储凡About 21 min

Redis-Key命名规范

建议风格一致

key的书写风格保持一致,常见的变量风格有:

  • 同时大驼峰,例如:UserAdmin
  • 同时小驼峰,例如:userAdmin
  • 同时下划线,例如:user_admin

做到项目级别的风格统一; 个人建议采用小驼峰

长度约束

  • key不能太长也不能太短,合理设计
  • 键名越长越占资源,太短可读性太差

以冒号分开

  • redis-key 单词与单词之间以,冒号:分开

  • 市面上的redis可视化工具,冒号:比较容易进行下级选择和业务分类

使用命名空间

一个项目一个命名空间,项目内业务不同命名空间也不同

一般情况下:

  • 第一段放置项目名或缩写 ,例如: userAdmin

  • 第二段把表名转换为key前缀,例如: user

  • 第三段放置用于区分区key的字段,对应mysql中的主键的列名,例如:id

  • 第四段放置主键值,如18,16

结合起来 PRO:USER:UID:18 直接意思就是,xx项目下的xx表中xx字段对应的值

以上是单机模式,当在redis集群中使用相关业务时候,常常需要将部分业务散列到相同的slot中,这时hash tag的作用就显得 非常重要; 做法是在key中添加{}前缀prefix

key分发模型

key空间分为16384个槽,有效地设置了16384个主节点的簇大小的上限(但建议的最大节点大小约为1000个节点)。 集群中的每个主节点处理16384个散列槽的子集。

当没有正在进行的集群重新配置时(即散列插槽从一个节点移动到另一个节点),集群是稳定的。

当集群稳定时,单个节点将提供单个散列槽(但是,在网络分裂或故障的情况下,服务节点可以有一个或多个将替换它的从属,并且可以用于扩展读取过时数据的读取操作)。 用于将键映射到散列槽的基本算法如下(读取此规则的散列标记异常的下一段):

HASH_SLOT = CRC16(key) mod 16384
  • Name:XMODEM(也称为ZMODEM或CRC-16 / ACORN)
  • Width:16位
  • Poly:1021(实际上是x^16 + x^12 + x^5 + 1)
  • Initialization:0000
  • Reflect Input byte:False
  • Reflect Output CRC:错误
  • Xor constant to output CRC:0000
  • Output for "123456789":31C3

使用16个CRC16输出位中的14个(这就是为什么在上面的公式中存在模16384运算的原因)。

在实际测试中,CRC16在16384个插槽中均匀分配不同类型的key时表现非常出色。

键哈希标签

计算用于实现散列标记的散列槽有一个例外。 散列标记是一种确保在同一散列槽中分配多个key的方法。这用于在Redis集群中实现多键操作。 为了实现散列标签,在某些条件下以稍微不同的方式计算key的散列槽。

如果key包含一个{...}模式仅是{and}之间的子串 ,以获得散列slot被散列。

但是,由于可能存在多次出现{or},以下规则很好地指定了算法:

  • 如果key包含一个{字符。
  • 如果{右边有一个字符}
  • 如果第一次出现{和第一次出现}之间有一个或多个字符。

如果满足条件三,不是对key进行散列,而是仅对第一次出现{和第一次出现}之间的内容进行散列。

例如:

  • 两个key{user1000}.following{user1000}.followers将散列到相同的散列slot, 因为只有在子串user1000会计算散列slot。

  • 对于键foo{}{bar},通常将整个键进行哈希处理,因为第一次出现{右侧是},而中间没有字符。

  • 对于键foo{{bar}}zap,子串{bar将被散列,因为它是第一次出现{和右边第一次出现}之间的子串。

  • 对于keyfoo{bar}{zap}的子串bar将被散列,算法在第一个有效或无效(无内部字节)匹配{and}后停止匹配。

该算法的结果是,如果key开头{},则保证整个散列。当使用二进制数据作为键名时,这很有用。

使用规范

在项目中,redis属于高频使用,遇到了各种各样的redis问题,针对自身情况梳理了一个redis使用规范。

Key的设计

  • 禁止包含特殊字符(比如空格、换行、单双引号以及其他转义字符)

  • 建议风格一致 建议同时大驼峰、同时小驼峰或者下划线;是项目级别的统一

  • key不能太长也不能太短,键名越长越占资源,太短可读性太差

  • key 单词与单词之间以冒号分开。市面上的redis可视化工具,:比较容易进行下级选择

  • redis使用的时候注意命名空间,一个项目一个命名空间,项目内业务不同命名空间也不同

一般情况下:

  • 第一段放置项目名或缩写 如 project
  • 第二段把表名转换为key前缀 如, user:
  • 第三段放置用于区分区key的字段,对应mysql中的主键的列名,如userid
  • 第四段放置主键值,如18,16

结合起来 PRO:USER:UID:18 就很清晰

value设计

  • 拒绝大key操作,禁用超过10K的string大key(虽然redis支持512MB大小的string),如果1mb的key每秒重复写入10次,就会导致写入网络IO达10MB。

  • 设计key时使用合适的数据类型(在资源利用和性能之间作平衡)。例如:将一个普通字符串弄成hash类型进行存储这是不合理的

  • 控制key的生命周期,例如:key设置为永不过期是不合理的,也不建议过期时间全部一样,避免key大面积失效,mysql被打满

  • 控制value长度。例如string类型,如果value为'8个字节的长整型'则内部使用int类型,如果value为'小于等于39个字节的字符串'则内部使用embstr类型,如果value为'大于39个字节的字符串'则内部使用raw类型。这样能很好的利用redis的性能。

数据按需存储

不需要的数据千万不要存储在redis,只会浪费内存空间

命令使用

  • 禁止使用keys、flushall、hmgetall等命令

为防止业务研发的误操作,通常可以在交付redis实例之前将默认命令rename掉;而真正需要删除或者遍历key时可以使用scan家族命令

  • 慎用hgetall、lrange、smembers、zrange等命令

除非业务场景需要,尽量不要使用这些命令。如果没有控制好会导致操作量过大,形成阻塞。

项目实战

  • 项目redis使用问题

当前的使用方式是,每个接入的应用要配置核心项目的redis配置。这样是不合理的,核心项目的redis应该只能在核心项目中使用,对外应该是提供api接口或者rpc进行访问。

  • 注意key的过期时间设置

在报名等高峰期的时候,key值设置过短容易造成缓存穿透,导致大量请求直接打到mysql数据库。

  • 提防缓存穿透

空值也应该被缓存,经常使用会只给有数据的结果进行缓存,结果导致空数据无法缓存,相同查询直接每次都到达数据库,所以

  • 不建议将redis做为消息队列

如没有非常特殊的需求,严禁将 Redis 当作消息队列使用。redis 当作消息队列使用,会有容量、网络、效率、功能方面的多种问题。 如需要消息队列,可使用高吞吐的 Kafka 或者高可靠的 RocketMQ,nsq,(花园同步有时间前后要求,且量不大才使用的)。

查询使用

线上Redis禁止使用Keys正则匹配操作

redis是单线程处理,在线上Key数量较多时,操作效率极低【时间复杂度为O(N)】,该命令一旦执行会严重阻塞线上其它命令的正常请求,而且在高QPS情况下会直接造成redis服务崩溃!如果有类似需求,可以使用scan命令代替。

参考资料