redis做为缓存相关的问题
缓存预热
1.定期生成,不涉及"预热"
2.实时生成
问题:redis服务在刚启动的时候,初始没有数据,就会导致所有请求全部打到MySQL中。
解决办法:可以将定期生成和实时生成结合一下,通过离线的方式,统计一点热点数据,导入redis中,分担MySQL的压力。
缓存穿透
问题:对于查询某个redis中没有的key,mysql中也没有,那么这个key就不会被更新到缓存中,每次查询就会都直接打到mysql上,这样的数据如果过多,反复查询,就会给mysql带来很大的压力。
1.设计不合理,比如对参数校验不合理
2.不小心对数据库进行误删
3.黑客恶意攻击
解决办法:
1.如果发现某个key在redis和mysql上都不存在,仍然写入redis,value设成一个非法值(比如"")。
2.引入布隆过滤器在查询钱判断是否存在。
缓存雪崩
问题:由于短时间内,redis上大规模的key失效,导致缓存命中率陡然下降,并且mysql的压力迅速上升,甚至直接宕机。
1.redis直接挂了
2.同时设置了大量的key,并且设置了同一个过期时间
解决办法:
1.加强监控报警,加强redis集群的可用性的保证。
2.不给key设置过期时间或者在设置过期时间的时候加上一个随机因子(避免同一时间过期)。
缓存击穿
问题:相当于缓存雪崩的特殊情况下,针对于热点的key突然过期,导致大量请求直接打到数据库,甚至引起数据库宕机。
热点的key访问频率更高,影响更大
解决办法:
基于统计的方式发现热点的key,并设置永不过期。
进行必要的服务器降低,例如使用数据库的时候使用分布式锁,限制同时请求数据库的并发数。
redis和mysql如何保证双写一致性?
什么是双写一致性:用户修改数据的时候,需要对数据库进行修改,那么同时也需要修改缓存中的数据,但是如果直接写数据库和写redis的时候,有一方出现问题,就可能导致数据不一致的问题。
解决办法:
强一致性要求高的数据:
延迟双删:读的时候,如果没有数据就写入缓存,写的时候先删除缓存,再更新数据库,延迟一段时间后(数据库需要同步数据),再删除缓存。
这种办法也会存在数据不一致的问题,可以通过加读写锁的方式,来解决写的时候读的问题。
延迟一致性的数据:
异步通知保证数据的最终一致性,将要修改的数据发生到rabbitmq,异步实现数据的一致性。
或者是基于canal的异步通知,监听mysql的binlog。
redis作为缓存,数据的持久化是怎么做到?
reids持久化的方式:1.RDB 2.AOF
区别:
RDB:redis的数据快照,把内存中的所有数据都记录在磁盘中,如果redis发生故障重启后,从磁盘中读取快照文件,恢复数据。(数据安全性要求比较低)
AOF:redis处理的每一个命令都会记录在AOF文件中,可以看做是命令日志文件,通过把这个文件再执行一遍来恢复数据。(数据安全性要求比较高)
哪种恢复的比较快?
RDB因为是二进制文件,保存的时候体积比较小,恢复比较快,但是可能造成数据丢失,AOF虽然慢,但是风险比较小。

