您的当前位置:首页正文

Redis主从复制 | 演示搭建 | 踩坑分享

2024-11-09 来源:个人技术集锦


一. 前言

1. 主从复制是什么?

主从复制:顾名思义将主机的数据复制到另一台从机(或者说备用机中),那么这就叫主从复制了,开个玩笑,当然没有这么简单。
Redis中的主从复制是指主机数据更新后根据配置和策略, 自动同步到备机的master/slaver机制,Master以写为主Slave以读为主,下面小编画了一张图希望有助于各位读者朋友的理解。
可以看到服务将数据写入到主机(Master)中,而主机接收到数据后就会立刻同步到其他的从机(Slave)中,当应用需要读取数据时,就从同步主机数据的丛机中读取,实现了读写分离主从复制

2. 有什么作用?

那么这时就有人要问了这样的设计有什么用呢? 既然你诚心诚意的问了,我就大发慈悲地告诉你:

1. 读写分离

这种集群的设计方式,实现了数据的读写分离,假设服务的读写都在一台Redis主机上完成,无疑对于单台主机来说线性压力有点大了。采用主从复制之后,将“读”的操作分摊出去,这大大降低了单台主机压力,提高了系统的健壮性。

2. 服务高可用

这种集群的设计也带来另一个特性,那就是“高可用” ,按照之前单主机的架构设计方式,假如主机宕掉了那么缓存服务就彻底瘫痪了。新增从节点后,即使挂掉一个从节点也可以快速切换去读取另一个从节点的数据,即使主节点挂掉了,后文我们要聊到的“哨兵模式”也可解决这个问题,大大提高了系统的可用性。

3. 服务扩展

一些特殊的业务场景比如双11等,这种吞吐量需求极大的业务场景,而我们平常用不到这么大的吞吐量,到这个特殊的时间段我们需要对缓存服务进行快速扩容,这种架构的设计方式就不必向传统去改动负载均衡服务器,而是可以直接加入新的从节点,实现动态扩容

3. 小总结

总的来说这种集群的设计架构,提高服务器的读写负载能力,减轻线性操作对单台主机的压力。和数据的热备份,以及系统服务的容灾快速恢复,同时也很好的展现了集群的高可用性,是一种很不错的集群节点架构。

3. 缺点

由于所有的写操作都是先在Master上操作,然后同步更新到Slave上,所以从Master同步到Slave机器有一定的延迟,当系统很繁忙的时候,延迟问题会更加严重,Slave机器数量的增加也会使这个问题更加严重。

二. 搭建一主多从

介绍完Redis的主从复制,那么接下来就是实操演示了,小编将以案例的方式演示搭建一个一主多从的Redis集群,考虑到读者朋友们可能都是新手,这里小编就不太复杂化了,就搭建一个一主两从的吧。

1. 环境准备

小编是准备在同一台主机上启动多个Redis服务来进行配置,为了演示方便首先使用以下命令创建一个文件夹来存放我们接下来的配置信息。

// 创建文件夹
mkdir /myredis
// 进入文件夹
cd /myredis
cp /usr/src/redis-6.2.6/redis.conf /myredis

编辑这个配置文件做出下面的操作

appendonly no // appendonly修改为no 默认就是no

创建三个配置文件 redis6379.confredis6380.confredis6381.conf

touch redis6379.conf
touch redis6380.conf
touch redis6381.conf

往里面添加内容,三个文件的内容分别如下 不要把注释也复制进去了。
include /myredis/redis.conf是引入配置文件的公共部分。

// redis6379.conf 内容如下 
include /myredis/redis.conf
pidfile /var/run/redis_6379.pid
port 6379
dbfilename dump6379.rdb

// redis6380.conf 内容如下
include /myredis/redis.conf
pidfile /var/run/redis_6380.pid
port 6380
dbfilename dump6380.rdb
masterauth 331213 // Redis主机密码下面避坑 连接授权需要


// redis6381.conf 内容如下
include /myredis/redis.conf
pidfile /var/run/redis_6381.pid
port 6381
dbfilename dump6381.rdb
masterauth 331213 // Redis主机密码下面避坑 连接授权需要

2. 启动服务

修改保存退出后,使用下面的三条命令分别启动三个Redis服务

redis-server /myredis/redis6379.conf
redis-server /myredis/redis6380.conf
redis-server /myredis/redis6381.conf

可以通过下面的命令查看启动的状态

ps -ef | grep redis

redis-cli -p 6379
redis-cli -p 6380
redis-cli -p 6381

使用以下命令可以查看到当前Redis服务主从的详细信息

info replication

注意:如果执行遇到NOAUTH Authentication required. 则要进行权限认证执行以下命令即可

auth 331213 // 当前服务Redis密码

  • role:master 当前主机角色
  • connected_slaves:0 当前主机丛机器数量

没有做任何配置,三个服务一启动全是主机

3. 搭建主从复制

执行以下命令指定主机让当前服务机成为其从机

slaveof [主机ip] [主机端口]

在占用6380端口和6381端口的服务上分别执行下面这条命令成为6379主机的从机

slaveof 127.0.0.1 6379

注意:如果出现NOAUTH Authentication required. 则要进行权限认证执行以下命令即可

auth 331213 // Redis密码

info replication

注意: 这时如果主机信息显示connected_slaves:0 就是连接失败了,可能是 配置文件bind 127.0.0.1
需要改为 bind 0.0.0.0 如果还是不行,打开从机的配置文件加入 masterauth 主机Redis密码 。
再杀死两个从机进程,再重启从机重新设置主从复制

ps -ef|grep redis // 查看Redis进程
kill -9 [pid] // 杀死两个从机进程

可以看到connected_slaves:2 有两台从机 下面是从机的详细信息 state=online 是从机在线状态

