首页 > 数据库 >使用Redis必须考虑的问题

使用Redis必须考虑的问题

时间:2023-02-01 17:22:18浏览次数:38  
标签:缓存 必须 删除 过期 数据库 Redis key 考虑

1 为什么使用缓存?

高性能、高并发。

缓存主要是用来提高获取数据的速度,通过将一些热点数据存储在缓存中,可以大大提高业务处理的速度,因此可以提高系统的性能和并发能力。

在实际业务场景中,也可以用来缓存一些特殊数据,例如登录用户的token、分布式锁等。

2 Redis有哪些数据类型?

string,list,hash,set,zset,位图,HyperLogLog,布隆过滤器。

string可以存储字符串:

set name Xianhuii

list可以存储有序列表:

rpush books Java JavaScript Spring

hash可以存储多个键值对:

hset person name Xianhuii
hset person age 18

set可以存储去重的无序列表:

sadd books python
sadd books python

zset可以存储去重的排序列表:

zadd books 10 Java
zadd books 8 Spring
zadd books 9 Java

位图可以按位存储信息:

setbit bitMap 1 1
setbit bitMap 2 0

HyperLogLog可以用于统计大量数据:

pfadd users Xianhuii
pfadd users CHUAN
……
pfcount users

布隆过滤器可以用于大量数据的过滤:

bf.add users Xianhuii
……
bf.exists user CHUAN

3 Redis的过期策略?

定期删除+惰性删除,内存淘汰策略。

Redis中的key都可以设置过期时间,对于这类数据,会采用定期删除+惰性删除策略:

  • 定期删除:Redis将设置过期时间的key存储在一个独立字典中,会定时扫描这个字典,根据过期时间来判断是否删除该key。
  • 惰性删除:如果某个key过期了,但是还没进行定期删除扫描,此时客户端获取这个过期key时,Redis会先判断过期时间,如果过期了就立即删除。

定期删除+惰性删除策略在日常工作中也有很多应用,它的原理就是使用定时任务进行轮询,保证整体业务的稳定性;对于轮询间隔的少量数据,使用即使处理的兜底策略。

Redis中的key也可以不设置过期时间,这部分数据不能用定期删除+惰性删除策略进行处理。如果内存中存在大量未设置过期时间的key,以及大量设置过期时间但未过期的key,造成内存达到了上线,此时定期删除+惰性删除策略就派不上用场了。

此时,Redis会采取内存淘汰策略:

  • noeviction(默认):不再处理写请求,可以继续执行读请求和删除请求。
  • volatile-lru:优先淘汰最少使用的、设置过期时间的key。
  • volatile-ttl:优先淘汰ttl小的、设置过期时间的key。
  • volatile-random:随机淘汰设置过期时间的key。
  • allkeys-lru(建议使用):优先淘汰最少使用的全体key。
  • allkeys-random:随机淘汰全体key。

简单来说,淘汰策略:

  • 不再写入,需要手动删除。
  • 设置过期时间的key集合/全体key集合中进行最少使用淘汰/最小ttl淘汰/随机淘汰

4 Redis如何持久化?

RDB,AOF。

Redis的数据全部存储在内存中,如果宕机会造成数据丢失。为此,Redis提供了持久化功能:

  • RDB:定时(周期较长)将内存中的全部数据保存到磁盘文件中,每次都会新生成该时刻的数据文件。
  • AOF:记录对内存进行修改的指令记录,由于可能会有覆盖操作,需要定时对该日志进行瘦身重写,即定时将内存数据转换成操作指令。

RDB是对内存数据的整体备份,生成的文件通常比较少,恢复速度快。但是由于备份周期长,可能会丢失一部分未及时备份的数据。

AOF是对操作指令的记录,随着运行时间增长会变得越来越大,恢复速度慢。

实际项目中通常使用RDB+AOF混合持久化策略,使用RDB定期备份内存中的数据,使用AOF记录上个RDB备份周期至今的操作指令。由此既保证了数据的完整性,又大大减小了AOF指令文件,加快了恢复速度。

5 如何保证Redis的高可用和高并发?

主从复制,哨兵,集群。

Redis高可用,简单来说就是要保证某个服务器宕机后不能影响客户端的业务,Redis提供了主从复制+哨兵功能。

Redis高并发,简单来说就是要能够快速处理客户端的请求,所以通常需要增加服务器实例的数量,Redis提供了集群功能。

实际上主从复制哨兵集群是不可分的,它们往往会结合到一起工作。

5.1 主从复制

快照同步,增量同步。

可以为Redis服务器设置一个master节点和多个slaver节点,master负责与客户端进行交互,slaver则会使用快照同步+增量同步的方式,定时从master(主从同步)或slaver(从从同步)同步数据。

快照同步类似于RDB持久化方式,它会将内存中的数据持久化到磁盘文件,然后将该磁盘文件数据同步给slaver。

增量同步类似于AOF持久化方式,它会将修改操作指令记录到缓存中,然后将该缓存数据同步给slaver。

