Redis重要知识点

使用场景

1. 缓存 2. 分布式锁 3. 计数器(Incr) 4. 保存token(String) 5. 消息队列(List) 6. 延迟队列(Zset)

缓存穿透

一个get请求:api/news/getById/1

定义

查询一个不存在的数据,mysql查询不到数据也不会直接写入缓存,就会导致每次请求都查询数据库。

解决方案一

缓存空数据,查询返回的结果为空,仍把这个空结果进行缓存。

优点:简单。

缺点:消耗内存,可能发生不一致的现象。

解决方案二

使用布隆过滤器。

优点:内存占用较少,没有多余key。

缺点:实现复杂,存在误判。

布隆过滤器原理

bitmap(位图):相当于是一个以(bit)位为单位的数组,数组中每个单元只能存储二进制数0或1。

布隆过滤器作用:布隆过滤器可以用于检索一个元素是否在一个集合中。

存在误判情况。

误判率

数组越小误判率就越大,数组越大误判率就越小,但是同时带来了更多的内存消耗。

缓存击穿

定义

给某一个key设置了过期时间,当key过期的时候,恰好这时间点对这个key有大量的并发请求过来,这些并发的请求可能会瞬间把DB压垮。

解决方案一

互斥锁。

解决方案二

逻辑过期。

缓存雪崩

定义

在同一时段大量的缓存key同时失效或者Redis服务宕机,导致大量请求到达数据库,带来巨大压力。

解决方案

1. 给不同的Key的TTL添加随机值。

2. 利用Redis集群提高服务的可用性(哨兵模式、集群模式)。

3. 给缓存业务添加降级限流策略(可作为系统的保底策略)。

4. 给业务添加多级缓存。

双写一致

定义

当修改了数据库的数据也要同时更新缓存的数据,缓存和数据库的数据要保持一致。

读操作:缓存命中,直接返回;缓存未命中查询数据库,写入缓存,设定超时时间。

写操作:延迟双删。存在脏数据风险。

允许延时一致的业务,采用异步通知。

1. 使用MQ中间中间件,更新数据之后,通知缓存删除。

2. 利用canal中间件,不需要修改业务代码,伪装为mysql的一个从节点,canal通过读取binlog数据更新缓存。

强一致性的业务,采用Redisson提供的读写锁。

共享锁:读锁readLock,加锁之后,其他线程可以共享读操作。

排他锁:写锁writeLock,加锁之后,阻塞其他线程读写操作。

持久化

RDB定义

RDB全称Redis Database Backup file(Redis数据备份文件),也叫Redis数据快照。简单来说就是把内存中的所有数据都记录到磁盘中。当Redis实例故障重启后,从磁盘读取快照文件,恢复文件。

save 由Redis主进程来执行RDB,会阻塞所有命令。

bgsave 开启子进程执行RDB,避免主进程受到影响。

RDB执行原理

bgsave开始时会fork主进程得到子进程,子进程共享主进程的内存数据。完成fork后读取内存数据并写入RDB文件。

AOF定义

AOF全称为Append Only File(追加文件)。Redis处理的每一个写命令都会记录在AOF文件,可以看做是命令日志文件。

AOF默认是关闭的,需要修改redis.conf配置文件来开启AOF。

因为是记录命令,AOF文件会比RDB文件大的多。而且AOF会记录对同一个key的多次写操作,但只有最后一次写操作才有意义。通过执行bgrewriteaof命令,可以让AOF文件执行重写功能,用最少的命令达到相同效果。

RDB与AOF对比

RDB和AOF各有自己的优缺点,如果对数据安全性要求较高,在实际开发中往往会结合两者来使用。

RDB

AOF

持久化方式

定时对整个内存做快照

记录每一次执行的命令

数据完整性

不完整,两次备份之间会丢失

相对完整,取决于刷盘策略

文件大小

会有压缩,文件体积小

记录命令,文件体积很大

宕机恢复速度

很快

数据恢复优先级

低,因为数据完整性不如AOF

高,因为数据完整性更高

系统资源占用

高,大量CPU和内存消耗

低,主要是磁盘IO资源

AOF重写时会占用大量CPU和内存资源

使用场景

可以容忍数分钟的数据丢失,追求更快的启动速度

对数据安全性要求较高

数据过期策略

定义

Redis对数据设置数据的有效时间,数据过期以后,就需要将数据从内存中删除掉。可以按照不同的规则进行删除,这种删除规则就被称之为数据的删除策略(数据过期策略)。

惰性删除

设置该key过期时间后,我们不去管它,当需要该key时,我们在检查其是否过期,如果过期,我们就删掉它,反之返回该key。

优点 :对CPU友好,只会在使用该key时才会进行过期检查,对于很多用不到的key不用浪费时间进行过期检查。

缺点 :对内存不友好,如果一个key已经过期,但是一直没有使用,那么该key就会一直存在内存中,内存永远不会释放。

定期删除

定义

每隔一段时间,我们就对一些key进行检查,删除里面过期的key(从一定数量的数据库中取出一定数量的随机key进行检查,并删除其中的过期key)。

模式

SLOW模式是定时任务,执行频率默认为10hz,每次不超过25ms,以通过修改配置文件redis.conf的hz选项来调整这个次数。

FAST模式执行频率不固定,但两次间隔不低于2ms,每次耗时不超过1ms。

优点:可以通过限制删除操作执行的时长和频率来减少删除操作对 CPU 的影响。另外定期删除,也能有效释放过期键占用的内存。

缺点:难以确定删除操作执行的时长和频率。

数据淘汰策略

定义

当Redis中的内存不够用时,此时在向Redis中添加新的key,那么Redis就会按照某一种规则将内存中的数据删除掉,这种数据的删除规则被称之为内存的淘汰策略。

