Redis原理总结(一文轻松掌握Redis底层原理)

1、产生背景

        Mysql的工作越来越繁重,导致Mysql快要累死了,究其原因还是Mysql有缓存,但会写入硬盘,从硬盘读取数据的IO操作很累,也很慢,所以就在想有没有内存数据库,于是Redis便应运而生。毕竟是内存数据库,避免了Mysql繁重的IO操作,所以对Redis的访问相比MYsql来说是很快的,同时也在很大程度上,减轻了数据库的负担。

2、使用方式

        最常用的方法就是配合Mysql进行操作,即由redis作为缓存,服务器想要获取数据,先查看Redis缓存中是否存有该数据,如果有,则直接从Redis返回,这样就不需要访问数据库,如果Redis没有,则访问数据库,并更新缓存。

如下图所示:

 3、Redis的缓存如何处理?

上述提到了不少Redis的好处,包括可以减轻数据库压力,能够更快的返回响应数据等等,但是,Redis毕竟是内存数据库,什么东西都存在内存里只会害了你,不去对这些数据进行管理删除得到话,内存是迟早要玩的,所以需要去对缓存的数据进行删除,该怎么去删除呢?

(1)定期删除

会对所有的缓存信息设置过期时间,会定期的随机选择一批数据,查看其是否过期,过期就删掉,不全盘清理过期时间的原因是太消耗时间,不能保证用户的请求做出快速的回应,所以定期删除的策略就是随机抽检,过期就删,可以高效的腾出空间来。

(2)惰性删除

定期删除有缺点吗?有的,万一有欧狗呢?万一就是有一个key过期了,但一直没有被随机选中呢,那么他就会活很长一段时间不会被清除,这时,又产生了一种崭新的删除策略,惰性删除,他很懒,随机删除相比全盘查找就已经算是很懒惰的处理方式了,惰性删除更懒 ,当这个key被访问时,过期了才会删,所以这叫惰性删除

(3)内存淘汰机制

惰性删除+定期删除的方式,并不能将过期数据清理干净,比如一个key是个比较幸运的,但又无人问津的,它的死活就很难通过定期删除和惰性删除去判断,还有一种情况,当过期时间所有的设置的很长,然后redis已经存不下了,但由于所有都没过期,也腾不出数据,这时就很危险,所以出现了内存淘汰机制。

  • volatile-lru(least recently used):从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰

  • volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰

  • volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰

  • allkeys-lru(least recently used):当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的 key(这个是最常用的)

  • allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰

  • no-eviction:禁止驱逐数据,也就是说当内存不足以容纳新写入数据时,新写入操作会报错。这个应该没人使用吧!

  • volatile-lfu(least frequently used):从已设置过期时间的数据集(server.db[i].expires)中挑选最不经常使用的数据淘汰

  • allkeys-lfu(least frequently used):当内存不足以容纳新写入数据时,在键空间中,移除最不经常使用的 key

 所以,不同系统可以根据情况,去选用不同的内存淘汰策略,去保证Redis的稳定性。

4、使用Redis做缓存会产生的问题

首先,我们需要知道的是,即使使用Redis做缓存来避免频繁的向数据库请求,Redis做的缓存也是有大小的,缓存一直存储在Redis中也并不合理,所以会有过期时间,对同一信息的访问,在过期时间内都可以在redis中找到,过期时间的设置会带来一定的问题,如下:

(1)缓存击穿

所谓缓存击穿,就是某一个存储在Redis中的key失效后,突然来了对这个key的大量访问,因为失效,Redis找不到了,那这些大量的访问请求就会向Mysql发起进攻,导致Mysql最后受不了了,这就是缓存击穿。

(2)缓存雪崩

所谓缓存雪崩,就是多个key同时失效,导致比上一种情况更加危险,Mysql可能直接就去世了,宕机了。

(3)布隆过滤器

这是解决上述两种问题的一种非常高效的方式,它可以去判断某一个东西是否“一定不存在或者可能存在”,是一种即为高效的判定方式,可以对一个查询进行判定,如果布隆过滤器说它一定不存在于数据库,那么就可以不访问数据库,避免了很大一部分非法或者错误的请求,但对于存在这个方面的判断,就有一定的误判率。

