1、概念

主机数据更新后根据配置和策略,自动同步到备机的master/slaver机制,Master以写为主,Slave以读为主

2、作用

  • 读写分离,性能扩展
  • 容灾快速恢复

image.png

3、主从复制

  1. 1、创建/myredis文件夹
  2. [root@localhost ~]# mkdir /myredis
  3. 2、拷贝redis.conf配置文件
  4. [root@localhost ~]# cp /etc/redis.conf /myredis
  5. 3、配置一主两从
  6. daemonize yes
  7. appendonly no

1、新建三个配置文件

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

redis6381.conf

include /myredis/redis.conf
pidfile /var/run/redis_6381.pid
port 6381
dbfilename dump6381.rdb

2、启动三台redis服务器

[root@localhost myredis]# redis-server redis6379.conf 
[root@localhost myredis]# redis-server redis6380.conf 
[root@localhost myredis]# redis-server redis6381.conf

3、查看系统进程,看看三台服务器是否启动

[root@localhost myredis]# ps -ef|grep redis
root       1592      1  1 22:06 ?        00:00:00 redis-server *:6379
root       1598      1  0 22:06 ?        00:00:00 redis-server *:6380
root       1604      1  1 22:06 ?        00:00:00 redis-server *:6381
root       1610   1537  0 22:07 pts/0    00:00:00 grep --color=auto redis

4、查看三台主机运行情况

info replication打印主从复制的相关信息

[root@localhost myredis]# redis-cli -p 6379
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:0
master_failover_state:no-failover
master_replid:4df64367911db7a415aaee69ee3badb92ab51596
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:0
second_repl_offset:-1
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0

目前都为主机

5、配从(库)不配主(库)

slaveof 成为某个实例的从服务器
1、在 6380 和 6381 上执行: slaveof 127.0.0.1 6379

[root@localhost ~]# redis-cli -p 6380
127.0.0.1:6380> slaveof 127.0.0.1 6379
OK
[root@localhost ~]# redis-cli -p 6381
127.0.0.1:6381> slaveof 127.0.0.1 6379
OK

[root@localhost myredis]# redis-cli -p 6379
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:2
slave0:ip=127.0.0.1,port=6380,state=online,offset=70,lag=1
slave1:ip=127.0.0.1,port=6381,state=online,offset=70,lag=1
master_failover_state:no-failover
master_replid:ebf6e7e8db9e923527f978e0698256e83c1e9844
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:70
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:70

此时已经可以看到配置成功了

2、在主机上写,在从机上可以读取数据,在从机上写数据报错

127.0.0.1:6379> set k1 v1
OK
127.0.0.1:6379> get k1
"v1"

127.0.0.1:6380> keys *
1) "k1"
127.0.0.1:6380> get k1
"v1"
127.0.0.1:6380> set k2 v2
(error) READONLY You can't write against a read only replica.

3、主机挂掉,重启就行,一切如初
4、从机重启需重设:slaveof 127.0.0.1 6379
可以将配置增加到文件中。永久生效。

4、三种方案

1、一主二仆

一台机器作为主服务器,其他两台服务器作为从服务器

主机挂掉

从机还是知道主机是谁,也知道主机已经挂掉,依旧可以进行读操作

127.0.0.1:6380> info replication
# Replication
role:slave
master_host:127.0.0.1
master_port:6379
master_link_status:down
127.0.0.1:6380> keys *
1) "k1"
127.0.0.1:6380> get k1
"v1"

主机挂掉重启

依旧是主机,知道从机在哪里

[root@localhost myredis]# redis-server redis6379.conf 
[root@localhost myredis]# redis-cli -p 6379
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:2
slave0:ip=127.0.0.1,port=6381,state=online,offset=0,lag=0
slave1:ip=127.0.0.1,port=6380,state=online,offset=0,lag=1

从机挂掉

从原主机的从机下直接删除掉。

127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:1
slave0:ip=127.0.0.1,port=6381,state=online,offset=112,lag=1

从机挂掉重启

自己直接变成主机,与之前完全独立

[root@localhost ~]# redis-server /myredis/redis6380.conf 
[root@localhost ~]# redis-cli -p 6380
127.0.0.1:6380> info replication
# Replication
role:master
connected_slaves:0

通过 slaveof ip port 重新加入,此时会将原有的数据都会复制回来

127.0.0.1:6380> slaveof 127.0.0.1 6379
OK
127.0.0.1:6380> keys *
1) "k1"

127.0.0.1:6380> info replication
# Replication
role:slave
master_host:127.0.0.1
master_port:6379
master_link_status:up

2、薪火相传

上一个 slave 可以是下一个 slave 的 master,slave 同样可以接收其他 slaves 的连接和同步请求,那么该 slave 作为了链条中下一个的 master, 可以有效减轻 master 的写压力,去中心化降低风险。

6379作为6380的主机
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:1
slave0:ip=127.0.0.1,port=6380,state=online,offset=42,lag=1

