redis – 规范

  • ①.关于键值对的使用规范,主要两个方面:
  1. key的命名规范,只有命名规范,才能提供可读性强、可维护性好的key,方便日常管理
  2. value的设计规范,包括避免bigkey、选择高效序列化方法和压缩方法、使用整数对象共享池、数据类型选择
  • ②. 规范一:key的命名规范:把业务名作为前缀,然后用冒号分隔,再加上具体的业务数据名(这样一来,我们可以通过key的前缀区分不同的业务数据,就不用在多个数据库间来回切换了)
    key本身是字符串,底层的数据结构是SDS。SDS结构中会包含字符串长度、分配空间大小等元数据信息。从Redis3.2版本开始,当key字符串的长度增加时,SDS中的元数据也会占用更多内存空间

  • ③. 规范二:避免使用bigkey
    Redis是使用单线程读写数据,bigkey的读写操作会阻塞线程,降低Redis的处理效率。在应用Redis时,关于value的设计规范,非常重要的一点就是避免bigkey

  1. 键值对的值大小本身就很大,例如value为1MB的String类型数据。为了避免String类型的bigkey,在业务层,我们要尽量把String类型的数据大小控制在10KB以下
  2. 键值对的值是集合类型,集合元素个数非常多,例如包含100万个元素的Hash集合类型数据。为了避免集合类型的bigkey,我给你的设计规范建议是,尽量把集合类型的元素个数控制在1万以下
  • ④. 规范三:使用高效序列化方法和压缩方法
  1. 为了节省内存,除了采用紧凑型数据结构以外,我们还可以遵循两个使用规范,分别是使用高效的序列化方法和压缩方法,这样可以减少value的大
  2. XML和JSON格式的数据占用的内存空间比较大。为了避免数据占用过大的内存空间,我建议使用压缩工具例如snappy或gzip,把数据压缩后再写入Redis,这样就可以节省内存空间了
  • ⑤. 规范四:使用整数对象共享池
  1. 如果一个键值对中有0到9999范围的整数,Redis就不会为这个键值对专门创建整数对象了,而是会复用共享池中的整数对象,即使大量键值对保存了0到9999范围内的整数,在Redis实例中,其实只保存了一份整数对象,可以节省内存空间
  2. 那什么时候不能用整数对象共享池呢?主要有两种情况
    第一种情况是,如果Redis中设置了maxmemory,而且启用了LRU策略allkeys-lru或volatile-lru策略,那么,整数对象共享池就无法使用了。这是因为,LRU策略需要统计每个键值对的使用时间,如果不同的键值对都共享使用一个整数对象,LRU策略就无法进行统计了
    第二种情况是,如果集合类型数据采用ziplist编码,而集合元素是整数,这个时候,也不能使用共享池。因为ziplist使用了紧凑型内存结构,判断整数对象的共享情况效率低

redis – 建议

  • ①.冷热数据分离,不要将所有数据全部都放到Redis中
    虽然Redis支持持久化,但是Redis的数据存储全部都是在内存中的,成本昂贵。建议根据业务只将高频热数据存储到Redis中[QPS大于5000],对于低频冷数据可以使用MySQL/ElasticSearch/MongoDB等基于磁盘的存储方式,不仅节省内存成本,而且数据量小在操作时速度更快、效率更高

  • ②.不同的业务数据要分开存储
    不要将不相关的业务数据都放到一个Redis实例中,建议新业务申请新的单独实例。因为Redis为单线程处理,独立存储会减少不同业务相互操作的影响,提高请求响应速度;同时也避免单个实例内存数据量膨胀过大,在出现异常情况时可以更快恢复服务!在实际的使用过程中,redis最大的瓶颈一般是CPU,由于它是单线程作业所以很容易跑满一个逻辑CPU,可以使用redis代理或者是分布式方案来提升redis的CPU使用率

  • ③.存储的Key一定要设置超时时间
    如果应用将Redis定位为缓存Cache使用,对于存放的Key一定要设置超时时间!因为若不设置,这些Key会一直占用内存不释放,造成极大的浪费,而且随着时间的推移会导致内存占用越来越大,直到达到服务器内存上限!另外Key的超时长短要根据业务综合评估,而不是越长越好!

  • ④.对于必须要存储的大文本数据一定要压缩后存储
    对于大文本[+超过500字节]写入到Redis时,一定要压缩后存储!大文本数据存入Redis,除了带来极大的内存占用外,在访问量高时,很容易就会将网卡流量占满,进而造成整个服务器上的所有服务不可用,并引发雪崩效应,造成各个系统瘫痪

  • ⑤.线上Redis禁止使用Keys正则匹配操作
    Redis是单线程处理,在线上KEY数量较多时,操作效率极低[时间复杂度为O(N)],该命令一旦执行会严重阻塞线上其它命令的正常请求,而且在高QPS情况下会直接造成Redis服务崩溃!如果有类似需求,请使用scan命令代替

  • ⑥.命名规范

  1. 虽然说Redis支持多个数据库默认32个,可以配置更多,但是除了默认的0号库以外,其它的都需要通过一个额外请求才能使用。所以用前缀作为命名空间可能会更明智一点
  2. 另外,在使用前缀作为命名空间区隔不同key的时候,最好在程序中使用全局配置来实现,直接在代码里写前缀的做法要严格避免,这样可维护性实在太差了
  3. 如:系统名:业务名:业务数据:其他,但是注意,key的名称不要过长,尽量清晰明了,容易理解,需要自己衡量
  • ⑦.禁止大string
    核心集群禁用1mb的string大key(虽然redis支持512MB大小的string),如果1mb的key每秒重复写入10次,就会导致写入网络IO达10MB

  • ⑧.根据业务场景合理使用不同的数据结构类型
    目前Redis支持的数据库结构类型较多:字符串String,哈希Hash,列表List,集合Set,有序集合SortedSet,Bitmap,HyperLogLog和地理空间索引geospatial等,需要根据业务场景选择合适的类型。
    常见的如:String可以用作普通的K-V、计数类;Hash可以用作对象如商品、经纪人等,包含较多属性的信息;List可以用作消息队列、粉丝/关注列表等;Set可以用于推荐;SortedSet可以用于排行榜等!

  • ⑨.谨慎全量操作Hash、Set等集合结构
    在使用HASH结构存储对象属性时,开始只有有限的十几个field,往往使用HGETALL获取所有成员,效率也很高,但是随着业务发展,会将field扩张到上百个甚至几百个,此时还使用HGETALL会出现效率急剧下降、网卡频繁打满等问题[时间复杂度O(N)],此时建议根据业务拆分为多个Hash结构;或者如果大部分都是获取所有属性的操作,可以将所有属性序列化为一个STRING类型存储!同样在使用SMEMBERS操作SET结构类型时也是相同的情况!

  • ⑩.线上禁止使用monitor命令
    禁止生产环境使用monitor命令,monitor命令在高并发条件下,会存在内存暴增和影响Redis性能的隐患

  • ⑩①.redis容量
    单实例的内存大小不建议过大,建议在10~20GB以内。
    redis实例包含的键个数建议控制在1kw内,单实例键个数过大,可能导致过期键的回收不及时。

  • ⑩②.可靠性
    需要定时监控redis的健康情况:使用各种redis健康监控工具,实在不行可以定时返回redis的info信息
    客户端连接尽量使用连接池长链接和自动重连