5、Redis的持久化机制

因为iRedis是内存数据库,如果没有持久化机制,作为缓存的Redis,本身就存在内存中,一旦崩溃宕机,再上线之后,之前所有存在内存里的缓存,就都没了,之前存的缓存就付之一炬了。

所以,Redis需要有一定的机制,去将缓存中的东西去刷新到硬盘上,这样,即使出现宕机的情况,也不至于说什么缓存都不剩下,一点备份都没有了的情况。

持久化机制如下:

(1)快照(RDB)

过创建快照来获得存储在内存里面的数据在某个时间点上的副本。

首先,副本一定不会小,如果短时高频的去保存副本,那redis也干不了别的事了,所以RDB提供了三种刷入硬盘的策略,也对应着不同的修改频度

当然,有一定缺点,分钟级别的持久化策略导致,最快,也是一分钟一次,导致一丢可能就会丢一分钟的数据,在访问量极大的情况下,其实一分钟也会丢不少的数据的。

 (2)只追加文件(AOF)

像MySQL中的binlog学习,,存储的不是数据,而是记载的是命令

然后在硬盘中存储命令的记录,内存中分一块区域去存储命令,然后去往硬盘中的AOF文件中,添加内容即可。

缺点是,只是一直向一个文件追加,硬盘中的这个文件会越来越大,会对硬盘造成很沉重的负担,所以出现了AOF重写,会对指令进行一定程度的合并。但这种方式还是很消耗时间,所以最终的策略还是跟rdb一样,去通过子进程去做这件事,但又会出现问题,子进程处理AOF重写这个比较耗时的操作时,Redis本身依旧有很大可能去收到命令,还需要在内存中存储一下,从交由子进程重写,到重写完成这段时间,新接到的数据,然后再AOF文件中写入重写后的命令,再加上新来的所有命令。这样就能保证这次AOF操作不会有遗漏,因为哪个新缓存保存了中间这段时间的遗漏问题。

6、Redis的主从复制、哨兵机制保证高可用性

(1)主从复制

看标题也可以知道,整这些花里胡哨的机制是为了什么?高可用性,说白了就是单Redis服务器还是有极限的,所以就可以多整好几个服务器,做主从,主节点主要负责写操作,从节点主要负责读操作,这样就可以从一定程度上优化,为什么呢?因为读操作比写操作一定多很多,这样把读写分开,就可以一定程度上去缓解压力。

主要原理是,主写从读,然后,主节点需要去将信息共享给从节点,可以跟上面说的一样,去发送一个RDB以及一个遗漏的命令列表(跟AOF里哪个子进程去处理一样),这样就能保证主从节点信息的统一。

当从节点宕机,该系统不会出现问题,无非就是其他从节点压力会大一点点,也不会立刻就去世的。有一个小小的问题,从节点宕机,回来之后肯定要数据同步的,当然,不管是主节点还是其他从节点,不出问题都会有全量的信息,宕机的从节点本地也有持久化,它内部也会存在很多信息,该如何去保证数据同步时,仅传递缺失的信息呢

Redis中要求主节点去维持一个复制偏移量,或者换句简单的话说,就是版本号,某个从节点会知道自己宕机前的版本号,等它上线后,去同步一下版本就好,去发送缺失的那部分版本即可。

(2)哨兵机制

主从复制看上去已经很不错了啊,还有优化的点吗?有的,主节点去世了怎么办呢?主节点一旦去世,整个系统就要去世了,当然,我们可以去人为的改变主从,就是将宕机的主节点变成从节点,整个从节点上去当主节点,然后去继续用,主节点回来就变成从节点了,同步信息当从节点就好了

可以智能一点吗?不需要程序员认为干预的那种自稳定的那种?

有,这就是哨兵机制