6380作为6381的主机,6379的从机
127.0.0.1:6380> slaveof 127.0.0.1 6379
OK
127.0.0.1:6380> info replication
# Replication
role:slave
master_host:127.0.0.1
master_port:6379
master_link_status:up
master_last_io_seconds_ago:2
master_sync_in_progress:0
slave_repl_offset:56
slave_priority:100
slave_read_only:1
connected_slaves:1
slave0:ip=127.0.0.1,port=6381,state=online,offset=56,lag=1

6381作为6380的从机
127.0.0.1:6381> slaveof 127.0.0.1 6380
OK
127.0.0.1:6381> info replication
# Replication
role:slave
master_host:127.0.0.1
master_port:6380
master_link_status:up

挂掉的情况同一主二仆

不同:

  • 一旦某个slave宕机,后面的slave都没法备份
  • 主机挂了,从机还是从机,无法写数据了
  • 中途变更转向:会清除之前的数据,重新建立拷贝最新的

    3、反客为主

    当一个 master 宕机后,后面的 slave 可以立刻升为 master,其后面的 slave 不用做任何修改。
    slaveof no one 将从机变为主机。 ```shell 6379主机挂掉 127.0.0.1:6379> shutdown not connected>

//从机检测到主机挂掉,从机执行命令后成为主机 127.0.0.1:6380> info replication

Replication

role:slave master_host:127.0.0.1 master_port:6379 master_link_status:down connected_slaves:1 slave0:ip=127.0.0.1,port=6381,state=online,offset=952,lag=0 127.0.0.1:6380> slaveof no one OK 127.0.0.1:6380> info replication

Replication

role:master connected_slaves:1 slave0:ip=127.0.0.1,port=6381,state=online,offset=952,lag=0

<a name="RQwmE"></a>
# 5、复制原理

- slave 启动成功连接到 master 后会发送一个 sync 命令要求进行数据同步
- master接到命令启动后台的存盘进程,同时收集所有接收到的用于修改数据集命令,在后台进程执行完毕之后产生 rdb 文件,master 将传送整个数据文件到 slave,slave 拿到 rdb 进行读取
- 每次主服务器进行写操作后,都会和从服务器进行同步
- 全量复制:slave 服务在接收到数据库文件数据后,将其存盘并加载到内存中。
- 增量复制:master 新的所有收集到的修改命令依次传给 slave,完成同步
- 但是只要是重新连接 master,一次完全同步(全量复制)将被自动执行

![image.png](https://cdn.nlark.com/yuque/0/2021/png/21583664/1621218107089-93d0ece3-af3e-40b3-8b35-7babedff196f.png#align=left&display=inline&height=157&id=qIayZ&margin=%5Bobject%20Object%5D&name=image.png&originHeight=157&originWidth=397&size=50442&status=done&style=none&width=397)


<a name="XhrJ2"></a>
# 6、哨兵模式(sentinel)
**反客为主的自动版**,能够后台监控主机是否故障,如果故障了根据投票数自动将从库转换为主库
<a name="noAll"></a>
## 1、使用步骤
1、调整为一主二仆模式,6379带着6380、6381
```shell
[root@localhost myredis]# redis-server redis6379.conf 
[root@localhost myredis]# redis-cli -p 6379
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:2
slave0:ip=127.0.0.1,port=6380,state=online,offset=28,lag=1
slave1:ip=127.0.0.1,port=6381,state=online,offset=28,lag=1

2、自定义的/myredis目录下新建 sentinel.conf 文件(名字绝不能错)

[root@localhost myredis]# vim sentinel.conf

3、配置哨兵,填写内容

sentinel monitor mymaster 127.0.0.1 6379 1

其中 mymaster 为监控对象起的服务器名称,1 为至少有多少个哨兵同意迁移的数量。
4、启动哨兵
执行redis-sentinel/myredis/sentinel.conf

