- 1、为什么要使用Redis(使用Redis的好处)?
- 2、Redis有哪些数据结构?
- 3、Redis的持久化机制?
- 4、RDB和AOF选哪个?
- 5、Redis的过期策略(或Redis过期数据的删除策略,或假设设置了一批key只能存活一分钟,那么一分钟后,Redis如何对这批key进行删除的)?
- 6、Redis的内存淘汰机制?
- 7、Redis如何判断数据是否过期?
- 8、Redis怎样保证高可用?
- 9、什么是缓存击穿?缓存穿透?什么是缓存雪崩?
- 10、如何保证缓存与数据的双写一致性?
- 11、谈一下Redis中的事务?
- 12、Redis主从复制是什么?能干嘛?主从复制如何操作?主从复制的原理?
- 13、Redis哨兵机制是什么?怎么用?
1、为什么要使用Redis(使用Redis的好处)?
- Redis的读写性能优秀,因为数据是存在内存中,读写性能很高;
- 它支持数据的持久化;
- 支持主从复制,主机可以自动将数据复制到从机上,实现读写分离;
- 支持集群,高性能,高可用;
- 有哨兵机制,高可用;
- 数据结构丰富,支持多种数据的存储;
- 可以通过Redis来实现分布式锁;
2、Redis有哪些数据结构?
Redis有五种基本数据类型:
- String:String数据结构是简单的key-value类型,它是二进制安全的,可以包含任何数据,比如jpg图片或者序列化对象,一个redis的String类型的value最多可以为512m;
- list:list是redis中的链表,它是一个双向链表,支持反向查找和遍历,更方便操作。但是它带来了部分额外的内存开销。它按照插入顺序排序,可以添加一个元素到列表的头部或者尾部;
- hash:hash类似jdk8之前的HashMap,是一个键值对集合,内部使用数组+链表实现。hash是一个string类型的key和value的映射表,特别适合用于存储对象,类似于Java中的Map
。 - set:set类似于java中的HashSet,它可以自动排重,是一个无序结合。如果需要存储一个列表数据,又不希望出现重复数据时,可以用set。并且set提供了一个判断某个成员是否在set集合内的接口,这时list所没有的。它底层是一个value为null的hash表,所以添加、删除、查找的复杂度都是O(1)。
- zset:又称sorted set,是有序集合,它和set一样,是一个没有重复元素的字符串结合。但是zset的每个成员都关联了一个权重参数score,这个权重参数被按照从最低分到最高分的凡事排序集合中的成员。集合中的成员是唯一不可以重复的,但是权重参数是可以重复的。
—-> Redis6中,新增了几个数据结构:
Bitmaps、HyperLogLog、Geospatial;
3、Redis的持久化机制?
Redis提供了两种持久化机制,一种是快照机制RDB,另一种是AOF。
RDB(snapshoting,快照):
RDB是什么:
RDB是在指定的时间间隔中,将内存中的数据集快照写入磁盘,它恢复的时候将快照文件直接读到内存中。
Redis可以通过创建快照来获取存储在内存里的数据在某个时间点上的副本。Redis创建快照后,可以对快照进行备份,也可以将快照复制到其他服务器上来创建具有相同数据的服务器副本(比如Redis主从结构,主要用来提高Redis性能),还可以将快照留在原地以便重启服务器的时候使用。
注意,RDB快照就是记录某一个瞬间的内存数据,记录的是实际数据。Redis的快照是全量快照,也就是说,每次执行快照,都是把内存中的Redis的所有数据记录到磁盘中。所以可以认为,执行快照是一个比较重的操作,如果频率太过频繁,可能会对Redis性能产生影响,;而如果频率太低,服务器故障时,丢失的数据会很多。
RDB是如何进行的:
Redis会单独创建(fork)一个子进程来进行持久化,会先将数据写入到一个临时文件中,等持久化的过程结束了,用这个临时文件,替换上次持久化好的文件。整个过程中,主进程是不进行任何IO操作的,这就确保了极高的性能。如果需要进行大规模的数据恢复,且对数据恢复的完整性不是非常敏感,那么RDB方式比AOF方式更加高效。
RDB方式最后一次持久化的数据可能丢失。
AOF(append-only file只追加文件):
AOF是什么
AOF是以日志的形式来记录每个写操作(增量保存)。会将Redis执行过的所有写指令记录下来(不记录读指令),只可以追加文件,但是不可以更改文件。Redis启动的时候,会读取该文件重新构建数据。也就是Redis重启的话,就会根据日志文件的内容,将写指令从前到后执行一遍,以完成数据的恢复工作。
AOF持久化流程:
- 首先,客户端的请求,写命令会被append追加到AOF缓冲区内;
- 然后,AOF缓冲区根据AOF持久化策略,将操作sync同步到磁盘的AOF文件中;
- AOF文件大小超过重写策略或手动重写时,会对AOF文件进行重写,压缩AOF文件的容量;
- Redis服务重启时,会重新加载AOF文件中的写操作,达到数据恢复的目的。
AOF细节:
与RDB相比,AOF持久化实时性更好,因此已成为主流持久化方案。默认情况下,Redis没有开启AOF,可以通过addpendonly参数开启: appendonly yes;
开启AOF后,每执行一条会更改Redis中数据的命令,Redis就会将该命令写入到内存缓存erver.aof_buf中,然后根据appendfsync配置来决定何时将其同步到硬盘的AOF文件中。
在Redis配置文件中,有三种不同的AOF方式(三种AOF持久化策略),分别是:
- appendfsync always:每次有修改发生时,都会写入AOF文件,这样会严重降低Redis的速度;
- appendfsync everysec:每秒钟同步一次,显示地将多个命令同步到硬盘;
- appendfsync no:让操作系统决定何时进行同步;
- 8
->为了兼顾数据和写入性能,用户可以考虑appendfsync everysec选项,让redis每秒同步一次aof文件,这样redis的性能几乎没有受到任何影响,而且这样即使出现系统崩溃,用户最多只丢失一秒内产生的数据。
4、RDB和AOF选哪个?
官方推荐两个都启用(两个都启用时,Redis会默认读取AOF的数据);
如果对数据不敏感,可以单独选用RDB;
官方说不要只使用AOF,可能有潜在的BUG;
如果只做纯内存缓存,可以都不用;
5、Redis的过期策略(或Redis过期数据的删除策略,或假设设置了一批key只能存活一分钟,那么一分钟后,Redis如何对这批key进行删除的)?
常用的过期策略有两个:
- 定期删除:每隔一段时间抽取一批key执行删除过期key的操作。并且Redis底层会通过限制删除操作执行的时长和频率来减少删除操作对CPU时间的影响。定期删除对内存更加友好。
- 惰性删除:只会在取出key的时候才会对数据进行过期检查。这样对CPU最友好,但是会可能造成太多过期的key没有删除,因此对内存不友好。
定期删除对内存更加友好,惰性删除对CPU更加友好,二者各有千秋,因此Redis采用的是定期删除+惰性删除一起。
—-> 但是,仅仅通过给key设置过期时间还是有问题的,因为还是可能存在定期删除和惰性删除漏掉了很多过期key的情况,这样就导致了大量过期key堆积在内存里,然后可能就Out Of Memory了。
如何解决这个问题? 答案是Redis的内存淘汰机制。详情见下一个问题。
6、Redis的内存淘汰机制?
Redis提供了六种内存淘汰机制(数据淘汰策略):
- no-eviction:禁止驱逐数据,这时默认的策略,但是实际上,应该没人用,因为这个策略下,当内存不足以写入新数据时,也不会进行数据淘汰,而是直接报错。
- allkeys-random:从数据集中任意选择数据进行淘汰。
- allkeys-lru(least recently used):最常用。当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的key。
- volatile-random:从已设置过期时间的数据集中任意选择数据淘汰;
- volatile-ttl:从已设置过期时间的数据集中挑选将要过期的数据淘汰;
- volatile-lru(least recently used):从已设置过期时间的数据集中挑选最近最少使用的数据淘汰;
4.0版本后增加了以下两种:
- volatile-lfu(least frequently used):从已设置过期时间的数据集中挑选最不常用的数据淘汰;
- allkeys-lfu(least frequently used):当内存不足以容纳新写入数据时,在键空间中,移除最不经常使用的key。
7、Redis如何判断数据是否过期?
Redis通过一个叫做过期字典的东西来保存数据的过期时间。(过期字典可以看作是个hash表)
过期字典的键指向Redis数据库中的某个key,过期字典的值是一个long long类型的整数,这个整数保存了key锁指向的数据库键的过期时间(是个毫秒精度的unix时间戳)。
—->后面再搜搜看吧。
8、Redis怎样保证高可用?
- 主从复制
- 哨兵机制
- 搭建集群
9、什么是缓存击穿?缓存穿透?什么是缓存雪崩?
注意,一开始这里我把缓存击穿缓存穿透搞成同一种情况了。其实二者不同。
缓存穿透:
缓存穿透是什么:
缓存穿透是指查询一个不存在的数据。
即大量请求的key,在缓存中根本不存在,这个时候由于缓存未命中,导致请求直接到了数据库上,根本没有经过缓存,这时数据库也没有这个记录,就不会在查询后往缓存中保存,就导致这个不存在的数据每次都要到数据库去查询,这就是缓存穿透。
风险:在流量大的时候,可能数据库压力过大,就挂掉了;如果有人利用不存在的key频繁攻击应用,这就是一种漏洞。
如何解决缓存穿透:
- 最基本的是做好参数校验,一些不合法的参数请求直接在前端或者请求到后台的时候,抛出异常信息返回给客户端,比如查询数据库id小于0、传入字段格式不对的数据,直接返回错误信息;
- 可以缓存无效key,如果这个key的数据在redis和数据库中都查不到,那就缓存这个key,给它一个空结果(null);当然这可能导致redis中缓存了大量无效的key,所以尽量设置一个比较短的过期时间,比如一分钟;
- 通过布隆过滤器(后续学习);
缓存雪崩:
缓存雪崩是什么:
缓存雪崩是指,缓存在同一时间大面积失效,导致后面的请求都直接转发到数据库上,造成数据库短时间内承受大量的请求,瞬时压力过大而雪崩。
如何解决缓存雪崩:
- 可以给缓存,比如热点数据设置过期时间的时候,增加一个随机值,这样每个缓存的过期时间的重复率就会降低,就很难引发缓存大面积集体失效的事件;
- 当然,也可以缓存永不失效;
- 针对Redis服务不可用的情况,采用Redis集群,避免单机Redis出现问题,导致整个缓存服务都不可用;
- 针对Redis服务不可用的情况,采取限流措施,避免同时处理大量请求;
10、如何保证缓存与数据的双写一致性?
采取双写模式:
数据库数据修改后,就也把缓存中的数据做修改。
这样可能产生脏数据,但是这个脏数据是暂时性的,在数据稳定,缓存过期后,又能得到最新的正确数据。
这时,可以在更新数据时,加锁来解决。在一个线程更新时,得到锁,等这个线程更新完了,释放锁了其他线程才能得到锁。又或者如果对数据的一致性要求不是特别高,可以在设计缓存时,设置一个过期时间,等缓存过期了,重新写入数据,一次来保证数据的最终一致性即可。
采取失效模式:
数据库修改后,就直接将缓存删掉,等下次查询时,进行更新缓存。
- 可能产生脏数据,也可以通过加锁来解决;
- 或者把缓存失效时间设短,这样的话缓存就会从数据库中加载数据,但这种方式治标不治本,而且对于先操作缓存再操作数据库的场景不适用;
- 常用 增加缓存更新重试机制,如果缓存服务当前不可用,导致缓存设置失败的话,就隔一段时间进行重试,重试的次数自己设定,如果多次重试还是失败,可以把当前更新失败的key存入队列中,等缓存服务可用后,再将缓存中对应的key删除即可。
11、谈一下Redis中的事务?
Redis事务是一个单独的隔离操作,事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户短发送来的命令请求所打断。Redis事务的主要作用就是串联多个命令防止别的命令插队。
Redis以multi命令来进行命令的组队,multi指令后面的命令会被放进一个队列中,遇到exec指令时执行队列里的所有指令,并返回所有执行结果,遇到discard命令时放弃组队。
在组队阶段,如果组队中某个命令出现了错误,那么执行时整个的队列都会被取消;
如果执行阶段,某个命令报出了错误,则只有报错的命令不会被执行,其他的命令都会执行,不会回滚。
—>Redis事务的三个特性;
- 单独的隔离操作:事务中所有的命令都会被序列化,按顺序的执行。事务在执行的过程中,不会被其他客户端发来的命令打断;
- 没有隔离级别的概念:队列中的命令没有提交之前都不会实际被执行,因为事务提交前任何指令都不会被实际执行;
- 不保证原子性:事务中如果有一条命令执行失败,其他的命令仍然会被执行,不会回滚。
12、Redis主从复制是什么?能干嘛?主从复制如何操作?主从复制的原理?
主从复制是什么:
主从复制是指将一台Redis服务的数据,根据配置和策略,自动同步到其他Redis服务器上。
前者称为主节点(master),后者称为从节点(slave)。数据复制是单向的,只能从主节点到从节点,主节点以写为主,从节点以读为主。默认情况下,每一台Redis服务器都是主节点,一个主节点可以有多个从节点(也可以没有),但一个从节点只能有一个主节点。
主从复制能干什么:
- 实现读写分离;
- 当服务器宕机,数据丢失,可以进行容灾快速恢复;
- 一台服务器的内存会达到峰值,也不可能无限升级,可以通过主从复制来达到扩展内存的效果;
主从复制如何配置:
百度;
主从复制的原理:
- 从机启动成功,连接到主机后会发送一个同步命令;
- 主机接到同步命令后,启动后台的存盘进程,同时收集所有接收到的用于修改数据集的命令,在后台进程执行完毕之后,主机将传送整个数据文件到从机,以完成一次完全同步;
- 全量复制:从机在接收到数据文件后,将其存盘并加载到内存中;
- 增量复制:主机继续将新的所有收集到的修改命令依次传给从机,完成同步;
- 只要是重新连接主节点,一次完全同步(全量复制)将被自动执行;
13、Redis哨兵机制是什么?怎么用?
哨兵机制:
在主从复制的基础上,哨兵机制是Redis下的一个特殊的进程,主从库运行的同时,它也在运行。哨兵主要负责三个任务:监控、选主和通知。它是实现主库和仓库切换的关键机制,有效的解决了主从复制模式下的故障转移。
哨兵在运行到时候,周期性的给所有主从库发送PING命令,检测他们是否仍然在线运行。如果仓库没有在规定时间相应哨兵的PING命令,哨兵就会把仓库标记为下线状态,同理,如果主库没有在规定的时间响应哨兵的PING命令,哨兵就会判定主库下线,然后开始自动切换主库的流程。
切换主库的流程:哨兵会从从库中,按照一定的规则选择一个从库实例,把它作为一个新的主库。这一步完成之后,现在就又有了新的主库。最后哨兵会把新的主库链接信息发给其他从库,让他们执行replicaof命令,和新的主库连接,并进行数据的复制。同时,哨兵会把新主库的链接信息通知给客户端,让他们把请求发送到新的主库上。