Redis主从哨兵,SpringBoot整合应用

【1】主从

一、概念

主从复制,是指将一台Redis服务器的数据,复制到其他的Redis服务器。前者称为主节点(master/leader),后者称为从节点(slave/follower);数据的复制是单向的,只能由主节点到从节点。Master以写为主,Slave以读为主。
默认情况下,每台Redis服务器都是主节点(因为还没有配置主从);
且一个主节点可以有多个从节点(或没有从节点),但一个从节点只能有一个 主节点。
一般来说,单台Redis最大使用内存不应该超过20G。
电商网站上的商品,一般都是一次上传,无数次浏览的,也就是"多读少写"。
对于这种场景,我们可以使如下这种架构:
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210628114809891.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzQ4MzI0Ng==,size_16,color_FFFFFF,t_70

二、配置

机器规划:一台虚拟机开启三个redis,一主二从
默认情况下,每台redis服务器都是主节点,一般情况下,只配置从机就可以了。
一主(用79),二从(用80和81)

复制3个conf文件,然后修改对应的信息
1、端口
2、pid名字
3、log文件名字
4、dump.rdb名字

# 步骤:
# 在一台虚拟机上,克隆3个窗口,复制3份conf文件

[root@node1 redis-3.2.8-bin]# cd /export/server/redis-3.2.8-bin
[root@node1 redis-3.2.8-bin]# cp redis.conf redis79.conf 
[root@node1 redis-3.2.8-bin]# cp redis.conf redis80.conf   
[root@node1 redis-3.2.8-bin]# cp redis.conf redis81.conf  

命令:vim redis79.conf
# 第二个文件对应的改成6380和6381
port 6379 # 84行  端口这里不用改 本身这个文件就是79端口  
daemonize yes # 128行 后台运行 要yes
pidfile /var/run/redis_6379.pid # 150行 这里pid file 也没问题
logfile "/export/server/redis-3.2.8-bin/logs/redis6379.log" # 163行 logfile加上后缀6379
dbfilename dump6379.rdb # 236行 dump.rdb改成 dump6379.rdb 否则会重名
# 至此第一个就保存好了。

(1)主节点配置:主节点按照正常的配置配好即可。

(2)从节点配置
<2.1>想要让机器变成从节点,需要在从节点的 conf中 配置主从复制的相关参数。
在从节点的配置文件conf中指定主节点的信息(如果需要的话,可以配置主节点的登录密码,主从复制相关的参数)。二台从节点的配置是一样的。

# 配置主节点的ip和端口
slaveof 192.168.3.12 6379
# 从redis2.6开始,从节点默认是只读的
slave-read-only yes
# 假设主节点有登录密码,是root
masterauth root

<2.2>也可以不配置上面的文件,使用redis-server命令,在启动从节点时,通过参数 --slaveof 指定主节点是谁。
【系统运行时,如果master挂掉了,可以在一个从库(如slave1)上手动执行命令slaveof no one,将slave1变成新的master;在slave2上执行slaveof 192.168.3.13 6379 将这个机器的主节点指向的这个新的master;同时,挂掉的原master启动后作为新的slave也指向新的master上。

执行命令slaveof no one命令,可以关闭从服务器的复制功能。同时原来同步的所得的数据集都不会被丢弃。】

./redis-server --slaveof 192.168.3.12 6379

修改完毕之后,在一台虚拟机的三个窗口分别启动我们3个redis服务器,可以通过进程查看。

# 窗口1 
$ redis-server redis79.conf 
$ redis-cli -h node1 -p 6379

# 窗口2 
$ redis-server redis80.conf 
$ redis-cli -h node1 -p 6380

# 窗口3 
$ redis-server redis81.conf 
$ redis-cli -h node1 -p 6381

启动后可以用 info replication 命令查看自己的角色和主从节点的信息

注意:
主机可以写;从机不能写只能读。
主机中的所有信息和数据,都会自动被从机保存。
从机写会报错:​ (error) READONLY You can’t write against a read only slave.(你不能写,只能读,你仅仅只是一个从机)

三、主从复制的机制

在这里插入图片描述
复制原理:
1)SIave启动成功连接master后会发送一个sync命令;
2)Master接到命令,启动后台的存盘进程,同时收集所有接收到的用于修改数据集命令,在后台进程执行完毕之后,master将传送整个数据文件到slave,并完成一次完全同步。

  1. 全量复制:

slave服务在接收到数据库文件数据后,将其存盘并加载到内存中。

主机set k1 v1,从机断开,主机set k2 v2,从机重新连接主机,全量复制,从机还可以get k2。
  1. 增量复制:

Master继续将新的所有收集到的修改命令依次传给slave,完成同步

从机连接主机后,主机set k3 v3,从机可以get k3,这就是增量复制

