规范的级别分为3个:强制、推荐 和 建议,其中强制表示必须这么做,否则会引起严重的错误或问题;推荐属于最佳实践的范畴,表示“强烈建议”这么做,这样会使设计或者开发过程更加规范、整洁,影响的是整个系统的健壮性或可维护性;建议则通常适用于一些特殊的设计,给出一种比较好的实现方式,在实际实现中可以有多种方式实现,而且选择哪种方式对系统的整体影响并不大。
以业务系统为前缀,使用冒号进行多段分割,可以使用业务系统:表或模块:key
进行组合设计,例如:
manager:device:332710
video:count:20220923
这样设计可以有效避免key的冲突,同时会使系统设计清晰规范,易于开发和问题定位。
如果业务系统名称太长,可以使用-
分割或者使用简写方式。
在不影响语义和理解的前提下,可以适当使用简写控制key的长度,例如:
funnel-statistics:messages:jobs
可以简写为:
fs:m:jobs
具体简写的方式依赖于实际的业务抽象,特别是对于很长的连字符拼接的单词非常建议使用简写来替代,可以有效节省内存空间的占用。
key中不要包含空格、换行、单引号以及其他转义字符,否则会对开发人员带来困扰或麻烦。
bigkey会带来慢查询和大量流量消耗,因此对value的长度要做出限制:
string类型长度限制在10KB以内,对于hash、list、set、zset类型中元素个数不要超过10000。
反例:线上使用Redis list作为简单队列,长度达到了200万。
解决:Redis用作消息队列适用于小规模的场景,同时生产者侧要控制好队列的长度,对于大规模消息的场景建议采用Kafka
或Pulsar
等专用的消息平台。
非string类型的bigkey,在删除时不要用del
直接删除,而是采用hscan
、sscan
、zscan
等方式渐进删除,同时关注过期自动删除的问题,否则会容易出现慢查询导致阻塞。
例如对于实体类型建议使用特定的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
如果条件允许,对于key在设置过期时间时要尽量分散,不要集中过期,否则在回收时会引起慢查询,导致其他查询的阻塞。
推荐
对于常见的hgetall
、hkeys
、lrange
、smembers
、zrange
等命令并非不能使用,但是需要能明确N的大致区间,N在可接受的范围内可以使用。
如果需要遍历hash
、set
、zset
等,建议使用hscan
、sscan
、zscan
等方式进行迭代。
强制
对于Redis普通用户,线上禁止使用keys
、flushdb
、flushall
等危险命令,可以通过ACL禁止用户操作:
ACL SETUSER dev -keys -flushdb -flushall
对于获取所有的key,可以使用scan
方式进行迭代。
推荐
Redis数据库是采用数字作为区分,且单个实例的所有库的操作仍然是单线程处理,并不能做到隔离,所以在多个业务资源消耗都很小的情况下,可以使用多个库进行区分,方便管理,但是对于资源密集型业务建议使用单独的Redis实例来运行,做到有效的隔离,另外对于完全不相关的业务系统也必须使用多个不同的实例。
推荐
例如对于string
或者hash
类型的数据,原生就支持批量操作的命令mset
、mget
、hmset
等,如果在操作频繁时使用可以很大程度上提升性能,在开发时可以优先选择,对于原生不支持批量操作的命令,可以使用pipeline
操作来提升效率。
使用批量操作时注意每批数据量元素的个数和总大小,例如个数不要超过500个。
推荐
Redis 6.x引入的ACL功能,可以更细粒度的控制用户的操作权限,因此建议将Redis版本更新,即使由于其他的原因无法更新也应该为Redis设置高强度的密码。
对于Redis 6.x则不要暴露default
用户给应用程序和外部,正常应该禁用或设置高强度密码,仅用于管理员维护,应用程序应该使用专门的受限用户,可以根据业务限制不同的用户访问不同的key前缀,如果搭建主从复制或者Sentinel,还应该为复制和Sentinel访问设置专门的受限用户。
在不安全的环境下数据传输建议使用SSL方式访问。
建议
单节点只适用于数据安全性不高的场景,例如作为数据库缓存,随时可以丢失,这种情况可以配置单实例运行。
如果目前只有2个节点且数据要求一定的可靠性,可以配置1主1副本,采用手动故障转移,这样当一个节点故障时,副本节点可以临时启用来支撑服务运行。
如果具有2个以上的节点且需要读写分离来提升性能,主要是读多写少的场景,可以配置1主多副本,否则其他高可用需要的情况下都建议采用第3种部署方式。
如果有高可用的需求且具有至少3个节点,那么可以考虑配置复制+Sentinel的方式,来实现高可用。
在节点规模大于或等于6个时,可以考虑配置Redis Cluster,数据既可以分slot也可以复制,整体的性能可以实现线性扩展,但客户端库或者某些特殊操作会存在不兼容,会导致较大规模的代码重构,建议在扩展为集群时进行谨慎的评估确定是否需要。
建议
客户端建议使用带有连接池的API,可以有效控制连接创建和释放的开销,提升操作效率。
Reference: