zoukankan      html  css  js  c++  java
  • Redis主从复制

    主从复制

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

    用处

    读写分离,性能扩展

    容灾快速恢复

    示意图:

    配置Redis

    1、拷贝多个redis.conf文件include,因为redis.conf可以配置共有的配置。如果有不同,include后,可以自行配置,会覆盖redis.conf中的配置。

     

     首先在主目录下,新建master-slave文件夹(其实就是随便建个目录放文件),里面添加不同端口的配置文件,起3个服务,形成三个redis节点。

     同时include共有的配置:

    然后,共有的配置到redis.conf中修改,不同的配置在单独的配置文件中修改。

    2、开启daemonize yes

    使用的是一台机器启动多个服务的方法,所以需要配置后台启动。

    在redis.conf中:

    # By default Redis does not run as a daemon. Use 'yes' if you need it.
    # Note that Redis will write a pid file in /var/run/redis.pid when daemonized.
    daemonize yes

    3、Pid文件名字pidfile

    这个在redis.conf中找到,各自配置下,如果是单独的机器,这个不用配置:

    pidfile /var/run/redis_6379.pid

    4、指定端口

    port 6379

    5、Log文件名字

    logfile /usr/local/src/bchen/redis-5.0.8/master-slave/file_6379.log

    6、Dump.rdb名字dbfilename,涉及到一个文件名称和一个路径名称

    dbfilename dump_6379.rdb
    dir /usr/local/src/bchen/redis-5.0.8/master-slave

    7、Appendonly 关掉或者换名字

    这个是aof持久化相关的,我们可以不用配置,直接关了就好,有开rdb就可以了。直接在共有的redis.conf中配置。

    appendonly no

    其实默认就是no。

    8、其他实例也配置下,最终配置文件长这样:

    6379:

    include /usr/local/src/bchen/redis-5.0.8/redis.conf
    pidfile /var/run/redis_6379.pid
    port 6379
    logfile /usr/local/src/bchen/redis-5.0.8/master-slave/file_6379.log
    dbfilename dump_6379.rdb
    dir /usr/local/src/bchen/redis-5.0.8/master-slave

    6380:

    include /usr/local/src/bchen/redis-5.0.8/redis.conf
    pidfile /var/run/redis_6379.pid
    port 6379
    logfile /usr/local/src/bchen/redis-5.0.8/master-slave/file_6379.log
    dbfilename dump_6380.rdb
    dir /usr/local/src/bchen/redis-5.0.8/master-slave

    6381:

    include /usr/local/src/bchen/redis-5.0.8/redis.conf
    pidfile /var/run/redis_6379.pid
    port 6379
    logfile /usr/local/src/bchen/redis-5.0.8/master-slave/file_6379.log
    dbfilename dump_6381.rdb
    dir /usr/local/src/bchen/redis-5.0.8/master-slave

    启动

    启动命令

    查看进程:

     三个pid文件:

     日志文件:

    搭建简单的一主二仆模式

    这三个实例其实现在是互不关联的,需要额外的操作使之互相起作用。

     先熟悉两个重要的命令:

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

    slaveof  <ip>  <port> : 成为某个实例的从服务器,相当于现在的小弟找大哥。

    先三台机器各自执行下,info replication命令:

     

     

     可以看到初始角色全部都是master。

     接下来把6380和6381配置slave。

    192.168.71.131:6381> slaveof 192.168.71.131 6379
    OK
    192.168.71.131:6380> slaveof 192.168.71.131 6379
    OK

    查看下主从关系:

    192.168.71.131:6379> info replication
    # Replication
    role:master
    connected_slaves:2
    slave0:ip=192.168.71.131,port=6381,state=online,offset=392,lag=0
    slave1:ip=192.168.71.131,port=6380,state=online,offset=392,lag=0
    master_replid:119b5221a7a59fa0bae8b405aa9bc09074ee0c11
    master_replid2:0000000000000000000000000000000000000000
    master_repl_offset:392
    second_repl_offset:-1
    repl_backlog_active:1
    repl_backlog_size:1048576
    repl_backlog_first_byte_offset:1
    repl_backlog_histlen:392
    192.168.71.131:6380> info replication
    # Replication
    role:slave
    master_host:192.168.71.131
    master_port:6379
    master_link_status:up
    master_last_io_seconds_ago:4
    master_sync_in_progress:0
    slave_repl_offset:378
    slave_priority:100
    slave_read_only:1
    connected_slaves:0
    master_replid:119b5221a7a59fa0bae8b405aa9bc09074ee0c11
    master_replid2:0000000000000000000000000000000000000000
    master_repl_offset:378
    second_repl_offset:-1
    repl_backlog_active:1
    repl_backlog_size:1048576
    repl_backlog_first_byte_offset:323
    repl_backlog_histlen:56
    192.168.71.131:6381> info replication
    # Replication
    role:slave
    master_host:192.168.71.131
    master_port:6379
    master_link_status:up
    master_last_io_seconds_ago:9
    master_sync_in_progress:0
    slave_repl_offset:392
    slave_priority:100
    slave_read_only:1
    connected_slaves:0
    master_replid:119b5221a7a59fa0bae8b405aa9bc09074ee0c11
    master_replid2:0000000000000000000000000000000000000000
    master_repl_offset:392
    second_repl_offset:-1
    repl_backlog_active:1
    repl_backlog_size:1048576
    repl_backlog_first_byte_offset:1
    repl_backlog_histlen:392

    可以看到6379已经变成了master, 6380和6381为slave。

    测试主从复制

    尝试从slave(6380)写入:

    192.168.71.131:6380> select 0
    OK
    192.168.71.131:6380> keys *
    (empty list or set)
    192.168.71.131:6380> set k1 v1
    (error) READONLY You can't write against a read only replica.

    报错!

    尝试从master写入:

    192.168.71.131:6379> 
    192.168.71.131:6379> SELECT 0
    OK
    192.168.71.131:6379> keys *
    (empty list or set)
    192.168.71.131:6379> set k1 v1
    OK
    192.168.71.131:6379> get k1
    "v1"

    可以看到master可以写入也可以读取。

    再从slave中读取数据:

    192.168.71.131:6380> get  k1
    "v1"

    6380中可以读取到,同样的6381中也可以读取到。

    问题刨析

    1、从机是否可以写?set可否?

    以上已经测试过了,可以看出从机不能写,只能读。

    2、切入点问题。slave第一次加入进来,是从头开始复制还是从切入点开始复制。

    先把6380(或者6381)关闭掉,然后启动,删除所有数据,然后重新接入到6379成为slave,看下6380能否有之前的数据。

     可以看到没有6380这个进程,然后看下6379的主从关系。

    [root@localhost src]# ./redis-cli -h 192.168.71.131 -p 6379
    192.168.71.131:6379> info replication
    # Replication
    role:master
    connected_slaves:1
    slave0:ip=192.168.71.131,port=6381,state=online,offset=12652,lag=1
    master_replid:119b5221a7a59fa0bae8b405aa9bc09074ee0c11
    master_replid2:0000000000000000000000000000000000000000
    master_repl_offset:12652
    second_repl_offset:-1
    repl_backlog_active:1
    repl_backlog_size:1048576
    repl_backlog_first_byte_offset:1
    repl_backlog_histlen:12652

    这时候没有了6380这个slave。

    启动6380

    [root@localhost src]# ./redis-server ../master-slave/redis6380.conf 
    [root@localhost src]# ps -ef | grep redis
    root      86740      1  0 03:26 ?        00:00:12 ./redis-server 192.168.71.131:6379
    root      86750      1  0 03:26 ?        00:00:11 ./redis-server 192.168.71.131:6381
    root      86941  86919  0 07:33 pts/0    00:00:00 ./redis-cli -h 192.168.71.131 -p 6379
    root      86967      1  0 07:36 ?        00:00:00 ./redis-server 192.168.71.131:6380
    root      86972  86946  0 07:36 pts/2    00:00:00 grep --color=auto redis

    再次查看6379:

    192.168.71.131:6379> info replication
    # Replication
    role:master
    connected_slaves:1
    slave0:ip=192.168.71.131,port=6381,state=online,offset=13002,lag=1
    master_replid:119b5221a7a59fa0bae8b405aa9bc09074ee0c11
    master_replid2:0000000000000000000000000000000000000000
    master_repl_offset:13002
    second_repl_offset:-1
    repl_backlog_active:1
    repl_backlog_size:1048576
    repl_backlog_first_byte_offset:1
    repl_backlog_histlen:13002

    可以看出,slave不会保存上次的记忆,不会自动成为79的从机。

    这时候,我们把6380的数据全部清空。

    [root@localhost src]# ./redis-cli -h 192.168.71.131 -p 6380
    192.168.71.131:6380> keys *
    1) "k1"
    192.168.71.131:6380> FLUSHALL
    OK
    192.168.71.131:6380> keys *
    (empty list or set)

    然后再让它成为6379的从机:

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

    发现6380已经把全部数据同步过来了。并从新成为6379的slave。

    当一个全新的节点成为某个master的slave的时候,他会从master那边同步一份最全的数据过来,而并不是从切入点开始复制。

    3、其中一台从机运行了一段时间,然后down后情况如何?再次接入后,是怎么样的?

     shutdown 8081

    192.168.71.131:6381> shutdown
    not connected> 

    查看6379(要稍微等一会)

    192.168.71.131:6379> info replication
    # Replication
    role:master
    connected_slaves:1
    slave0:ip=192.168.71.131,port=6380,state=online,offset=25070,lag=1
    master_replid:119b5221a7a59fa0bae8b405aa9bc09074ee0c11
    master_replid2:0000000000000000000000000000000000000000
    master_repl_offset:25070
    second_repl_offset:-1
    repl_backlog_active:1
    repl_backlog_size:1048576
    repl_backlog_first_byte_offset:1
    repl_backlog_histlen:25070
    192.168.71.131:6379> info replication
    # Replication
    role:master
    connected_slaves:1
    slave0:ip=192.168.71.131,port=6380,state=online,offset=25140,lag=0
    master_replid:119b5221a7a59fa0bae8b405aa9bc09074ee0c11
    master_replid2:0000000000000000000000000000000000000000
    master_repl_offset:25140
    second_repl_offset:-1
    repl_backlog_active:1
    repl_backlog_size:1048576
    repl_backlog_first_byte_offset:1
    repl_backlog_histlen:25140

    然后对6379写入新的键值对:

    192.168.71.131:6379> set k2 v2
    OK
    192.168.71.131:6379> set k3 v3
    OK
    192.168.71.131:6379> keys *
    1) "k3"
    2) "k1"
    3) "k2"
    192.168.71.131:6380> keys *
    1) "k3"
    2) "k2"
    3) "k1"

    在6379和6380中都可以看到值的变化。

    这时候启动8081,并执行slaveof命令,成为6379的slave。

    [root@localhost src]# ./redis-server ../master-slave/redis6381.conf 
    [root@localhost src]# ps -aux | grep redis
    root      86740  0.0  0.0 145188  2300 ?        Ssl  03:26   0:20 ./redis-server 192.168.71.131:6379
    root      86967  0.0  0.0 145188  2316 ?        Ssl  07:36   0:07 ./redis-server 192.168.71.131:6380
    root      87119  0.0  0.0  14080  1208 pts/0    S+   09:56   0:00 ./redis-cli -h 192.168.71.131 -p 6379
    root      87120  0.0  0.0  14080  1200 pts/1    S+   09:56   0:00 ./redis-cli -h 192.168.71.131 -p 6380
    root      87145  0.0  0.0 144024  2040 ?        Ssl  10:06   0:00 ./redis-server 192.168.71.131:6381
    root      87150  0.0  0.0 112720   952 pts/2    S+   10:06   0:00 grep --color=auto redis
    [root@localhost src]# ./redis-cli -h 192.168.71.131 -p 6381
    192.168.71.131:6381> keys *
    1) "k1"
    192.168.71.131:6381> SLAVEOF 192.168.71.131 6379
    OK
    192.168.71.131:6381> keys *
    1) "k2"
    2) "k3"
    3) "k1"

    可以看到重新成为slave的时候,可以重新拿数据,从而跟上大部队。

    4、主机shutdown后情况如何?从机是上位成为master还是原地待命

    192.168.71.131:6379> SHUTDOWN
    not connected> exit

    关闭6379后。

    稍微等会,再查看6380和6381的情况

    192.168.71.131:6380> info replication
    # Replication
    role:slave
    master_host:192.168.71.131
    master_port:6379
    master_link_status:down
    master_last_io_seconds_ago:-1
    master_sync_in_progress:0
    slave_repl_offset:25949
    master_link_down_since_seconds:113
    slave_priority:100
    slave_read_only:1
    connected_slaves:0
    master_replid:119b5221a7a59fa0bae8b405aa9bc09074ee0c11
    master_replid2:0000000000000000000000000000000000000000
    master_repl_offset:25949
    second_repl_offset:-1
    repl_backlog_active:1
    repl_backlog_size:1048576
    repl_backlog_first_byte_offset:13311
    repl_backlog_histlen:12639
    192.168.71.131:6381> info replication
    # Replication
    role:slave
    master_host:192.168.71.131
    master_port:6379
    master_link_status:down
    master_last_io_seconds_ago:-1
    master_sync_in_progress:0
    slave_repl_offset:25949
    master_link_down_since_seconds:148
    slave_priority:100
    slave_read_only:1
    connected_slaves:0
    master_replid:119b5221a7a59fa0bae8b405aa9bc09074ee0c11
    master_replid2:0000000000000000000000000000000000000000
    master_repl_offset:25949
    second_repl_offset:-1
    repl_backlog_active:1
    repl_backlog_size:1048576
    repl_backlog_first_byte_offset:25698
    repl_backlog_histlen:252

    可以看到如果slave没有人为的额外的操作,仍然只是一个slave的角色。 不会上位成为master。

    5、主机又回来了后,主机新增记录,从机还能否顺利复制?

    现在我们启动6379

    [root@localhost src]# ./redis-server ../master-slave/redis6379.conf
    [root@localhost src]# ps -aux | grep redis
    root      86967  0.0  0.0 145184  2308 ?        Ssl  07:36   0:07 ./redis-server 192.168.71.131:6380
    root      87120  0.0  0.0  14080  1204 pts/1    S+   09:56   0:00 ./redis-cli -h 192.168.71.131 -p 6380
    root      87145  0.0  0.0 145168  2280 ?        Ssl  10:06   0:00 ./redis-server 192.168.71.131:6381
    root      87151  0.0  0.0  14080  1212 pts/2    S+   10:07   0:00 ./redis-cli -h 192.168.71.131 -p 6381
    root      87155  0.0  0.0 145172  2232 ?        Ssl  10:17   0:00 ./redis-server 192.168.71.131:6379
    root      87162  0.0  0.0 112720   956 pts/0    S+   10:17   0:00 grep --color=auto redis

    查看下信息:

    192.168.71.131:6379> info replication
    # Replication
    role:master
    connected_slaves:2
    slave0:ip=192.168.71.131,port=6380,state=online,offset=210,lag=0
    slave1:ip=192.168.71.131,port=6381,state=online,offset=196,lag=1
    master_replid:33bfcec0a2af6009b3e21df66a6bac7aeabcf64d
    master_replid2:0000000000000000000000000000000000000000
    master_repl_offset:210
    second_repl_offset:-1
    repl_backlog_active:1
    repl_backlog_size:1048576
    repl_backlog_first_byte_offset:1
    repl_backlog_histlen:210

    测试能否正常工作:

    192.168.71.131:6379> set k4 v4
    OK
    192.168.71.131:6380> get k4
    "v4"
    192.168.71.131:6381> get k4
    "v4"

    可以正常工作。

    当down掉的master重新回来的时候,是不用额外的操作,redis自动会维持原有的主从关系,并可以正常工作。

    复制原理

    1、每次从机联通后,都会给主机发送sync指令

    2、主机立刻进行存盘操作,发送RDB文件,给从机

    3、从机收到RDB文件后,进行全盘加载

    4、之后每次主机的写操作,都会立刻发送给从机,从机执行相同的命令

    搭建树形的主从关系

     上面的关系,主要存在的问题是: master如果下面有多个slave那么master的同步操作开销很大,因为从机数量太多。

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

     缺点: 风险是一旦某个slave宕机,后面的slave都没法备份。因为这是一种类似于树形的主从关系。如果有一个slave节点的挂了,那么对应的所有子树将全部没办法写了。

    我们可以测试搭建6379->6380->6381的这种主从关系。

    [root@VM_0_8_centos src]# ./redis-cli -h localhost -p 6380
    localhost:6380> slaveof localhost 6379
    OK
    localhost:6380> 
    127.0.0.1:6381> slaveof 127.0.0.1 6380
    OK

    我们查看6380,可以看出这个时候,角色是slave, 但是有对于6379来讲是从机,对于6381来讲是主机:

    虽然对于6381来讲是主机,但是也是不允许写入的。我们可以测试如下:

    127.0.0.1:6380> set k2 v2
    (error) READONLY You can't write against a read only replica.

    哨兵机制

    我门想到一个问题:如果以上的主从关系中:6379->6380->6381,当6379挂掉了以后:如何让6380上位?

    即执行:用 slaveof  no one  将从机变为主机。(必须手动执行)。

    哨兵机制其实就是反客为主的自动版。

    我首先建个sentinel.conf的文件,然后填写:

    sentinel  monitor  mymaster  127.0.0.1  6379  1

    其中mymaster为监控对象起的服务器名称, 1 为 至少有多少个哨兵同意迁移的数量。

    启动哨兵, 通过src目录下的redis-sentinel:

     

     这边哨兵也可以自动获取到主从关系。

    现在手动shutdown 6379看下,会怎么样:

    从哨兵的日志可以看到,其实现在已经是6380做master了。可以验证下:

    127.0.0.1:6380> info replication
    # Replication
    role:master
    connected_slaves:1
    slave0:ip=127.0.0.1,port=6381,state=online,offset=15719,lag=0
    master_replid:9fdc923e373621d1830cf52024edd2f1fc32096b
    master_replid2:5cdcc9b49def111a61014d745996f93bc9be07a4
    master_repl_offset:15719
    second_repl_offset:5099
    repl_backlog_active:1
    repl_backlog_size:1048576
    repl_backlog_first_byte_offset:1
    repl_backlog_histlen:15719
    127.0.0.1:6380> 

    那如果现在重新启动6379,情况会怎么样?其实从哨兵的日志可以看出来,6379已经编程6380的slave了。我们再启动6379,然后验证:

    总结:

    当主机挂了后,哨兵会选择一个从机作为slave, 选择条件依次为: 1、选择优先级靠前的 2、选择偏移量最大的 3、选择runid最小的从服务

    详解:什么是优先级靠前的?这个就要看主配置文件:slave-priority, (注:本人测试版本5.0.8,这个版本配置已经改成replica-priority),数字越小表示优先级越大,0表示永远不会被选为master。
    那什么是偏移量最大的?因为master需要向slave写数据,当master 挂了以后,那个时刻可能各个slave同步到的数据有细微差异,会优先选择同步数据更多的。

     那runid指每个redis实例启动后都会随机生成一个40位的runid。

  • 相关阅读:
    CF1386C Joker
    P7486 「StOI2031」彩虹
    CF1516E Baby Ehab Plays with Permutations
    重拾莫比乌斯反演
    联合省选 2020 补题记录
    拉格朗日插值如何插出系数
    NOI Online 2021 补题
    Re:从0开始的多项式生活
    LOJ #6485. LJJ 学二项式定理
    P5591 小猪佩奇学数学
  • 原文地址:https://www.cnblogs.com/chenmz1995/p/12671983.html
Copyright © 2011-2022 走看看