只要是重新连接master,一次完全同步(全量复制)将被自动执行。主机操作的数据一定可以在从机中看到。
也就是:
主从刚刚连接的时候,进行全量同步;
全同步结束后,进行增量同步。
当然,如果有需要,slave在任何时候都可以发起全量同步。
Redis的策略是,无论如何,首先会尝试进行增量同步,如不成功,要求从机进行全量同步。

【2】哨兵

一、概念

缺点:主从模式下,当主服务器宕机后,需要 手动 把一台从服务器切换为主服务器,这就需要人工干预,还会造成一段时间内服务不可用。

哨兵模式: “自动” 谋朝篡位
这种模式下,master宕机,哨兵会自动选举master并将其他的slave指向新的master。

Redis提供了哨兵的命令,哨兵是一个独立的进程,作为进程,它会独立运行。其原理是哨兵通过发送命令,等待Redis服务器响应,从而监控运行的多个Redis实例。
在这里插入图片描述

二、哨兵模式文件

哨兵模式文件:redis-sentinel

redis的bin目录下,和redis-server类似
在这里插入图片描述
这里的哨兵有两个作用:
1)通过发送命令,让Redis服务器返回监控其运行状态,包括主服务器和从服务器。【监控主从服务器】
2)当哨兵监测到master宕机,会自动将slave切换成master,然后通过发布订阅模式通知其他的从服务器,修改配置文件,让它们切换主机。【帮从服务莫朝篡位】

三、多个哨兵

一个哨兵进程对Redis服务器进行监控,可能会出现问题。因为redis客户端连服务器通过TCP,网络不稳定造成误判。
为此,我们可以使用多个哨兵进行监控。各个哨兵之间还会进行监控,这样就形成了多哨兵模式。
一般是奇数个哨兵,少数服从多数。哨兵可以和redis机器部署在一起,也可以部署在其他的机器上。
在这里插入图片描述
假设,哨兵1先检测到主服务器宕机,系统并不会马上进行failover(故障转移),仅仅是哨兵1主观的认为主服务器不可用,这个现象称为主观下线。
当后面的哨兵也检测到主服务器不可用,并且数量达到一定值时,那么哨兵之间就会进行一次 投票 ,投票的结果由一个哨兵发起,进行failover故障转移操作。切换成功后,就会通过 发布订阅模式 ,让各个哨兵把自己监控的从服务器实现切换主机,这个过程称为客观下线。(ps:哨兵很像kafka集群中的zookeeper的功能)

四、哨兵的配置文件

<1>编辑配置文件

vim sentinel.conf

# 禁止保护模式
protected-mode no
# 配置监听的主服务器,这里sentinel monitor代表监控,mymaster代表服务器的名称,可以自定义,
#192.168.3.12代表监控的主服务器,6379代表端口,2代表只有两个或两个以上的哨兵认为主服务器不可用的时候,才会进行failover操作。
sentinel monitor mymaster 192.168.3.12 6379 2
# sentinel author-pass定义服务的密码,mymaster是服务名称,root是Redis服务器密码
sentinel auth-pass mymaster root

<2>启动哨兵

首先启动主节点,然后一台一台启动从节点。

redis集群启动完成后,分别启动哨兵集群所在机器的 三个哨兵 ,使用redis-sentinel /XXX/XXXX/sentinel.conf命令。

<3>测试主机崩了【这里有投票算法】

1.在6379主机,set k1 v1,然后shutdown exit退出
2.在6380 和 6381从机 分别:info replication ,发现目前依旧是:slave模式.
3.哨兵日志
1)+try-failover  发现故障,尝试连接
2)+failover  故障转移
3)+sdown slave 选举新的主节点完毕,例子里是6380

4.再次观察6380和6381,就会发现6380变成了master

现在选出了新的主机,就算把6379连回来,也不再是主机了。因为已经选出了6380作为新的主机。
这里有个有趣的点:
当6379主机刚连接回来的时候,info replication,这时候6379是master主机,观察哨兵日志,发现开始转换。然后再用info replication看6379,发现6379已经是slave了;info replication看6380,发现connected_slaves:从1变成了2,也就是说6379恢复连接后,被转换成了新的Master 6380的从机了。

【3】SpringBoot2.X整合哨兵主从服务

<1>pom依赖

在这里插入图片描述

<2>application.properties配置文件

spring.redis.host=192.168.3.12  
#这里设置虚拟机主节点,宕机后哨兵会把推举的新主机节点配置更新。
#不用担心写死后成从节点导致报错。
spring.redis.port=6379
spring.redis.password=root
# 连接池最大连接数(使用负值表示没有限制) 默认为8
spring.redis.lettuce.pool.max-active=8
# 连接池最大阻塞等待时间(使用负值表示没有限制) 默认为-1
spring.redis.lettuce.pool.max-wait=-1ms
# 连接池中的最大空闲连接 默认为8
spring.redis.lettuce.pool.max-idle=8
# 连接池中的最小空闲连接 默认为 0
spring.redis.lettuce.pool.min-idle=0