5.2 哨兵Sentinel

哨兵是Redis主从节点的管理器,它会持续监控主从节点,当master宕机时,会选择最优的slaver作为新的master。

使用哨兵的流程:

  1. 客户端连接哨兵,请求master地址。
  2. 客户端连接master进行操作。

如果master宕机重新选取后,客户端需要重新上述步骤,获取最新的master地址。

5.3 Redis Cluster

Redis Cluster是官方的集群化方案,它本身提供类似主从复制和哨兵的功能。

Redis Cluster是去中心化的,它将所有数据划分为16384个槽位,每个节点负责一部分槽位,保存一部分数据。当客户端连接集群时,会返回一份集群的槽位配置信息。客户端需要查找某个key时,可以直接定位到目标节点。

Redis Cluster可以为每个主节点设置若干从节点,当从节点发生故障时,集群会自动将其中某个从节点提升为主节点。如果某个主节点没有从节点,那么宕机时就会造成整个集群不可用。

Redis Cluster通过Gossip协议广播来保证集群中实例间的信息同步。如果某个节点发现节点A失联了(PFail,Possible Fail),会向整个集群广播。各个节点会判断节点A的连接情况,并广播判断结果。如果集群中大部分节点都判断该节点失联,就会将节点A下线(Fail),并且进行主从切换。

6 如何保证缓存和数据库的数据一致性?

简单双删策略,延迟双删策略,串行化策略。

在使用Reids缓存数据库数据时,就会出现缓存数据和数据库数据不一致问题。

根据对数据一致性的不同程度要求,我们可以采取递进的措施。

6.1 简单双删策略

如果对数据一致性要求不严格,可以使用以下简单的双删策略:

读取数据:

public Result read() {
	// 读取缓存
	// 如果缓存没有,读取数据库
	// 更新缓存
	return res;
}

更新数据:

public void update() {
	// 删除缓存
	// 更新数据库
	// 删除缓存
}

正常情况下,updateread操作会按顺序执行。每次update操作都会更新数据库数据,删除缓存。每次read操作都会获取数据库中的最新数据作为缓存。

但是在实际线上环境中,readupdate可能会并发执行,在小概率情况下可能会按以下顺序执行,造成数据不一致:

  1. read读取缓存
  2. 缓存没有,read读取数据库
  3. update删除缓存
  4. update更新数据库
  5. update删除缓存
  6. read更新缓存(旧值)

6.2 延迟双删策略

为了避免这种并发执行情况,保证数据最终一致性,可以在update操作中增加一个延迟删除操作。通过延迟删除,可以使删除缓存操作位于并发执行的最后,保证缓存在数据库更新后被删除,下次读取时就可以获取最新数据:

public void update() {
	// 删除缓存
	// 更新数据库
	// 删除缓存
	// 延迟删除:如DelayQueue或MQ
}

6.3 串行化策略

上述延迟双删策略保证了数据的最终一致性,但是并发read到延迟删除这一时间段的数据仍可能是不一致的。

如果需要保证数据的强一致性,就需要将update和read操作串行化了。

例如可以使用BlockingQueue,在update和read时将实际逻辑添加到队列中,然后按顺序进行执行。

7 如何解决缓存雪崩、缓存穿透和缓存击穿?

缓存雪崩、缓存穿透和缓存击穿都是指,在高峰期系统处理大量请求时,由于缓存中获取不到数据,从而直接请求数据库,造成数据库崩溃的现象。

7.1 缓存雪崩

缓存雪崩是指在高峰期,由于缓存服务器宕机或者大量key同时过期,大量业务请求数据库,造成数据库崩溃。

为了避免缓存服务器宕机造成的缓存雪崩,需要开启Redis的主从复制、哨兵模式和集群功能,保证系统的高可用。为了宕机后的数据恢复,还需要开启持久化功能。

在业务中,应该设置不同的过期时间,避免大量key过期后被同时删除。

如果缓存服务器已经宕机,则需要开启本地缓存,通过限流或服务降级,避免数据库崩溃。后续通过Redis重启从磁盘恢复数据,在恢复原先的架构。

7.2 缓存穿透

缓存穿透是指大量请求的数据在缓存和数据库中都不存在,每次请求都会越过缓存请求数据库,但是数据库中也不存在数据,因此不会更新缓存。

这种情况往往是恶意的,我们可以通过缓存一个空值状态到数据库,下次请求时,直接响应该空值:

public Result find() {
	// 查询缓存
	// 缓存如果存在,直接返回
	// 缓存不存在,查询数据库
	// 数据库如果存在,直接返回
	// 数据库不存在,更新对应空值状态缓存并返回
}

由于不存在的数据是无穷多个的,我们没办法缓存每个空值状态。可以采取一种反向思维,使用布隆过滤器缓存已存在的数据,请求查询时,先判断布隆过滤器中是否存在:

  • 存在:从对应缓存或数据库中获取数据。
  • 不存在:直接返回空值状态

新增数据时:

public void add(Data data) {
	// 更新数据库
	// 添加到布隆过滤器
}