三. 常用三招

1. 场景演示

基于我们上面搭建好的一主二从场景来演示两个场景:
场景一:比如现在我们的某台从服务器挂掉了可以在Redis客户端执行以下命令停止当前的Redis服务

shutdown

redis-server /myredis/redis6380.conf
redis-cli -p 6380
slaveof 127.0.0.1 6379

这时就会发现从机会同步主机中新添加的数据,注意:是从连接主机器就将主机中的数据从头到尾数据复制了一遍。
场景二:在主服务器的Redis客户端执行以下命令将主服务器弄挂掉

shutdown

redis-server /myredis/redis6379.conf
redis-cli -p 6380
info replication

可以看到启动的主机保持着主机状态并且一起来就有两个从机。

复制原理:当从服务器连接上主服务器后,从服务器会向主服务器发送数据同步的消息,主服务器接收到从服务器发送过来同步数据的消息后,会把主服务器的数据进行持久化RDB,然后会将持久化文件发送给从服务器,从服务器拿到持久化文件再进行读取起到一个复制的作用(这个是从服务器主动)。
每次主服务器进行写操作后,都会和从服务器进行数据的同步(这个是主服务器主动)
全量复制:slave服务在接收到数据库文件数据后,将其存盘并加载到内存中。
增量复制:Master继续将新的所有收集到的修改命令依次传给slave,完成同步

2. 薪火相传

这是一种常用的做法,上一个Slave可以是下一个slave的Master,Slave同样可以接收其他 slaves的连接和同步请求,那么该slave作为了链条中下一个的master, 可以有效减轻master的写压力,去中心化降低风险。
就像是套娃一样。

配置这种主从模式,还是使用上面那种主从连接命令。
执行以下命令指定主机让当前服务机成为其从机

slaveof [主机ip] [主机端口]

但是这种方式也存在缺点,风险是一旦某个slave宕机,后面的slave都没法备份,主机挂了,从机还是从机,无法写数据了。

3. 反客为主

当一个master宕机后,后面的slave可以立刻升为master,其后面的slave不用做任何修改。使用以下命令可以实现这个效果

slaveof  no one  // 将从机变为主机

比如此时占用6379端口的主机挂掉了,这时我们在占用6380的从机上执行上面这条命令,那么6380的从机就变成了主机状态,且占用6381的从机也会成为6380主机的从机。
但是这种方式的缺点就是需要手动来完成,但是我们接下来要讲解的哨兵模式可以完美的解决这个问题。

四. 哨兵模式

反客为主的自动版,能够后台监控主机是否故障,如果故障了根据投票数自动将从库转换为主库。

1. 搭建哨兵模式

以上面介绍的一主二从的场景来演示
首先我们在上面创建的配置文件夹中创建 sentinel.conf 文件 (文件名是固定的) 可以执行以下命令创建

touch /myredis/sentinel.conf

将以下内容添加进刚创建好的 sentinel.conf 文件
其中mymaster为监控对象起的服务器名称, 1 为至少有多少个哨兵同意迁移的数量。
sentinel auth-pass mymaster 指定主机密码

sentinel monitor mymaster 127.0.0.1 6379 1
sentinel auth-pass mymaster 331213

2. 启动哨兵

配置好上面的配置文件后执行以下命令启动哨兵模式

redis-sentinel  /myredis/sentinel.conf

可以看到哨兵的默认端口为 26379

可以看到下面有一些主从复制的基本信息,监控的是哪台主机,有哪些从机等信息

3. 场景

假如此时占用6379端口的主机挂掉,可以执行以下命令停止主机。

shutdown


这时哨兵就会监听到主机挂掉的信息,会开始选举主机的两个从机成为主机,这时查看哨兵的会话窗口就可以发现已经选举完成。
选举了占用6380端口的从服务器为主机。

这时在6380端口执行以下命令则可以看到6380端口的服务已经成为主机了且有一台从机6381

info replication


假如此时再次启动6379服务器,这时会发现6379一启动就会变成6380的从服务器,这就是自动版的反客为主“哨兵模式”。

4. 选举规则

选举条件为:

  • 选择优先级靠前的
  • 选择偏移量最大的
  • 选择runid最小的

选择优先级靠前的:在从机的 redis.conf 配置文件可以设置一个 slave-priority [数值] 数值就是优先级,默认不设置这个配置的话就是100,数值越小优先级越高。
选择偏移量最大的:偏移量是指获得原主机数据最全的
选择runid最小的:每个redis实例启动后都会随机生成一个40位的runid

5. java代码连接

如何用java连接Redis并识别哪个是主哪个是从呢?其实只要在连接池上面做手脚就可以了。

private static JedisSentinelPool jedisSentinelPool=null;

public static  Jedis getJedisFromSentinel(){
if(jedisSentinelPool==null){
            Set<String> sentinelSet=new HashSet<>();
            sentinelSet.add("192.168.11.103:26379"); // 26379 是哨兵的端口

            JedisPoolConfig jedisPoolConfig =new JedisPoolConfig();
            jedisPoolConfig.setMaxTotal(10); //最大可用连接数
jedisPoolConfig.setMaxIdle(5); //最大闲置连接数
jedisPoolConfig.setMinIdle(5); //最小闲置连接数
jedisPoolConfig.setBlockWhenExhausted(true); //连接耗尽是否等待
jedisPoolConfig.setMaxWaitMillis(2000); //等待时间
jedisPoolConfig.setTestOnBorrow(true); //取连接的时候进行一下测试 ping pong
//                                       服务名
jedisSentinelPool=new JedisSentinelPool("mymaster",sentinelSet,jedisPoolConfig);
return jedisSentinelPool.getResource();
        }else{
return jedisSentinelPool.getResource();
        }
}
显示全文