策略

noeviction: 不淘汰任何key,但是内存满时不允许写入新数据,默认就是这种策略。

volatile-ttl: 对设置了TTL的key,比较key的剩余TTL值,TTL越小越先被淘汰。

allkeys-random:对全体key ,随机进行淘汰。

volatile-random:对设置了TTL的key ,随机进行淘汰。

allkeys-lru: 对全体key,基于LRU算法进行淘汰。

volatile-lru: 对设置了TTL的key,基于LRU算法进行淘汰。

allkeys-lfu: 对全体key,基于LFU算法进行淘汰。

volatile-lfu: 对设置了TTL的key,基于LFU算法进行淘汰。

LRU & LFU

LRULeast Recently Used)最近最少使用。用当前时间减去最后一次访问时间,这个值越大则淘汰优先级越高。

LFULeast Frequently Used)最少频率使用。会统计每个key的访问频率,值越小淘汰优先级越高。

建议

1. 优先使用 allkeys-lru 策略。充分利用 LRU 算法的优势,把最近最常访问的数据留在缓存中。如果业务有明显的冷热数据区分,建议使用。

2. 如果业务中数据访问频率差别不大,没有明显冷热数据区分,建议使用 allkeys-random,随机选择淘汰。

3. 如果业务中有置顶的需求,可以使用 volatile-lru 策略,同时置顶数据不设置过期时间,这些数据就一直不被删除,会淘汰其他设置过期时间的数据。

4. 如果业务中有短时高频访问的数据,可以使用 allkeys-lfu volatile-lfu 策略。

Redis分布式锁

Redis实现分布式锁主要利用Redis的setnx命令。setnx是SET if not exists(如果不存在,则SET)的简写。

Redisson实现

在redisson的分布式锁中,提供了一个WatchDog(看门狗),一个线程获取锁成功以后,WatchDog会给持有锁的线程续期(默认是每隔10秒续期一次)。

Redission锁可重入性

可以重入,多个锁重入需要判断是否是当前线程,在redis中进行存储的时候使用hash结构,来存储线程信息和重入的次数。

Redis集群

方案

1. 主从复制

2. 哨兵模式

3. 分片集群

主从复制

单节点Redis的并发能力是有上限的,要进一步提高Redis的并发能力,就需要搭建主从集群,实现读写分离。一般都是一主多从,主节点负责写数据,从节点负责读数据。

原理

全量同步

1. 从节点请求主节点同步数据(replication id、 offset)。

2. 主节点判断是否是第一次请求,是第一次就与从节点同步版本信息(replication id和offset)。

3. 主节点执行bgsave,生成rdb文件后,发送给从节点去执行。

4. 在rdb生成执行期间,主节点会以命令的方式记录到缓冲区(一个日志文件)。

5. 把生成之后的命令日志文件发送给从节点进行同步。

增量同步

1.从节点请求主节点同步数据,主节点判断不是第一次请求,不是第一次就获取从节点的offset值。

2.主节点从命令日志中获取offset值之后的数据,发送给从节点进行数据同步。

哨兵模式

监控

Sentinel会不断检查master和slave是否按预期工作。

基于心跳机制监测服务状态,每隔1秒向集群的每个实例发送ping命令:

主观下线:如果某sentinel节点发现某实例未在规定时间响应,则认为该实例主观下线

客观下线:若超过指定数量(quorum)的sentinel都认为该实例主观下线,则该实例客观下线。quorum值最好超过Sentinel实例数量的一半。

自动故障恢复

如果master故障,Sentinel会将一个slave提升为master。当故障实例恢复后也以新的master为主。

哨兵选主规则

首先判断主与从节点断开时间长短,如超过指定值就排该从节点。

然后判断从节点的slave-priority值,越小优先级越高。

如果slave-prority一样,则判断slave节点的offset值,越大优先级越高。

最后是判断slave节点的运行id大小,越小优先级越高。

通知

Sentinel充当Redis客户端的服务发现来源,当集群发生故障转移时,会将最新信息推送给Redis的客户端。

哨兵模式脑裂

min-replicas-to-write 1   表示最少的salve节点为1

min-replicas-max-lag 5  表示数据复制和同步的延迟不能超过5

分片集群

特征

集群中有多个master,每个master保存不同数据。

每个master都可以有多个slave节点。

master之间通过ping监测彼此健康状态。

客户端请求可以访问集群任意节点,最终都会被转发到正确节点。

哈希槽

Redis 分片集群引入了哈希槽的概念,Redis 集群有 16384 个哈希槽,每个key通过 CRC16 校验后对 16384 取模来决定放置哪个槽,集群的每个节点负责一部分 hash 槽。

读写数据:根据key的有效部分计算哈希值,对16384取余(有效部分,如果key前面有大括号,大括号的内容就是有效部分,如果没有,则以key本身做为有效部分)余数做为插槽,寻找插槽所在的实例

Redis速度快的原因

1. Redis是纯内存操作,执行速度非常快,性能瓶颈是网络延迟而不是执行速度。

2. 采用单线程,避免不必要的上下文切换可竞争条件,多线程还要考虑线程安全问题。

3. 使用I/O多路复用模型,非阻塞IO。

I/O多路复用模型

原理

是利用单个线程来同时监听多个Socket ,并在某个Socket可读、可写时得到通知,从而避免无效的等待,充分利用CPU资源。

通知方式

select和poll只会通知用户进程有Socket就绪,但不确定具体是哪个Socket,需要用户进程逐个遍历Socket来确认。

epoll则会在通知用户进程Socket就绪的同时,把已就绪的Socket写入用户空间。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值