Redis-05(主从复制,哨兵模式,缓存穿透和雪崩)

Redis主从复制

概念

主从复制,是指将一台Redis服务器的数据,复制到其他的Redis服务器.前者称为从节点(Slave/Follower),数据的复制是单向的,只能由从节点复制到主节点(主节点以写入为主,从节点只能读取)

作用

  1. 数据冗余:主从复制实现了数据的热备份,是持久化之外的一种数据冗余的方式
  2. 故障恢复:当前主节点故障的时候,从节点可以暂时提点主节点提供服务,是一种服务冗余的方式
  3. 负载均衡:在主从复制的基础上,配合读写分离,由主节点进行写的操作,从节点进行读的操作,分担服务器的负载,尤其是在多读少些的情况下,通过多个节点进行复杂,提高并发量
  4. 高可用基石:主从复制还是哨兵集群能够实施的基础

为什么使用集群

一般来说,要将Redis运用到工程中,只需要一个Redis是不可能的,原因如下

  1. 从结构上,单个容易发生故障,并且服务器需要处理所有的请求负载,压力较大
  2. 从容量上来说,单个Redis服务器内存有限,就算一台为256G也不能将所有的内存作用于Redis储存内存,一般来说,单台Redis最大内存不能超过20G
    电商平台的商品大部分都是一次上传,多次浏览,也就是多读少些.
    这种场景可以使用这种架构
    image
    主从复制,读写分里80%的情况下都是在进行读的操作,减缓服务器压力,架构中常常使用一主二从
    在公司中,主从复制就是必须要使用的,因为在真实的项目中不可能单机使用Redis

总结

  1. 单台的服务器难以负载大量的请求
  2. 单台服务器故障率高,系统崩坏率高
  3. 单台服务器内存容量有限

环境配置

  1. 复制三个redis.conf分别为redis6379.conf redis6380.conf redis6381.conf.配置相对应的
    1. 端口
    2. pid名字
    3. log文件名字
    4. dump.rdb名字
  2. 启动单机多服集群
    image
  3. 一主二从配置
    默认情况下,每台Redis都是主节点,我们一般配置从机就好(80,81)
    使用

slaveof 127.0.0.1 6379命令

使得80,81为从机
image

info replication 也能看到主机当前的信息

真实的情况下主从配置都应该在配置文件中写入,而不该在命令行中,命令行是暂时的,配置文件是永久的

使用规则

  1. 从机只能读,不能写,主机可读可写

127.0.0.1:6381> set name sakura               # 从机6381写入失败
(error) READONLY You can't write against a read only replica.
127.0.0.1:6380> set name sakura              # 从机6380写入失败

(error) READONLY You can't write against a read only replica.

127.0.0.1:6379> set name sakura
OK

127.0.0.1:6379> get name
"sakura"
  1. 当主机断电之后,默认情况下的从机角色不会转变,只会变成两个从机,集群失去了写入的操作,主机恢复的时候,又会连接上从机恢复原状
  2. 当从机断电宕机后,若不是使用配置文件配置的从机,再次启动后作为主机是无法获取之前主机的数据的,若此时重新配置称为从机,又可以获取到主机的所有数据。这里就要提到一个同步原理。
  3. 主机故障之后,不会出现新的主机,但是有两种情况可以产生新的主机
    1. 从机手动的执行命令slaveof on one,这样执行了之后就会变成主机
    2. 使用哨兵模式(自动选举)

复制原理

slave启动成功之后连接到master后会发送一个sync的同步命令
master接到命令之后,启动后台的存盘进程,同时收集所有接收到用于修改数据集命令,在后台进程执行完毕之后,master将传送整个数据文件到slave,完成一次增量复制

  • 全量复制:slave服务在接收数据库文件后,将其存盘并加载到内存中
  • 增量复制:master继续将新的所有收集到的修改命令依次传递给slave,完成同步
    只要重连master,一次完全同步将会被自动执行,数据一定可以在从机中看到

哨兵模式

作用:当master宕机的时候从从机中选出新的master.从redis2.8开始正式提供sentinel(哨兵)
能够监控后台的主机是否故障,如果故障,可以根据投票选出从库升为主库
image
向每台发送信息确定是否存活,类似于springcloud的心跳检测
单机哨兵哨兵也可能会宕机,所以现在都使用多哨兵模式
当哨兵模式检测到master宕机,会自动将slave切换成master,通过发布订阅模式通知其他的从服务器,修改配置文件,让他们切换主机
image

