Redis 开发规范

规范的级别分为3个:强制推荐建议,其中强制表示必须这么做,否则会引起严重的错误或问题;推荐属于最佳实践的范畴,表示“强烈建议”这么做,这样会使设计或者开发过程更加规范、整洁,影响的是整个系统的健壮性或可维护性;建议则通常适用于一些特殊的设计,给出一种比较好的实现方式,在实际实现中可以有多种方式实现,而且选择哪种方式对系统的整体影响并不大。

1. key设计规范

1.1.key名称设计

  1. 可读性和可维护性 推荐

以业务系统为前缀,使用冒号进行多段分割,可以使用业务系统:表或模块:key进行组合设计,例如:

manager:device:332710
video:count:20220923

这样设计可以有效避免key的冲突,同时会使系统设计清晰规范,易于开发和问题定位。

如果业务系统名称太长,可以使用-分割或者使用简写方式。

  1. 简洁性 建议

在不影响语义和理解的前提下,可以适当使用简写控制key的长度,例如:

funnel-statistics:messages:jobs

可以简写为:

fs:m:jobs

具体简写的方式依赖于实际的业务抽象,特别是对于很长的连字符拼接的单词非常建议使用简写来替代,可以有效节省内存空间的占用。

  1. 不要包含特殊字符 强制

key中不要包含空格、换行、单引号以及其他转义字符,否则会对开发人员带来困扰或麻烦。

1.2.value设计

  1. 不要出现bigkey 强制

bigkey会带来慢查询和大量流量消耗,因此对value的长度要做出限制:

string类型长度限制在10KB以内,对于hash、list、set、zset类型中元素个数不要超过10000。

反例:线上使用Redis list作为简单队列,长度达到了200万。

解决:Redis用作消息队列适用于小规模的场景,同时生产者侧要控制好队列的长度,对于大规模消息的场景建议采用KafkaPulsar等专用的消息平台。

  1. bigkey删除 推荐

非string类型的bigkey,在删除时不要用del直接删除,而是采用hscansscanzscan等方式渐进删除,同时关注过期自动删除的问题,否则会容易出现慢查询导致阻塞。

  1. 设计合适的数据类型 推荐

例如对于实体类型建议使用特定的value实现,不要都放到string中,例如实体user

class User {
    string name;
    int age;
    string number;
}

反例:

set user:11:name tom
set user:11:age 23
set user:11:number 31002912002

正例:

hmset user:11 name tom age 23 number 31002912002
  1. 生命周期管理,分散key的过期时间 推荐

如果条件允许,对于key在设置过期时间时要尽量分散,不要集中过期,否则在回收时会引起慢查询,导致其他查询的阻塞。

2. 命令使用规范

2.1.复杂度为O(N)的命令 注意N的大小

推荐

对于常见的hgetallhkeyslrangesmemberszrange等命令并非不能使用,但是需要能明确N的大致区间,N在可接受的范围内可以使用。

如果需要遍历hashsetzset等,建议使用hscansscanzscan等方式进行迭代。

2.2.禁用高危命令

强制

对于Redis普通用户,线上禁止使用keysflushdbflushall等危险命令,可以通过ACL禁止用户操作:

ACL SETUSER dev -keys -flushdb -flushall

对于获取所有的key,可以使用scan方式进行迭代。

2.3.合理区分Redis的database和实例

推荐

Redis数据库是采用数字作为区分,且单个实例的所有库的操作仍然是单线程处理,并不能做到隔离,所以在多个业务资源消耗都很小的情况下,可以使用多个库进行区分,方便管理,但是对于资源密集型业务建议使用单独的Redis实例来运行,做到有效的隔离,另外对于完全不相关的业务系统也必须使用多个不同的实例。

2.4.使用批量操作提升性能

推荐

例如对于string或者hash类型的数据,原生就支持批量操作的命令msetmgethmset等,如果在操作频繁时使用可以很大程度上提升性能,在开发时可以优先选择,对于原生不支持批量操作的命令,可以使用pipeline操作来提升效率。

使用批量操作时注意每批数据量元素的个数和总大小,例如个数不要超过500个。

2.5.合理设置用户

推荐

Redis 6.x引入的ACL功能,可以更细粒度的控制用户的操作权限,因此建议将Redis版本更新,即使由于其他的原因无法更新也应该为Redis设置高强度的密码。

对于Redis 6.x则不要暴露default用户给应用程序和外部,正常应该禁用或设置高强度密码,仅用于管理员维护,应用程序应该使用专门的受限用户,可以根据业务限制不同的用户访问不同的key前缀,如果搭建主从复制或者Sentinel,还应该为复制和Sentinel访问设置专门的受限用户。

在不安全的环境下数据传输建议使用SSL方式访问。

2.6.Redis部署模式的选择

建议

  1. 单节点

单节点只适用于数据安全性不高的场景,例如作为数据库缓存,随时可以丢失,这种情况可以配置单实例运行。

  1. 主从复制

如果目前只有2个节点且数据要求一定的可靠性,可以配置1主1副本,采用手动故障转移,这样当一个节点故障时,副本节点可以临时启用来支撑服务运行。

如果具有2个以上的节点且需要读写分离来提升性能,主要是读多写少的场景,可以配置1主多副本,否则其他高可用需要的情况下都建议采用第3种部署方式。

  1. 主从复制+Sentinel高可用

如果有高可用的需求且具有至少3个节点,那么可以考虑配置复制+Sentinel的方式,来实现高可用。

  1. Cluster配置

在节点规模大于或等于6个时,可以考虑配置Redis Cluster,数据既可以分slot也可以复制,整体的性能可以实现线性扩展,但客户端库或者某些特殊操作会存在不兼容,会导致较大规模的代码重构,建议在扩展为集群时进行谨慎的评估确定是否需要。

2.7.客户端使用连接池优化性能

建议

客户端建议使用带有连接池的API,可以有效控制连接创建和释放的开销,提升操作效率。

Reference:

  1. 阿里云Redis开发规范
  2. bigkey解析