#哨兵的配置列表  
spring.redis.sentinel.master=mymaster
spring.redis.sentinel.nodes=192.168.3.12:26379
##哨兵集群
#spring.redis.sentinel.nodes=192.168.3.13:26379,192.168.3.14:26380

<3>Redis配置类

/**
 * redis 配置类
 */
@Configuration
public class RedisConfig {
 
    @Bean
    public <T> RedisTemplate<String, T> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, T> template = new RedisTemplate<>();
        template.setConnectionFactory(redisConnectionFactory);
        template.setKeySerializer(new StringRedisSerializer());
        template.setHashKeySerializer(new StringRedisSerializer());
 
        Jackson2JsonRedisSerializer jsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
 
        template.setHashValueSerializer(jsonRedisSerializer);
        template.setValueSerializer(jsonRedisSerializer);
        template.afterPropertiesSet();
        return template;
    }
}

<4>单元测试

package com.sze.redis;
 
import javax.annotation.PostConstruct;
 
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.junit4.SpringRunner;
 
@RunWith(SpringRunner.class)
@SpringBootTest
public class SentinelTest {
    
    @Autowired
    RedisTemplate redisTemplate;
    
    ValueOperations<String, String> stringRedis;
    
    @PostConstruct
    public void init(){
        redisString=redisTemplate.opsForValue();
    }
    
    
    @Test
    public void testString (){
        redisString.set("name", "花满楼");
        System.out.println(redisString.get("name"));
    }
}

【4】Redis缓存穿透(查不到)

1)概念:

用户想要査询一个数据,发现 redis内存数据库没有,缓存没有命中,于是向持久层数据库査询。发现也没有,于是本次査询失败。
当用户很多的时候,缓存都没有命中,都去请求了持久层数据库。这会给持久层数据库造成很大的压力,这时候就相当于出现了缓存穿透。

2)解决方案:

1、布隆过滤器:
布隆过滤器是一种数据结构,对所有可能査询的参数以hash形式存储,在控制层先进行校验,不符合则丟弃,从而避免了对底层存储系统的查询压力;布隆校验没有的一定没有,但校验有的不一定有。
在这里插入图片描述
1、缓存空对象:
当存储层不命中后,即使返回的空对象也将其缓存起来,同时会设置一个过期时间,之后再访问这个数据将会从缓存中获取,保护了后端数据源:
在这里插入图片描述

但是这种方法存在2个问题:
1、如果空值能够被缓存起来,这就意味着缓存需要更多的空间存储更多的键,因为这当中可能会有很多的空值的键;
2、即使对空值设置了过期时间,还是会存在缓存层和存储层的数据会有一段时间窗口的不一致,这对于需要保持一致性的业务会有影响。

【5】Redis缓存击穿(访问量太大,缓存过期)和雪崩(缓存集中过期)

一、缓存击穿:

1)概念:

击穿:
是指一个key非常热点,在不停的扛着大并发,大并发集中对这一个点进行访问,当这个key在失效的瞬间,持续的大并发就穿破缓存,直接请求数据库,就像在一个屏障上凿开了一个洞。

2)解决方案

1、设置热点数据永不过期
从缓存层面来看,没有设置过期时间,所以不会出现热点key过期后产生的问题。
2、加互斥锁
分布式锁:
使用分布式锁,保证对于每个key同时只有一个线程去査询后端服务,其他线程没有获得分布式锁的权限,因此只需要等待即可。这种方式将高并发的压力转移到了分布式锁,因此对分布式锁的考验很大。
在这里插入图片描述

二、缓存雪崩:

1)概念:

雪崩:是指在某一个时间段,缓存集中过期失效。或者Redis宕机(停电了)。

产生雪崩的场景:马上就要到双十二零点,很快就会迎来一波抢购,这一批商品时间比较 集中 的放入了缓存,假设缓存一个小时。那么到了凌晨一点钟的时候,这批商品的缓存就都过期了。而对这批商品的访问查询,都落到了数据库上,对于数据库而言,就会产生周期性的压力波峰。于是所有的请求都会达到存储层,存储层的调用量会暴増,造成存储层也会挂掉的情况。

2)解决方案

1)redis高可用

搭建集群

2)限流降级

在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个key只允许一个线程査询数据和写缓存,其他线程等待。

3)数据预热

在正式部署之前,先把可能的数据先预先访问,让部分可能大量访问的数据加载到缓存中。在即将发生大并发访问前手动触发加载缓存不同的key,设置不同的过期时间,让缓存失效的时间点尽量均匀。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值