多哨兵模式

假设master宕机,sentinel先检测到这个结果,系统并不会马上进行failover(故障切换、失效备援)这个现象称为主观下线,当后面的哨兵也检测到主服务器不可用,sentinel之间会发起一次投票,投票的结果由随机一个sentinel发起,进行failover操作,得到sentinel票数多的slave能成功切换为master,切换成功后,通过发布订阅模式,让各个哨兵把自己监控的服务器实现切换主机,这个过程称为客观下线

  1. 实现:
    需要建立配置文件sentinel.conf
# sentinel monitor 被监控的名称 host port 1
sentinel monitor myredis 127.0.0.1 6379 1

2.启动哨兵
redis-sentinel sliconf/sentinel.conf
image
此时哨兵正在监视6379,我们断开master
image

哨兵模式的优缺点

优点:

  1. 哨兵集群,基于主从复制模式,所有主从复制的优点都有
  2. 主从可以切换,故障转移,系统的可用性好
  3. 哨兵模式是由主从模式的升级,手动到自动,更加健壮
    缺点:
  4. Redis不好在线扩容,集群容易达到上限,在线扩容就很麻烦
  5. 实现哨兵模式的配置很麻烦,其中有很多配置项

哨兵模式的全部配置

# Example sentinel.conf
哨兵sentinel实例运行的端口 默认26379
port 26379


哨兵sentinel的工作目录
dir /tmp



哨兵sentinel监控的redis主节点的ip port
master-name  可以自己命名的主节点名字 只能由字母A-z、数字0-9 、这三个字符".-_"组成。
quorum 当这些quorum个数sentinel哨兵认为master主节点失联 那么这时 客观上认为主节点失联了

sentinel monitor <master-name> <ip> <redis-port> <quorum>

sentinel monitor mymaster 127.0.0.1 6379 1



当在Redis实例中开启了requirepass foobared 授权密码 这样所有连接Redis实例的客户端都要提供密码,设置哨兵sentinel 连接主从的密码 注意必须为主从设置一样的验证密码

sentinel auth-pass <master-name> <password>

sentinel auth-pass mymaster MySUPER--secret-0123passw0rd



指定多少毫秒之后 主节点没有应答哨兵sentinel 此时 哨兵主观上认为主节点下线 默认30秒

sentinel down-after-milliseconds <master-name> <milliseconds>

sentinel down-after-milliseconds mymaster 30000



这个配置项指定了在发生failover主备切换时最多可以有多少个slave同时对新的master进行 同步,
这个数字越小,完成failover所需的时间就越长,
但是如果这个数字越大,就意味着越 多的slave因为replication而不可用。
可以通过将这个值设为 1 来保证每次只有一个slave 处于不能处理命令请求的状态。

sentinel parallel-syncs <master-name> <numslaves>

sentinel parallel-syncs mymaster 1


故障转移的超时时间 failover-timeout 可以用在以下这些方面:
1. 同一个sentinel对同一个master两次failover之间的间隔时间。
2. 当一个slave从一个错误的master那里同步数据开始计算时间。直到slave被纠正为向正确的master那里同步数据时。
3.当想要取消一个正在进行的failover所需要的时间。
4.当进行failover时,配置所有slaves指向新的master所需的最大时间。不过,即使过了这个超时,slaves依然会被正确配置为指向master,但是就不按parallel-syncs所配置的规则来了
默认三分钟

sentinel failover-timeout <master-name> <milliseconds>

sentinel failover-timeout mymaster 180000



SCRIPTS EXECUTION

