Redis原理讲解
Redis是什么?
远程字典服务(Remote dictionary server ),是一种使用C语言编写的,可基于内存亦可持久化的日志型,Key_Value数据库,并提供多种语言的API。会周期性地把更新的数据写入磁盘,或者把修改操作写入追加的记录文件,并在此基础上实现主从复制。
Redis是一个开源的,内存中的数据结构存储系统。它可以用作数据库,缓存,消息中间件MQ。它支持多种类型的数据结构,如字符串,散列,列表,集合,有序集合。范围查询;bitMaps,地理空间索引半径查询。内置了复制,LUA脚本,LRU驱动事件,事务和不同级别的磁盘持久化,并通过redis哨兵和自动分区提供高可用性。
Redis能干什么?
1、 内存存储、持久化。内存断电即失,持久化很重要(rdb,AOF)!
2、 效率高,用于高速缓存;
3、 发布订阅系统;
4、 地图信息分析;
5、 计时器,计数器(浏览量);
Redis有什么特性?
1、多样化的数据类型。8种,5种基本数据类型String , hash, List, Set, SortSet ,3种其他数据类型 HyperLoglog , BitMaps, Geo。
2、持久化, RDF, AOF 两种方式。
3、集群。Cluster集群,可以将数据分片存储,在线扩容,提供主从复制,负载均衡,故障转移,节点间gossip协议进行通信。
4、事务
Redis为什么是单线程还很快?
Redis是基于机器的内存和网络的带宽,是可以单线程实现的。为什么是不用多线程呢?因为多线程不一定是比单线程快,多线程有上下文切换,这
是一个耗时的操作。对于内存来说,如果没有上下文的切换,效率就是最高的。多次读写都在一个CPU上,在内存上就是一个最佳方案。
Redis事务?
Redis单条命令是保证原子性的,但是redis事务是不保证原子性的!
Redis事务的本质就是一组命令的集合。一个事务的所有命令都会被序列化,会按照顺序执行。一次性,顺序性,排他性!执行一系列的命令。
Redis事务没有隔离级别的概念。所有的命令在事务中并没有直接被执行。只有发起执行命令的时候才会被执行。
Redis的事物务分为三种阶段:
开启事务(multi)
命令入队(…..)
执行事务(exec)
Redis的几种数据类型?
String,List,Hash,set,Zset, Geo,hyperloglog,bitMaps。
Redis的几种键删除策略?
一、惰性删除
做法是:设置一个key过期时间后,我们不去管它。当需要该key时,我们在检查其是否过期,如果过期我们就删掉它,反之返回该key。
优点:对CPU时间友好。缺点:对内存不友好。假设数据库中有很多过期键,但是这些键就一直没有被访问到,但是却一直占用着宝贵的内存资源,造成资源浪费。
Redis的惰性删除策略由 expireIfNeeded 函数实现,所有键读写命令执行之前都会调用 expireIfNeeded 函数对其进行检查,如果过期,则删除该键,然后执行键不存在的操作;未过期则不做操作,继续执行原有的命令。
二、定期删除
做法是:每隔一段时间,我们就对一些key进行检查,删除里面过期的key。这是定时删除和惰性删除的一种折中方案。
定期删除策略每隔一段时间执行一次删除过期键操作,并通过限制删除操作执行的时长和频率来减少删除操作对CPU时间的影响,同时,通过定期删除过期键,也有效地减少了因为过期键而带来的内存浪费。
由activeExpireCycle 函数实现,函数以一定的频率运行,每次运行时,都从一定数量的数据库中取出一定数量的随机键进行检查,并删除其中的过期键。
三、定时删除
做法是:在设置某个key 的过期时间的同时,我们创建一个定时器,让定时器在该过期时间到来时,立即执行对其进行删除的操作。
优点:对内存友好。缺点:对CPU时间不友好。如果此时有大量的并发请求等待服务器处理,而服务器把大量的时间用在了删除过期键上,势必会影响服务器的吞吐量和响应时间。也就是说,大量的定时器会降低服务器处理命令请求的性能。
Redis持久化
Redis是内存数据库,如果不将内存中的数据库状态保存到磁盘,那么一旦服务器进程退出,服务器中的数据库状态也会消失,所有redis提供了持久化的功能。
Redis 的RDB
RDB(RedisDataBase)
在指定的时间间隔内,将内存中的数据集快照写入磁盘,也就是snapshot快照,恢复时是将快照文件直接读入内存中。
Redis会单独创建一个fork子进程来进行持久化,它会先将数据写入一个临时文件。待持久化操作结束后,再用这个临时文件替换上次持久化好的文件。整个过程中,主进程是不进行任何IO操作的。
RDB的缺点:最后一次持久化会丢失数据,这就确保了极高的性能,rdb保存的文件dump.rdb都是在快照中进行配置的。
RDB触发机制
1、 save规则满足的情况下,会自动触发rdb规则;
2、 执行flushall命令,也会触发我们的rdb规则;
3、 退出redis命令,也会产生rdb文件;
4、 备份就会自动生成一个dump.rdb。
如果恢复rdb文件,可以这样做:
1 只需要将rdb文件放在我们redis启动目录就好。Redis启动的时候会自动检查dump.rdb恢复其中的数据。
2 查看需要存在的位置;
127.0.0.1:6379> config get dir
- "dir"
- "D:\Redis" 如果这个目录下存在dump.rdb,那么启动就会自动恢复其中的数据。
RDB优缺点
优点:
1、适合大规模数据恢复!
2、如果你对数据完整性要求不高,也是可以使用rdb。
缺点:
1 需要一定的时间间隔进程操作,如果redis意外宕机了,这个最后一次修改的数据就没有了。
2 Fork进程的时候,会占用一定的内容空间。
AOF
AoF保存的文件是append.aof,默认是不开启的,我们需要手动配置。重启生效!将所有的写操作记录到日志!
如果aof配置文件有错误,redis是启动不了的;这个时候要修复aof文件。Redis提供了工具,redis_check.aof -fix appendonly.aof
如果文件正常,重启就可以直接恢复了。
重写规则说明:
Aof默认的就是文件的无限追加,文件会越大越大!
如果aof文件大于64MB,太大了,就会fork一个新的进程,来对文件进行重写。
Aof的优点和缺点
优点: 每一次修改都同步,文件的完整性会更加好。
每秒同步一次,可能会丢失一秒的数据。
从不同步,效率是最高的!
缺点:
相对于数据文件来说,Aof体积远远大于rdb, 但数据恢复的速度也比rdb慢;
Aof的运行效率也比rdb慢;redis默认的持久化是rdb,而不是aof。
RDB PK AOF
1、RDB持久化方式能够在指定的时间间隔内对你的数据进行快照存储;
2、AOF持久化方式记录每次对服务器写的操作,当服务器重启的时候,就会重新执行这些命令来恢复原始数据;
AOF命令以redis协议追加保存每次的写操作到文件末尾;redis还能对AOF后台文件进行重写,使得AOF文件的体积不至于过大。
3、只做缓存;
4、同时开启两种持久化的方式;
AOF的重写过程
答:首先,AOF的体积大于阈值的时候,会触发AOF重写。此时主进程可以继续运行,fork一个子进程来进行重写的操作。
第一步,先遍历Redis进程中的所有数据,生成写入命令写入到一个新的AOF临时文件中。
第二步,子进程运行过程中,主进程产生的写入增量命令会被存储到一个缓冲区。
第三步,将缓冲区的增量命令也追加到AOF临时文件中。这个追加的时机是在子进程将要完成AOF重写后,并将缓冲区的内容写入AOF临时文件;
并给主进程发一个通知,通知此时可以切换AOF文件了。然后主进程收到通知以后,再将缓冲区的内容写入AOF临时文件。
第四步,使用这个新的AOF临时文件去替换旧的AOF文件。从而完成AOF的重写过程。
注意,混合持久化的情况。如果服务器开启了混合持久化,则生成RDB数据文件到临时文件中,否则将进程中所有数据转换为写入命令写入临时文件。
Redis缓存雪崩?
缓存雪崩是大量的缓存集中在同一时间失效,对数据集DB造成很大的压力。
解决的办法
限流降级
在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个key只允许一个线程查询数据和写缓存,其他线程等待。
数据预热
在正式部署前,先把可能的数据先预先访问一次,这样部分可能大量访问的数据就会加载到缓存中。在即将发生大并发访问前手动触发加载缓存不同的key,设置不同的过期时间,让缓存失效的时间点尽量均匀。
Redis缓存击穿
key对应的数据存在,但是在Redis中过期,这时有大量的并发请求过来,发现key已经过期,就会去数据库中加载数据回设到缓存,这时大并发的请求会瞬间把后端数据库击垮。这就是缓存击穿。
解决方法:设置热点数据不过期;或者加互斥锁,保证对于每一个key同时只有一个线程去查询后端服务器,其他线程没有获得分布式锁的权限,因此只需要等待即可。这种方式将高并发的压力转移到了分布式锁,因此对分布式锁的考验很大!
Redis缓存穿透
缓存穿透是用户想要查询一个数据,发现缓存中没有,然后就去请求数据库,但是数据库也没有这个数据。如果有大量的并发请求都去查询这样一个缓存和数据库都不存在的数据,给数据库造成很大的压力,那么就会发生缓存穿透。
解决的办法
布隆过滤器
布隆过滤器是一种数据结构。对所有可能查询的参数以hash的形式存储,在控制层先进行校验,不符合则丢弃。从而避免了对底层存储系统的查询压力。
缓存空对象
简单粗暴,如果查询DB返回的数据为空,我们仍然把这个空值放到Redis缓存中,只是将它的过期时间设置的很短,另外为了避免不必要的内存消耗,可以定期清理空值的key。
Redis主从复制
Redis主从复制和mysql的主从复制性质差不多,为了实现数据备份和读写分离。在redis中我们可以通过slaveof命令来让一个服务器去复制另一个服务器,被复制的服务器是主服务器,复制的服务器叫从服务器。由主从服务器组成的模式叫主从复制。
80%的情况下,都是在进行读操作,从而减缓服务器的压力。
主从复制的作用主要包括:
1 、数据冗余。主从复制实现了数据的热备份,是持久化的一种数据冗余方式;
2 、故障恢复。当主节点出现问题时,可以由从节点提供服务。实现快速的故障恢复,实际上是一种服务的冗余;
3 、负载均衡。在主从复制的基础上,配合读写分离;可以由主节点提供写服务,由从节点提供读服务(写操作连接主节点,读操作连接从节点),分担服务器负载;尤其是在写少读多的场景下,通过多个从节点分担读复载,可以大大提高Redis服务器的并发量;
4 、高可用(集群)基石。
Redis主从复制的特点
(1)一个master可以有多个slave;
(2) 采用异步复制;
(3)每个从redis可以接收来自其他从redis服务器的连接;
(4) 主从复制对于主服务器来说是非阻塞的;这意味着当从服务器在进行主从复制同步过程中,主redis仍然可以处理外界的访问请求;
(5)主从复制提高了redis的可扩展性。主从复制提高了redis服务的扩展性,避免单个redis服务器的读写访问压力过大的问题,同时也可以给为数据备份及冗余提供一种解决方案;
(6)主从复制对于从redis服务器来说也是非阻塞的,这意味着,即使从redis在进行主从复制过程中也可以接受外界的查询请求,只不过这时候从redis返回的是以前老的数据,如果你不想这样,那么在启动redis时,可以在配置文件中进行设置,那么从redis在复制同步过程中来自外界的查询请求都会返回错误给客户端;(虽然说主从复制过程中对于从redis是非阻塞的,但是当从redis从主redis同步过来最新的数据后还需要将新数据加载到内存中,在加载到内存的过程中是阻塞的,在这段时间内的请求将会被阻,但是即使对于大数据集,加载到内存的时间也是比较多的);
(7)为了编码主redis服务器写磁盘压力带来的开销,可以配置让主redis不在将数据持久化到磁盘,而是通过连接让一个配置的从redis服务器及时的将相关数据持久化到磁盘,不过这样会存在一个问题,就是主redis服务器一旦重启,因为主redis服务器数据为空,这时候通过主从同步可能导致从redis服务器上的数据也被清空;
Redis主从复制的原理
全量复制:slave服务在接收到所有数据库文件数据后,将其存盘并加载到内存中。
增量复制:master继续将新的所有收集到的修改命令依次传给slave,完成同步。但是只要是重新连master,一次完全同步(全量复制)将被自动执行。
原理:slave启动成功连接到一个master后会发送一个sync同步命令,master接到命令,启动后台的存盘进程,同时收集所有接收的用于修改数据集命令,在后台进程执行完毕后,master将传送整个数据文件到slave,并完成一次完全同步。但是只要是重新连接master,一次完全同步(全量复制)将被自动执行。我们的数据一定可以在丛机中。
主从复制中的哨兵模式(自动选举老大)
Sentinel(哨兵)是用于监控redis集群中Master状态的工具,是Redis 的高可用性解决方案,sentinel哨兵模式已经被集成在redis2.4之后的版本中。sentinel是redis高可用的解决方案,sentinel系统可以监视一个或者多个redis master服务,以及这些master服务的所有从服务;当某个master服务下线时,自动将该master下的某个从服务升级为master服务替代已下线的master服务继续处理请求。
sentinel可以让redis实现主从复制,当一个集群中的master失效之后,sentinel可以从slave中选举出一个新的master用于自动接替master的工作,集群中的其他redis服务器自动指向新的master同步数据。如果主机此时回来了,只能归并到此时新的主机下,当做丛机,这就是哨兵的规则!这里有一个很详细的帖子供参考。https://www.cnblogs.com/kevingrace/p/9004460.html
优点:
1、 哨兵集群,一般基于主从复制模式。所有的主从配置优点,它全有!
2、 主从可以切换,故障可以转移,系统的可用性就会好;
3、 哨兵模式就是主从模式的升级,手动到自动,更加健壮!
缺点:
1、 redis不会在线扩容的,集群容量一旦达到上限,在线扩容就会十分麻烦;
2、 实现哨兵模式的配置,其实是很麻烦的,里面有很多选择。