redis数据过期策略
惰性删除:访问一个key时发现已经过期再删除
定期删除:每隔一段时间进行一次扫描,删除掉已经过期的key
redis中同时使用了惰性过期和定期过期两种过期策略。
1.每隔100ms就随机抽取一定的key来检查和删除
2.在获取key的时候,也会进行检查是否过期,过期了就会删除
内存淘汰策略
FIFO先进先出
把缓存中存在时间最久的淘汰掉
LRU淘汰最久未使用的
记录每个key的最近访问时间,把最近访问时间最老的key淘汰掉
LFU淘汰访问次数最少的
记录每个key最近一段时间的访问次数,把访问次数最少的淘汰掉
Random随机淘汰
Redis的内存淘汰策略有哪些?
redis提供了很多种,默认是noeviction,不删除任何数据,内存不足直接报错。
可以在redis的配置文件中进行配置,有两个非常重要的概念是LRU和LFU
LRU的意思是最少最近使用,删除访问时间最老的key
LFU的意思是最少频率使用,删除使用频率最少的key
数据库中有1000万数据,redis只能缓存20w数据,如何保证redis中的数据都是热点数据?
可以使用allkeys-lru(挑选最近最少使用的数据淘汰)
redis内存用完了会发生什么?
redis默认的策略是noeviction,会直接报错
redis作为分布式锁
1.如何实现的
使用redisson实现分布式锁,底层是setnx和lua脚本保证原子性
2.如何合理控制锁的有效时长
使用WatchDog(看门狗),一个线程获取锁成功之后,WatchDog会给持有锁的线程续期
3.redisson这个锁可重入吗?
可重入,redis记录了获取锁的线程信息和重入的次数
4.redisson锁能解决主从数据一致性的问题吗?
不能解决,但是可以使用redisson提供的红锁(多个redis共同进行加锁),但是性能比较差,建议使用zookeeper实现。
redis的集群方案
主从复制
主节点主要负责写操作,从节点负责读操作,主节点写操作之后,要把数据同步给从节点。
介绍一下redis的主从同步?
单节点redis的并发能力是有上限的,需进一步提高redis的并发能力,就需要搭建主从集群,实现读写分离。一般都是一主多从,主节点负责写数据,从节点负责读数据。
能说一下,主从同步数据的流程吗?
全量同步
1.从节点请求主节点同步数据(replication id 、offset)
2.主节点判断是否是第一次请求,是第一次就与从节点同步版本信息(replication id和offset)
3.主节点执行bgsave,生成rdb文件后,发送给从节点去执行。
4.在rdb生成执行期间,主节点会以命令的方式记录到缓存区(一个日志文件)
5.把生成之后的命令日志文件发送给从节点进行同步。
增量同步:
1.从节点请求主节点同步数据,主节点判断是不是第一次请求,不是第一次就获取从节点的offset的值。
2.主节点从命令日志中获取offset值之后的数据,发送给从节点进行数据同步。
哨兵的作用
redis提供了哨兵(sentinel)机制来实现主从集群的自动故障恢复。
怎么保证redis的高并发高可用?
使用哨兵模式:实现主从集群的自动故障恢复(监控、自动故障恢复、通知)
你们使用redis是单点还是集群,哪重集群?
主从(1主1从)+哨兵就可以了
redis集群脑裂,该怎么解决?
集群脑裂:由于主节点和从节点和哨兵处于不同的网络分区,如果哨兵没有能够感知到主节点的心跳,就会通过选举的方式提供了一个从节点为主,这样就存在了两个master,就像大脑分裂了一样,这样就会导致客户端还在老的主节点那里写入数据,新节点无法同步数据,当网络恢复后,哨兵会将主节点降为从节点,再从从节点那里同步数据,就会导致数据丢失。
解决:可以修改redis的配置,可以设置最少的从节点数量以及缩短主从数据同步的延迟时间,达不到要求就拒绝请求,避免数据的丢失。
分片集群结构
引入多个主节点解决内存不够的问题
redis的分片集群有什么作用
集群中有多个master,每个matser保存不同的数据
每个master都可以有多个slave节点
master之间通过ping监测彼此之间的健康状态
客户端请求可以访问集群任意节点,最终都会被正确的转发到正确的节点。
redis分片集群中数据是怎么存储和读取的?
redis分片集群引入了哈希槽的概念,redis集群中有16384个哈希槽。
将16384个插槽分配到不同的实例
读写数据:根据key的有效部分计算哈希值,对16384取余,余数作为插槽,寻找对应的实例。
Redis是单线程的,但为什么还那么快
redis是纯内存操作,执行速度非常快。
采用单线程,避免不必要的上下文切换可竞争条件,多线程还要考虑线程安全问题。
使用IO多路复用模型,非阻塞IO
能解释一下I/O多路复用模型吗?
是指利用单个线程来同时监听多个socket,并在某个socket可读、可写时得到通知,从而避免无效的等待,充分利用CPU资源。reids采用epoll实现,他会通知用户进程socket就绪的同时,把已就绪的socket写入用户空间,不需要遍历socket判断是否就绪,提高了性能。