配置当某一事件发生时所需要执行的脚本,可以通过脚本来通知管理员,例如当系统运行不正常时发邮件通知相关人员。
对于脚本的运行结果有以下规则:
若脚本执行后返回1,那么该脚本稍后将会被再次执行,重复次数目前默认为10
若脚本执行后返回2,或者比2更高的一个返回值,脚本将不会重复执行。
如果脚本在执行过程中由于收到系统中断信号被终止了,则同返回值为1时的行为相同。
一个脚本的最大执行时间为60s,如果超过这个时间,脚本将会被一个SIGKILL信号终止,之后重新执行。
通知型脚本:当sentinel有任何警告级别的事件发生时(比如说redis实例的主观失效和客观失效等等),将会去调用这个脚本,
这时这个脚本应该通过邮件,SMS等方式去通知系统管理员关于系统不正常运行的信息。调用该脚本时,将传给脚本两个参数,
一个是事件的类型,
一个是事件的描述。
如果sentinel.conf配置文件中配置了这个脚本路径,那么必须保证这个脚本存在于这个路径,并且是可执行的,否则sentinel无法正常启动成功。
通知脚本

sentinel notification-script <master-name> <script-path>

sentinel notification-script mymaster /var/redis/notify.sh


客户端重新配置主节点参数脚本
当一个master由于failover而发生改变时,这个脚本将会被调用,通知相关的客户端关于master地址已经发生改变的信息。
以下参数将会在调用脚本时传给脚本:
<master-name> <role> <state> <from-ip> <from-port> <to-ip> <to-port>


目前<state>总是“failover”,
<role>是“leader”或者“observer”中的一个。
参数 from-ip, from-port, to-ip, to-port是用来和旧的master和新的master(即旧的slave)通信的.这个脚本应该是通用的,能被多次调用,不是针对性的。

sentinel client-reconfig-script <master-name> <script-path>

sentinel client-reconfig-script mymaster /var/redis/reconfig.sh

缓存的穿透与雪崩

缓存穿透(查询不到)

  • 概念:
    在默认情况下,用户请求数据时,会先在缓存(Redis)中查找,若没找到即缓存未命中,再在数据库中进行查找,数量少可能问题不大,可是一旦大量的请求数据(例如秒杀场景)缓存都没有命中的话,就会全部转移到数据库上,造成数据库极大的压力,就有可能导致数据库崩溃。网络安全中也有人恶意使用这种手段进行攻击被称为洪水攻击。
  • 解决方案:
  1. 布隆过滤器
    image
  2. 缓存空对象
    image
    这样做有一个缺陷:存储空对象也需要空间,大量的空对象会耗费一定的空间,存储效率并不高。解决这个缺陷的方式就是设置较短过期时间

即使对空值设置了过期时间,还是会存在缓存层和存储层的数据会有一段时间窗口的不一致,这对于需要保持一致性的业务会有影响。

缓存击穿

  • 概念
    相较于缓存穿透,缓存击穿的目的性更强,一个存在的key,在缓存过期的一刻,同时有大量的请求,这些请求都会击穿到DB,造成瞬时DB请求量大、压力骤增。这就是缓存被击穿,只是针对其中某个key的缓存不可用而导致击穿,但是其他的key依然可以使用缓存响应。
    eg:比如热搜排行上,一个热点新闻被同时大量访问就可能导致缓存击穿。

  • 解决方案

  1. 设置热点数据永不过期
    这样就不会出现热点数据过期的情况,但是当Redis内存空间满的时候也会清理部分数据,而且此种方案会占用空间,一旦热点数据多了起来,就会占用部分空间

  2. 加互斥锁(分布式锁)
    在访问key之前,采用SETNX(set if not exists)来设置另一个短期key来锁住当前key的访问,访问结束再删除该短期key。保证同时刻只有一个线程访问。这样对锁的要求就十分高。

缓存雪崩

在某一个时间段,缓存集中过期失效,redis宕机
产生雪崩的原因之一,设置缓存的存活时间较短,大并发访问时刚好都过期,直接访问了数据库,对数据库而言,会产生周期性压力波峰,暴增时数据库可能会宕机
双十一时会停掉一些服务,保证主要的一些服务可用,springcloud中也有讲到过
image

  • 解决方案:
    --增加集群中服务器数量
    ----异地多活
    --限流降级
    ----缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量,对某个key只允许一个线程查询数据和写缓存,其他线程等待
    --数据预热
    ----正式部署之前,把可能的数据提前访问一遍,可能大量访问的数据就会加载到缓存中,加载不同的key,设置不同的过期时间,让缓存时间尽量均匀
posted @ 2021-10-12 15:22  1_f  阅读(43)  评论(0)    收藏  举报