优化 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 的数据量很大,也会影响持久化的执行

猜你喜欢

转载自www.cnblogs.com/qfjavabd/p/10552861.html
今日推荐