所谓哨兵机制,设置几个管理员,管理员的职责就是监控节点状态,包括主节点、从节点的状态,一旦主节点出现了故障,就通过几个管理员选举一个从节点上去当主节点,这里的选举机制可以是节点的性能(硬件配置高低)、优先级、以及上面说的复制偏移量的多少(当然,偏移量多的显然是更为适合当主节点的,因为它的版本最新嘛)

这里可以多说两句,这个所谓的管理员(哨兵),并不参与真正的数据读写,只是监控节点的作用,监控的方式类似于心跳,当然,管理员不能设定一个,一旦一个管理员宕机,也会出现问题,所以,哨兵至少三个,目的就像前面说的那样,防止哨兵过少导致一旦哨兵去世,系统会无法监控所有节点的状态。

7、Redis集群

继续递进,请问主从复制+哨兵的机制还有没有可以优化的地方,还有,没想到吧,我也没想到,

首先先表明一点,在高可用和自维护上,主从复制+哨兵机制,完全是可以满足需求的,那么为什么还要优化呢?

由于主从复制+哨兵机制的表现非常的优异,导致向redis中存储的数据也越来越多,所以问题来了,redis的主从复制+哨兵是可以完成高可用的,但是并不能解决数据量大的问题,为什么?

很简单,redis的主从复制有一个特点,想必大家也能发现,主从复制中,不管是主节点还是从节点,逻辑上存储的都是同一份数据,也就是三个redis服务器干了一个redis服务器的活,将读写分离,达到了高可用性的目的,所以,是不是问题就来了,主从做的再厉害,稳定性做的再好,那些主节点+从节点,说到底,也只是存储了相同的,一份数据。

那该如何完成数据量很大的情况呢?那就是集群。

集群是怎么实现的呢?

(1)集群的基本思路

多个主节点进行连接,并且保证每个主节点存储的值并不相同,比如存储一个key时,通过key计算一个hash值,该hash决定该放在哪个主节点中。这样,我们就将多个主节点的内存在逻辑意义上连接在了一起,类似于扩容,这样就能够解决数据量比较大的问题。

(2)集群的扩容

首先,某个集群中有几个主节点时,如果又有一个需要配置进来,该怎么做?

新的主节点去与该集群中的任意一个沟通,沟通方式类似于tcp的三次握手,用来确认该节点想要加入集群之中。

这样,我们的集群中就可以去加入新的主节点

(3)集群的分配策略

将总的空间分为了16384个块,称为槽位,会将所有的槽位给不同的主节点,根据它自身的硬件配置去分配,硬件配置高的就会多分一点,为了保证所有节点信息的一致性,会在集群启动时,各个节点会给其他人发送自己管理的槽位,这样为了保证,不会有一个槽位被多个管控,以及不会有一个槽位没人管理的情况,然后key的计算hash与槽位绑定,不会和某个节点绑定,这样即使集群中增加或者删除某一个节点,计算hash时也不会出错。

(4)小问题,多节点如何去同步自己管理的槽位

第一种解决方式,1代表自己管理,0代表自己不管理,这样实际上也就16384bit就能代表全量的信息,也就16384/8,也就是2000多字节,其实也算轻量级的数据了,但是有一点不方便啊,我要从每一个节点发出的16384位的信息中,去判断到底谁的第某一位是1,才能判断出某一个槽位是由哪个节点管理的,多少是有一点点不方便的。

第二种方式,空间换时间,直接定义一个16384长度的数组,数组中存储自己由谁管理,这时想要找某一个槽位由谁管理就是O(1)了

该说不说的,空间换时间,其实也还好,主打的,就是快。

(5)集群的主从复制及哨兵

说了这么多,集群里面有主从吗,显然有的啊,上层建筑从来都需要下层基础嘛,所以,我在上文中说的都是主节点,这意味着什么?主节点之后当然也有从节点去保证安全,防止哪天集群中的某个节点突然去世了,它有从节点能够直接顶上,防止整个集群一下子用不了。

这样,redis集群就既可以解决数据量多的问题,也可以去解决高可用性的问题(因为兼顾了主从复制的优点,所以高可用性肯定也有的),非常的nice。

以上就是我对reids的总结与理解,点点关注!点点赞,比心ღ( ´・ᴗ・` )比心

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值