目录
Redis过期删除和内存淘汰策略:
过期删除策略:
内存淘汰策略(解决内存过大问题):
LRU和LFU以及他们在Redis里的实现
主从复制
哨兵模式
缓存
缓存雪崩
缓存击穿
缓存穿透
数据库和缓存一致性问题
Redis过期删除和内存淘汰策略:
过期删除策略:
当对一个key设置过期时间之后,Redis会将其加入到过期字典中,Redis里使用的是惰性删除和定期删除相结合的方式,惰性删除是当查询key的时候,先判断是否在过期字典中存在,如果存在,则判断过期时间和当前时间的大小,如果还未过期,返回查询的结果,如果过期,就删除。定期删除每过一段时间在过期字典中随机抽查一些key,判断是否过期,如果过期的key占抽查的key25%以上,就会继续抽查,直到小于25%。然后再过一段时间之后继续抽查。
内存淘汰策略(解决内存过大问题):
当Redis的内存超过最大运行内存时,会触发内存淘汰策略,第一种不进行数据淘汰策略,是Redis3.0版本之后的默认内存淘汰策略,当超过最大内存限制之后,不能再添加key,但是可以查询。
两大种:在设置了过期时间的数据中进行淘汰,1.随机淘汰。2.优先淘汰更早的键值对。3.LRU淘汰算法(最近最少使用)。4.LFU淘汰算法(最近最不常用)。
在所有数据种进行淘汰,1.随机淘汰。2.LRU。3.LFU
LRU和LFU以及他们在Redis里的实现
LRU算法是基于链表的结构,链表中的元素按照操作顺序从后往前排列,最新的操作会被移动到链表头部,淘汰时只需要删除链表尾部的元素。
因为,传统LRU算法需要涉及很多链表的移动操作,会耗时间,影响Redis缓存的性能,所以Redis用的是近似的LRU算法。是在Redis的对象结构体中添加一个额外字段,用于记录此数据的最后一次访问时间。当Redis进行内存淘汰时,会随机采样来淘汰数据,淘汰最久没使用的那个。缺点 无法解决缓存污染问题,比如某一次读取了大量的数据,一下就把内存占满了,那之前的数据就会被清除掉,而这个数据如果只用一次,就会在Redis留存很长的时间,会造成缓存污染。
为了解决问题,Redis 4.0之后引入了LFU算法(最近最不常用),根据访问次数来淘汰数据。Redis里用的是,在Redis的对象结构体中添加了数据的访问频次字段lru,lru 24bits,高16bit存储ldt,记录访问时间戳,低8bit存储 logc,记录访问频次。然后根据这两个值来判断是否淘汰。
主从复制
为了解决单点故障的问题,Redis提供了主从复制模式,并且主从服务器采用的是读写分离方式,主服务器可以读写,当发生写操作时自动把写操作同步给从服务器,从服务器一般是只读,并且接收主服务器同步过来的写操作命令,然后执行命令。
第一次同步:
1.建立连接(replicaof 命令),确定主从。主服务器会返回FULLRSYNC响应命令,表示采用全量复制,把所有数据都同步给从服务器。
2.将主服务器同步数据给从服务器。主服务器生成RDB快照(异步操作,不会影响Redis处理命令)并发送给从服务器,从服务器清空所有数据然后载入RDB文件。但是同步期间发生的操作命令,主服务器会将命令写入到 replication buffer 中,会通过第三步发送给从服务器
3.主服务器发送新写操作给从服务器,将replication buffer中的写操作命令发送给从服务器。
命令传播:TCP连接,长连接。传输写操作命令
分摊主服务器压力:服务器B可以是服务器A的从服务器,也可以是服务器C的主服务器。这样减少了主服务器生成RDB文件和传输文件的消耗。
增量复制:由于网络问题,如果主从服务器间的网络连接断开,无法保持主从一致,Redis采用了增量复制的方式继续同步,只会把网络断开期间主服务器收到的写操作命令同步给从服务器。
首先从服务器会发送自己读的位置,然后主服务器会在 环形缓冲区内查找位置,若找到,主服务器根据当前写的位置和从服务器读的位置,会将之间的增量写入到replication buffer ,然后发送给从服务器。若未找到,主服务器会采用全量同步方式。
哨兵模式
主从架构中,当主节点挂了,那就没有主节点来执行客户端写操作的请求,也不能给从节点进行数据同步了。哨兵机制能实现主从节点故障转移(监控,选主,通知),会检测主节点是否存活,如果发现挂了,就会选举一个从节点切换为主节点,并且把主节点的相关信息通知给各从节点和客户端。
监控:主观下线,哨兵每隔一秒ping所有主从节点,如果有主从节点没有在规定的时间响应哨兵的ping命令,哨兵就会标记为主观下线,此时会通知所有的哨兵,其他哨兵根据自身和主节点的网络状况来投赞成或拒绝票。如果赞成票数到达要求后 quorum(建议为哨兵个数的二分之一加一),此时会被哨兵标记为客观下线。
选哨兵进行主从故障转移:哨兵标记主节点客观下线后,该哨兵就会发起投票,其他哨兵投赞成或拒绝票。拿到半数以上赞成并且大于等于配置文件中quorum值,才能做leader。
选主:第一步:在已下线主节点(旧主节点)属下的所有「从节点」里面,挑选出一个从节点,并将其转换为主节点,选择的规则:
- 过滤掉已经离线的从节点;
- 过滤掉历史网络连接状态不好的从节点;
- 将剩下的从节点,进行三轮考察:优先级、复制进度、ID 号。在每一轮考察过程中,如果找到了一个胜出的从节点,就将其作为新主节点。
通知:让已下线主节点属下的所有「从节点」修改复制目标,修改为复制「新主节点」;
将新主节点的 IP 地址和信息,通过「发布者/订阅者机制」通知给客户端;
继续监视旧主节点,当这个旧主节点重新上线时,将它设置为新主节点的从节点;
缓存
用户请求时,利用Redis做MySQL的缓存层,Redis是内存数据库,相当于数据缓存在内存中。虽然速度比磁盘提升几个等级,但引入缓存层后,会出现缓存穿透、击穿、雪崩问题。
缓存雪崩
大量缓存数据在同一时间过期,或者Redis故障宕机,此时如果有大量的用户请求,都无法在Redis中处理,于是全部请求都直接访问数据库,导致数据库宕机,造成系统崩溃。
解决办法:
针对大量缓存数据在同一时间过期:
1.随机设置过期时间,保证数据不会在同一个时间过期。
2.添加互斥锁,如果发现访问的数据不在Redis里,就加一个互斥锁(设置过期时间。防止出现意外不释放锁,其他请求拿不到锁),保证同一时间内只有一个请求来构建缓 存,当缓存构建完成后,再释放。
Redis故障宕机:
1.通过主从节点的方式构建Redis集群。当主节点宕机,可以通过哨兵选主,避免了宕机带来的问题。
2.启动服务熔断(限流。只能少部分请求)机制,暂停业务应用对缓存服务的访问,直接返回错误,不用再继续访问数据库,降低了对数据库访问的压力,等Redis恢复正常后,再允许业务访问。
缓存击穿
热点数据过期了,但是大量请求访问这个热点数据。缓存中没了,就要去数据库查询。数据库很容易发生崩溃。
解决方法:
1.添加互斥锁
2.不给热点数据添加过期时间。或者在热点数据将要过期前,提前通知后台更新缓存以及重新设置过期时间。
缓存穿透
请求到来时,访问缓存没有数据,访问数据库也没有数据,无法构建缓存数据。大量的请求,导致数据库压力激增。
解决方法:
1.非法请求的限制。
2.发现缓存穿透现象时,可以针对查询的数据,在缓存中设置一个空值或默认值。
3.布隆过滤器。在写入数据时,先在布隆过滤器中做标记。等请求来时,判断是否标记过。
数据库和缓存一致性问题
并发情况下,先更新数据库,再删除缓存可以解决数据库和缓存一致性问题。但是如果第二步操作没有成功执行,那末还是没作用。
解决办法:
1.给缓存设置较短的过期时间,勉强可以解决一些问题。
2.利用消息队列,将第二个操作加入到消息队列。如果删除缓存失败,那就可以从消息队列中重新读取数据,然后再次删除缓存。这个就是重试机制。