Redis
缓存穿透
描述:缓存穿透是指查询一个一定不存在的数据,由于缓存是不命中时需要从数据库查询,查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到数据库去查询,进而给数据库带来压力
解决:
-
对url中的key id值进行加密,不轻易暴露出真实的key值,防止黑客攻击
-
不管数据实际上存在不存在,都把这个键存入缓存
value为空不代表不占用内存空间,比较有效的方法就是针对这类数据设置一个较短的过期时间
缓存层和存储层的数据会有一段时间窗口的不一致。可以利用消息系统或者其他方式清除掉缓存层中的空对象
-
布隆过滤器拦截
在访问缓存层和存储层之前,将存在的key用布隆过滤器提前保存起来,做第一层拦截
优点:空间效率和查询效率都远远超过一般的算法
弊端:有一定的误识别率
缓存击穿
描述:给某一个key设置了过期时间,当key过期的时候,恰好这时间点对这个key有大量的并发请求过来,这些并发的请求可能会瞬间把数据库压垮
解决方案一:互斥锁,强一致,性能差
解决方案二:逻辑过期,高可用,性能优,不能保证数据绝对一致
缓存雪崩
描述:缓存雪崩是指在同一时段大量的缓存key同时失效或者redis服务宕机,导致大量的请求到达数据库,带来巨大压力。
解决方案:
给不同的key过期时间添加随机值
利用redis集群提高服务的可用性
给缓存业务添加降级限流策略
给业务添加多级缓存
双写一致性
描述:当修改了数据库的数据也要同时更新缓存的数据,缓存和数据库的数据要保持一致
一致性要求高;允许延迟一致
- 延迟双删,降低脏数据的出现,但仍存在脏数据的风险
- 分布式锁:共享锁、排他锁。强一致、性能低
- 异步通知:表数据发生变化的时候通知变更情况更新缓存,确保最终一致
持久化
- ROB Redis数据备份文件 把内存中的所有数据记录到磁盘中,当Redis实例故障重启后,从磁盘读取快照文件,恢复数据。例如配置多少秒内有几条数据修改则进行数据备份。
- AOF 追加文件 Redis处理的每一个写命令都会记录在AOF文件,可以看做命令日志文件。
数据过期策略
描述:Redis对数据设置数据的有效时间,数据过期以后,就需要将数据从内存中删除掉。可以按照不同规则进行删除,这种删除规则就被称之为数据的删除策略。
- 惰性删除
- 定期删除
数据淘汰策略
描述:当Redis中的内存不够用时,此时向Redis中添加新的key,那么Redis就会按照某一种规则将内存中的数据删除掉,这种数据的删除规则被称之为内存的淘汰策略。
- volatile-lru:从已设置过期时间的数据集中挑选最近最少使用的数据淘汰。
- volatile-ttl:从已设置过期时间的数据集中挑选将要过期的数据淘汰。
- volatile-random:从已设置过期时间的数据集中任意选择数据淘汰。
- volatile-lfu:从已设置过期时间的数据集挑选使用频率最低的数据淘汰。
- allkeys-lru:从数据集中挑选最近最少使用的数据淘汰
- allkeys-lfu:从数据集中挑选使用频率最低的数据淘汰。
- allkeys-random:从数据集中任意选择数据淘汰
- no-enviction(驱逐):禁止驱逐数据,这也是默认策略。意思是当内存不足以容纳新入数据时,新写入操作就会报错,请求可以继续进行,线上任务也不能持续进行,采用no-enviction策略可以保证数据不被丢失。
分布式锁
在分布式系统里,有时执行定时任务,或者处理某些并发请求,涉及到多个进程之间的同步,需要确保多点系统里同时只有一个执行线程进行处理。分布式锁就是在分布式系统里互斥访问资源的解决方案。
Redis集群
- 主从复制
描述:单节点Redis的并发能力是有上限的,要进一步提高Redis的并发能力,就需要搭建主从集群,实现读写分离。一般是一主多从,主节点负责写数据,从节点负责读数据。
全量同步:
- 从节点请求主节点同步数据(replication id、offset)
- 主机点判断是否是第一次请求,是第一次就与从节点同步版本信息
- 主节点执行bgsava,生成RDB文件,发送给从节点去执行
- 在RDG生成执行期间,主节点会以命令的方式记录到缓冲区(一个日志文件)
- 把生成之后的命令日志文件发送给从节点进行同步
增量同步:
- 从节点请求主节点同步数据,主节点判断不是第一次请求,就获取从节点的offfset值
- 主节点从命令日志中获取offset值之后的数据,发送给从节点进行数据同步
-
哨兵模式
-
监控:Sentinel会不断检查master和slave是否按预期工作
-
自动故障恢复:如果master故障,Sentinel会将一个slave提升为master。当故障实例恢复后也以新的master为主
-
通知:Sentinel充当Redis客户端的服务发现来源,当集群发生故障转移时,会将最新信息推送给Redis的客户端
-
– 脑裂解决方案:修改Redis配置,设置最少salve节点为一个;减少数据复制和同步的延迟时间
-
分片集群
-
集群中有多个master,每个master保存不同数据
-
每个master都可以有多个slave节点
-
master之间通过ping检测彼此健康状态
-
客户端请求可以访问集群任意节点,最终都会被转发到正确节点
-
分片集群中数据是怎么存储和读取的
Redis分片集群引入哈希槽的概念,Redis集群有16384个哈希槽
将16384个插槽分配到不同的实例
读写数据:根据key的有效部分计算哈希值,对18384取余(有效部分,如果key前面有大括号,大括号的内容就是有效部分,如果没有,则以key本身做为有效部分)余数做为插槽,寻找插槽所在的实例。
其他
Redis速度快的原因:
- Redis是纯内存操作,执行速度非常快
- 采用单线程,避免不必要的上下文切换可竞争条件,多线程还要考虑线程安全问题
- 使用I/O多路复用模型,非阻塞IO
– I/O多路复用:Redis是纯内存操作,执行速度非常快,它的性能瓶颈是网络延迟而不是执行速度,I/O多路复用模式主要就是实现了高效的网络请求
用户空间和内核空间
常见的IO模型
-
阻塞IO:当用户线程发出IO请求之后,内核会去查看数据是否就绪,如果没有就绪就会等待数据就绪,而用户线程就会处于阻塞状态,用户线程交出CPU。当数据就绪之后,内核会将数据拷贝到用户线程,并返回结果给用户线程,用户线程才解除block状态。
-
非阻塞IO:当用户线程发起一个read操作后,并不需要等待,而是马上就得到了一个结果。如果结果是一个error时,它就知道数据还没有准备好,于是它可以再次发送read操作。一旦内核中的数据准备好了,并且又再次收到了用户线程的请求,那么它马上就将数据拷贝到了用户线程,然后返回。在非阻塞IO模型中,用户线程需要不断地询问内核数据是否就绪,也就说非阻塞IO不会交出CPU,而会一直占用CPU。
-
IO多路复用:利用单个线程来同时监听多个Socket,并在某个Socket可读、可写时得到通知,从而避免无效的等待,充分利用CPU资源
Redis网络模型
连接应答处理器
- 连接应答处理器
- 命令回复处理器
- 命令请求处理器