查询数据时:

public Result find() {
	// 查询布隆过滤器
	// 布隆过滤器不存在,直接返回空值状态
	// 布隆过滤器存在,查询缓存
	// 缓存如果存在,直接返回
	// 缓存不存在,查询数据库,更新缓存并返回
}

7.3 缓存击穿

缓存击穿是指某个热点key过期后,大量请求集中式并发访问,此时这些请求都会直接请求数据库,容器造成数据库崩溃。

对于这种热点数据,可以将其设置成永不过期。或者使用定时任务,在过期前适当延长过期时间或更新缓存。

8 Redis为什么那么快?

Redis是个单线程程序,它的所有数据都存储在内存中,使用NIO多路复用与客户端进行交互,保证客户端的高并发请求;使用单线程处理指令,避免了线程的上下文切换。

当客户端发送请求时,请求指令会被缓存到指令队列中,Redis工作线程会轮询指令队列进行执行,将指令结果缓存到响应队列,Redis工作线程轮询会响应队列通过对应套接字响应给指定客户端。

这里的指令队列和响应队列,都是NIO的操作系统内核缓存,依赖底层操作系统。

9 Redis分布式锁

Redis分布式锁是日常项目中常用的工具。

所谓锁,就是一种全局唯一的状态标识,并且对其操作必须是原子性的。

在单机场景下,我们可以使用同一个Java对象保证它是全局唯一的,由于Java的synchronized等操作保证了加锁/解锁操作是原子性的,所以它可以作为锁。

在分布式场景下,由于Redis是单线程操作的,所有指令都会按顺序执行,天然保证了加锁/解锁的原子性。同时Redis的key是唯一的(就算是集群中也是唯一的),这就保证了使用Redis作为分布式锁的可能性。

我们可以通过set指令(原子操作)设置分布式锁:

# 1、获取分布式锁
set disKey disValue ex 5 nx
# 2、如果响应成功,说明加锁成功,进行业务操作
# 3、业务操作完成,解锁
del disKey

需要注意分布式锁的过期时间,如果分布式锁过期了,但是业务还没有完成,那么该分布式锁就失效了。

此时可以考虑使用Redisson,它会使用看门狗机制,定时检查客户端是否仍持有锁,并且适当延长过期时间。

标签:缓存,必须,删除,过期,数据库,Redis,key,考虑
From: https://www.cnblogs.com/Xianhuii/p/17083486.html

相关文章

  • 【redis】redis面试题总结
    一、Redis是什么?Redis是一个key-value存储系统,它支持存储的value类型相对更多,包括string、list、set、zset(sortedset--有序集合)和hash。这些数据结构都支持push/pop、ad......
  • (五)REDIS-哨兵与集群
    概念介绍:Sentinel(哨兵)是Redis的高可用性解决方案,主要是通过一个或多个Sentinel实例组成的Sentinel系统对任意多个主服务器以及这些主服务器的所有从服务器进行监视,当某个......
  • Redis源码安装
    Redis源码安装1、下载源码包http://download.redis.io/releases/2、安装#查看是否有安装gccgcc--version#安装gccyum-yinstallgccautomakeautoconflibtoo......
  • redis缓存一致性
    redis缓存一致性 redis是目前使用最广泛的分布式缓存系统,几乎每家公司都在用。它使用简单,吞吐量高,单机qps可以达到10万每秒,但在使用redis缓存时存在一个问题,即如......
  • 面试题-Redis的主从同步是如何实现的
    Redis的主从同步是如何实现的Redis的主从复制可以根据是否是全量,分为全量同步和增量同步(也叫全量复制和部分复制)。全量复制一般用于初次复制的场景部分复制则用于处理......
  • redisson分布式锁源码和原理浅析
    在redisson之前,很多人可能已经自己实现过基于redis的分布式锁,本身原理也比较简单,redis自身就是一个单线程处理器,具备互斥的特性,通过setNx,exist等命令就可以完成简单的分布式......
  • Redis主从同步分析
    一、Redis主从同步原理1.1Redis主从同步的过程配置好slave服务器连接的master后,slave会建立和master的连接,然后发送sync命令。无论是第一次同步建立的连接还是连接断开后的......
  • redis基本数据类型 set类型
      127.0.0.1:6379>SADDs1abc(integer)3127.0.0.1:6379>SMEMBERSs11)"b"2)"c"3)"a"127.0.0.1:6379>SREMs1a(integer)1127.0.0.1:6379>SCARD......
  • 前端必须掌握的JS面向对象
    面向对象和面向过程区别面向对象是把构成问题的事物拆解为各个对象,来描述这个事物在当前问题中的行为,而不是为了实现某个步骤。面向过程,是分析出实现问题的每个步骤,然后编......
  • 面试题-如何实现Redis的高可用
    如何实现Redis的高可用实现Redis的高可用,主要有哨兵和集群两种方式。哨兵简单的一句话:反客为主的自动版,能够后台监控主机是否故障,如果故障了根据投票数自动将从库转换为......