优化 Redis 的使用策略

Redis Key 的命名策略

Redis 是 K-V 形式的缓存数据库,每一个需要缓存的 Object 都需要唯一的 Key 来标识。但是,我们日常在做开发的时候,经常会出现一个公司或者部门之间共用一个 Redis 集群的情况。所以,这就有可能会造成 Key 冲突,引发数据被覆盖的问题(即使是同一个部门,也可能存在不同的研发人员使用了同名的 Key)。

  • 根据业务名称命名 - 不建议

一个项目中,相似的业务是很常见的,所以,如果不同的研发人员使用了同名的 Key,就会导致系统的 bug。同时,如果不同的项目组在共同使用一个 Redis 集群,也会发生这样的问题。例如:

127.0.0.1:6379> set name qinyi
OK
# 同一个项目中的不同业务使用了同名的 key (不同的研发人员共同开发造成)
127.0.0.1:6379> lpush name qinyi imooc
(error) WRONGTYPE Operation against a key holding the wrong kind of value
127.0.0.1:6379>
  • 在业务名称之前加上项目的名称 - 不建议

这样做可以大概率的避免不同的项目引起的 Key 冲突问题,但是,仍然不能避免同一个项目中的不同业务。例如:

# a、b 两个项目在使用 Redis 时,各自以项目的名称为 Key 的前缀
127.0.0.1:6379> set a-name qinyi
OK
127.0.0.1:6379> set b-name imooc
OK
# 仍不能避免同一个项目中的不同业务使用了同名的 key
127.0.0.1:6379> lpush a-name qinyi imooc
(error) WRONGTYPE Operation against a key holding the wrong kind of value
127.0.0.1:6379>
  • Key = 项目名称-业务名称-时间戳 - 建议

这种命名 Key 的方式是比较好的,相比于上一种方式,多增加了一个时间戳标识。这里的含义就是与不同的开发人员定义相同时间戳的概率很低很低。具体时间戳的精度可以根据业务的实际情况选择,比如:天、小时等等。例如:

# Key 中添加天级的时间戳来避免 Key 冲突的问题
127.0.0.1:6379> set a-name-20190314 qinyi
OK
127.0.0.1:6379> lpush a-name-20190315 qinyi imooc
(integer) 2
127.0.0.1:6379>

过期时间的设定

在使用 Redis 时,绝大多数情况都需要给 Key 设定过期时间,这个是非常有必要的。原因如下:

  • 作为缓存,加快程序的执行速度。但是缓存的 Object 很可能是会经常变化的,不要长期驻留在 Redis 中
  • 当 Redis 的内存使用超过一个阈值(可以自定义)时,会触发 Redis 的缓存淘汰策略,此时的 LRU 过程是非常慢的。极大的影响 Redis 的性能

所以,在保存 KV 时,最好是设定过期时间。例如:

127.0.0.1:6379> set name qinyi
OK
127.0.0.1:6379> expire name 30
(integer) 1
127.0.0.1:6379> ttl name
(integer) 25
127.0.0.1:6379>

关于 Redis 设定过期时间(这里包含过期键的删除)需要知道:

  • Redis 对于设定过期时间的键是怎么保存的
  • Redis 键的过期删除策略

数据结构的选择

Redis 常用的数据结构一共有五种:string、hash、list、set、zset(sorted set)。可以发现,大多数场景下使用 string 都可以去解决问题。但是,这并不一定是最优的选择。下面,简单说明下它们各自的适用场景:

  • string:单个的缓存结果,不与其他的 KV 之间有联系
  • hash:一个 Object 包含有很多属性,且这些属性都需要单独存储。注意:这种情况不要使用 string,因为 string 会占据更多的内存
  • list:一个 Object 包含很多数据,且这些数据允许重复、要求有顺序性
  • set:一个 Object 包含很多数据,不要求数据有顺序,但是不允许重复
  • zset:一个 Object 包含很多数据,且这些数据自身还包含一个权重值,可以利用这个权重值来排序

另外,Redis 还提供了一些特别的数据结构,用于一些特殊的场景。例如:Geo、HyperLogLog

  • Geo:LBS 相关的应用,可以参考:Redis Geo
  • HyperLogLog:允许存在误差的基数统计,可以参考:Redis HyperLogLog

持久化机制的选择

Redis 提供了两种持久化机制:RDB 和 AOF。

  • RDB:在指定的时间间隔内将内存中的数据快照写入磁盘,实际操作过程是 fork 一个子进程,先将数据写入临时文件,写入成功后,再替换之前的文件,用二进制压缩存储
  • AOF:以日志的形式记录服务器所处理的每一个写、删除操作,查询操作不会记录,以文本的方式记录,可以打开文件看到详细的操作记录

关于这两种持久化方式的优点不做解释,可以根据其实现形式得出结论。下面,分析下它们各自的缺点。

RDB 的缺点

  • 如果你想保证数据的高可用性,即最大限度的避免数据丢失,那么 RDB 将不是一个很好的选择。因为系统一旦在定时持久化之前出现宕机现象,此前没有来得及写入磁盘的数据都将丢失
  • 由于 RDB 是通过 fork 子进程来协助完成数据持久化工作的,因此,如果当数据集较大时,可能会导致整个服务器停止服务几百毫秒,甚至是1秒钟

AOF 的缺点

  • 对于相同数量的数据而言,AOF 文件通常要大于 RDB 文件。RDB 在恢复大数据时的速度比 AOF 的恢复速度要快
  • 由于同步策略的不同,AOF 在运行效率上往往会慢于 RDB

总结:二者选择的标准,就是看系统是愿意牺牲一些性能,换取更高的缓存一致性(AOF),还是愿意写操作频繁的时候,不启用备份来换取更高的性能。

不要使用 Redis 存储单 Key 大数据

这里所说的大数据,不是说不使用 Redis 存储更多的数据,而是说单个 KV 很大的情况。这里最核心的原因是:Redis 是单进程单线程的应用。这种工作方式在操作过程上避免了线程切换的耗时,而且不需要考虑线程安全,无需获取锁、释放锁等操作,是非常简单、直接的。但是:

  • Redis 的单线程工作机制,无法用多核并行处理。如果遇到 IO 量大的操作,出现等待 IO 的情况会增多,即使 Redis 底层用的是 IO 多路复用技术,IO 的事件句柄也是要占用资源的
  • Redis 的持久化需要将数据保存下来,KV 的数据量很大,也会影响持久化的执行

作者:张勤一

链接:https://www.imooc.com/article/283155

来源:慕课网

本文原创发布于慕课网 ,转载请注明出处,谢谢合作

相关推荐