[root@localhost myredis]# redis-sentinel sentinel.conf 
1751:X 17 May 2021 07:38:36.032 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
1751:X 17 May 2021 07:38:36.032 # Redis version=6.2.1, bits=64, commit=00000000, modified=0, pid=1751, just started
1751:X 17 May 2021 07:38:36.032 # Configuration loaded
1751:X 17 May 2021 07:38:36.033 * Increased maximum number of open files to 10032 (it was originally set to 1024).
1751:X 17 May 2021 07:38:36.033 * monotonic clock: POSIX clock_gettime
                _._                                                  
           _.-``__ ''-._                                             
      _.-``    `.  `_.  ''-._           Redis 6.2.1 (00000000/0) 64 bit
  .-`` .-```.  ```\/    _.,_ ''-._                                   
 (    '      ,       .-`  | `,    )     Running in sentinel mode
 |`-._`-...-` __...-.``-._|'` _.-'|     Port: 26379
 |    `-._   `._    /     _.-'    |     PID: 1751
  `-._    `-._  `-./  _.-'    _.-'                                   
 |`-._`-._    `-.__.-'    _.-'_.-'|                                  
 |    `-._`-._        _.-'_.-'    |           http://redis.io        
  `-._    `-._`-.__.-'_.-'    _.-'                                   
 |`-._`-._    `-.__.-'    _.-'_.-'|                                  
 |    `-._`-._        _.-'_.-'    |                                  
  `-._    `-._`-.__.-'_.-'    _.-'                                   
      `-._    `-.__.-'    _.-'                                       
          `-._        _.-'                                           
              `-.__.-'                                               

1751:X 17 May 2021 07:38:36.033 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
1751:X 17 May 2021 07:38:36.036 # Sentinel ID is 4a6c62e33158b068db7a6295e37409308203fc55
1751:X 17 May 2021 07:38:36.036 # +monitor master mymaster 127.0.0.1 6379 quorum 1
1751:X 17 May 2021 07:38:36.036 * +slave slave 127.0.0.1:6380 127.0.0.1 6380 @ mymaster 127.0.0.1 6379
1751:X 17 May 2021 07:38:36.038 * +slave slave 127.0.0.1:6381 127.0.0.1 6381 @ mymaster 127.0.0.1 6379

5、当主机挂掉,从机选举中产生新的主机

1751:X 17 May 2021 07:41:23.636 # +sdown master mymaster 127.0.0.1 6379
1751:X 17 May 2021 07:41:23.636 # +odown master mymaster 127.0.0.1 6379 #quorum 1/1
1751:X 17 May 2021 07:41:23.636 # +new-epoch 1
1751:X 17 May 2021 07:41:23.636 # +try-failover master mymaster 127.0.0.1 6379
1751:X 17 May 2021 07:41:23.640 # +vote-for-leader 4a6c62e33158b068db7a6295e37409308203fc55 1
1751:X 17 May 2021 07:41:23.640 # +elected-leader master mymaster 127.0.0.1 6379
1751:X 17 May 2021 07:41:23.640 # +failover-state-select-slave master mymaster 127.0.0.1 6379
1751:X 17 May 2021 07:41:23.711 # +selected-slave slave 127.0.0.1:6381 127.0.0.1 6381 @ mymaster 127.0.0.1 6379
1751:X 17 May 2021 07:41:23.711 * +failover-state-send-slaveof-noone slave 127.0.0.1:6381 127.0.0.1 6381 @ mymaster 127.0.0.1 6379
1751:X 17 May 2021 07:41:23.794 * +failover-state-wait-promotion slave 127.0.0.1:6381 127.0.0.1 6381 @ mymaster 127.0.0.1 6379
1751:X 17 May 2021 07:41:24.653 # +promoted-slave slave 127.0.0.1:6381 127.0.0.1 6381 @ mymaster 127.0.0.1 6379
1751:X 17 May 2021 07:41:24.653 # +failover-state-reconf-slaves master mymaster 127.0.0.1 6379
1751:X 17 May 2021 07:41:24.728 * +slave-reconf-sent slave 127.0.0.1:6380 127.0.0.1 6380 @ mymaster 127.0.0.1 6379
1751:X 17 May 2021 07:41:25.735 * +slave-reconf-inprog slave 127.0.0.1:6380 127.0.0.1 6380 @ mymaster 127.0.0.1 6379
1751:X 17 May 2021 07:41:25.735 * +slave-reconf-done slave 127.0.0.1:6380 127.0.0.1 6380 @ mymaster 127.0.0.1 6379
1751:X 17 May 2021 07:41:25.806 # +failover-end master mymaster 127.0.0.1 6379
1751:X 17 May 2021 07:41:25.806 # +switch-master mymaster 127.0.0.1 6379 127.0.0.1 6381
1751:X 17 May 2021 07:41:25.806 * +slave slave 127.0.0.1:6380 127.0.0.1 6380 @ mymaster 127.0.0.1 6381
1751:X 17 May 2021 07:41:25.806 * +slave slave 127.0.0.1:6379 127.0.0.1 6379 @ mymaster 127.0.0.1 6381

6381成为了主机

127.0.0.1:6381> info replication
# Replication
role:master
connected_slaves:1
slave0:ip=127.0.0.1,port=6380,state=online,offset=13668,lag=1

当6379重启时,成为了从机

127.0.0.1:6379> info replication
# Replication
role:slave
master_host:127.0.0.1
master_port:6381
master_link_status:up

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

2、故障恢复

M]2Y9UTV0C_9SJI~@}QO~60.png
优先级在redis.conf中默认:replica-priority 100,值越小优先级越高
偏移量是指获得原主机数据最全的
每个redis实例启动后都会随机生成一个40位的runid

3、主从复制

private static JedisSentinelPool jedisSentinelPool=null;

public static  Jedis getJedisFromSentinel(){
    if(jedisSentinelPool==null){
        Set<String> sentinelSet=new HashSet<>();
        sentinelSet.add("192.168.11.103: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();
    }
}