redis学习(十八)

redis学习(十八)

Redis主从复制

概念

主从复制,是指将一台Redis服务器的数据,复制到其他的Redis服务器。前者称为主节点
(master/leader),后者称为从节点(slave/follower);数据的复制是单向的,只能由主节点到从节点。
Master以写为主,Slave 以读为主。

默认情况下,每台Redis服务器都是主节点;
且一个主节点可以有多个从节点(或没有从节点),但一个从节点只能有一个主节点。()

主从复制的作用主要包括:

1、数据冗余:主从复制实现了数据的热备份,是持久化之外的一种数据冗余方式。
2、故障恢复:当主节点出现问题时,可以由从节点提供服务,实现快速的故障恢复;实际上是一种服务
的冗余。
3、负载均衡:在主从复制的基础上,配合读写分离,可以由主节点提供写服务,由从节点提供读服务
(即写Redis数据时应用连接主节点,读Redis数据时应用连接从节点),分担服务器负载;尤其是在写
少读多的场景下,通过多个从节点分担读负载,可以大大提高Redis服务器的并发量。
4、高可用(集群)基石:除了上述作用以外,主从复制还是哨兵和集群能够实施的基础,因此说主从复
制是Redis高可用的基础。

一般来说,要将Redis运用于工程项目中,只使用一台Redis是万万不能的(宕机),原因如下:
1、从结构上,单个Redis服务器会发生单点故障,并且一台服务器需要处理所有的请求负载,压力较大;
2、从容量上,单个Redis服务器内存容量有限,就算一台Redis服务器内存容量为256G,也不能将所有内存用作Redis存储内存,一般来说,单台Redis最大使用内存不应该超过20G。
电商网站上的商品,一般都是一次上传,无数次浏览的,说专业点也就是"多读少写"。

主从复制,读写分离! 80% 的情况下都是在进行读操作!减缓服务器的压力!架构中经常使用!
一主二从!
只要在公司中,主从复制就是必须要使用的,因为在真实的项目中不可能单机使用Redis!

image-20200729152111778

环境配置

只配置从库,不用配置主库!

127.0.0.1:6666> info replication # 查看信息
# Replication
role:master # 主机
connected_slaves:0 # 没有从机
master_replid:357d2d5730c8f29b586b06dd76549fcb3d49c172
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

复制三个配置文件,修改对应信息。

image-20200729153349164

1、端口
2、pid 名字
3、log文件名字
4、dump.rdb 名字
修改完毕之后,启动我们的3个redis服务器,可以通过进程信息查看。

# 普通方式
port 6378
pidfile /var/run/redis_6378.pid
logfile "/dev/redis78.log"
dbfilename dump6378.rdb
# docker方式-----------------------------------------------------------------------------------------------
# 创建属于redis的集群网络------------------------------------------------------------------------------------
docker network create redis-cluster-net
# 查看ip 172.18.0.0----------------------------------------------------------------------------------------
[root@centos8 ~]# docker network inspect redis-cluster-net
[
    {
        "Name": "redis-cluster-net",
        "Id": "c3550af56a4c5a4894e04963b5b747361122e3666f58bd1e88e854f4b295f316",
        "Created": "2020-07-29T04:42:39.479861603-04:00",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "172.18.0.0/16",
                    "Gateway": "172.18.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {},
        "Options": {},
        "Labels": {}
    }
]
# 编写模版文件名为:redis-cluster.tmpl ,路径放在 /usr/local/database/redis/redis-cluster ---------------------
# 基本配置
protected-mode yes
port ${port}
bind 0.0.0.0 
tcp-backlog 511
timeout 0
tcp-keepalive 300
daemonize no
supervised no
pidfile /var/run/redis_${port}.pid
loglevel notice
logfile ""
databases 16
always-show-logo yes
save 900 1
save 300 10
save 60 10000
stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes
dbfilename dump${port}.rdb
rdb-del-sync-files no
dir ./
replica-serve-stale-data yes
replica-read-only yes
repl-diskless-sync no
repl-diskless-sync-delay 5
repl-disable-tcp-nodelay no
replica-priority 100
acllog-max-len 128

 # requirepass 
lazyfree-lazy-eviction no
lazyfree-lazy-expire no
lazyfree-lazy-server-del no
replica-lazy-flush no
lazyfree-lazy-user-del no


appendonly no

appendfilename "appendonly.aof"

appendfsync everysec


auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb


aof-load-truncated yes


aof-use-rdb-preamble yes

lua-time-limit 5000
slowlog-log-slower-than 10000
slowlog-max-len 128
latency-monitor-threshold 0
notify-keyspace-events ""
hash-max-ziplist-entries 512
hash-max-ziplist-value 64


list-max-ziplist-size -2


list-compress-depth 0

set-max-intset-entries 512

zset-max-ziplist-entries 128
zset-max-ziplist-value 64

hll-sparse-max-bytes 3000

stream-node-max-bytes 4096
stream-node-max-entries 100

activerehashing yes
hz 10
dynamic-hz yes



# 创建配置脚本-----------------------------------------------------------------------------------------------

# 主目录
dir_redis_cluster='/usr/local/database/redis/redis-cluster'
# docker redis集群网关 gateway='172.18.0.1'
# 节点地址号 从2开始
idx=1
# 逐个创建各节点目录和配置文件 三个
for port in `seq 7000 7002`; do
    # 创建存放redis数据路径
    mkdir -p ${dir_redis_cluster}/${port}/data;
    # 通过模板个性化各个节点的配置文件
    idx=$(($idx+1));
    port=${port} ip=`echo ${gateway} | sed "s/1$/$idx/g"` \
        envsubst < ${dir_redis_cluster}/redis-cluster.tmpl \
        > ${dir_redis_cluster}/${port}/redis-${port}.conf
done
# 配置并启动-----------------------------------------------------------------------------------------------
# 创建容器配置并运行 redis.conf后面你的版本,默认是最新。
for port in `seq 7000 7002`; do
    docker run --name redis-${port} --net redis-cluster-net -d \
        -p ${port}:${port} -p 1${port}:1${port} \
        -v ${dir_redis_cluster}/${port}/data:/data \
        -v ${dir_redis_cluster}/${port}/redis-${port}.conf:/usr/local/etc/redis/redis.conf redis \
        redis-server /usr/local/etc/redis/redis.conf
done
# 查看集群功能是否开启,这里需要让它不成功 info cluster-----------------------------------------------------------
[root@centos8 ~]# docker exec -it redis-7000 redis-cli -p 7000 info cluster
# Cluster
cluster_enabled:0
# 其他操作(注意自己的路径)--------------------------------------------------------------------------
#!/bin/bash
# 外部输入命令
com=$1
# 主目录
dir_redis_cluster='/usr/local/database/redis/redis-cluster'
# redis集群网关
gateway='172.18.0.1'

case ${com} in
	create)
        idx=1;
		for port in `seq 7000 7005`; do
            # 创建存放redis数据路径
			mkdir -p ${dir_redis_cluster}/${port}/data;
            # 通过模板个性化各个节点的配置文件
            idx=$(($idx+1));
            port=${port} ip=`echo ${gateway} | sed "s/1$/$idx/g"` \
                envsubst < ${dir_redis_cluster}/redis-cluster.tmpl \
                > ${dir_redis_cluster}/${port}/redis-${port}.conf
		done
	;;
    build)
        # 创建容器配置并运行
        for port in `seq 7000 7005`; do
            docker run --name redis-${port} --net redis-cluster-net -d \
            	-p ${port}:${port} -p 1${port}:1${port} \
                -v ${dir_redis_cluster}/${port}/data:/data \
                -v ${dir_redis_cluster}/${port}/redis-${port}.conf:/usr/local/etc/redis/redis.conf redis \
                redis-server /usr/local/etc/redis/redis.conf
        done
    ;;
    start | begin)
        # 运行容器
    	for port in `seq 7000 7002`; do
            docker start redis-${port}
        done
    ;;
    stop | end)
        # 停止容器运行
        for port in `seq 7000 7002`; do
            docker stop redis-${port}
        done
    ;;
    rm)
        # 删除已有容器
        for port in `seq 7000 7002`; do
            docker rm redis-${port}
        done
    ;;
    restart)
        # 重启已有容器
    	for port in `seq 7000 7002`; do
            docker restart redis-${port}
        done
    ;;
    destroy)
        # 删除集群目录及配置
        for port in `seq 7000 7002`; do
            rm -rf ${dir_redis_cluster}/${port}
        done
    ;;
    *)
        echo "Usage:	./build [create|build|start|stop|rm|restart|destroy]"
    ;;
esac

一丛二主

默认情况下,每台Redis服务器都是主节点; 我们一般情况下只用配置从机就好了!
认老大!
一主 (70)二从(71,72)启动三个容器。

[root@centos8 redis-cluster]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                                                        NAMES
2157b7f9d97d        redis               "docker-entrypoint.s…"   5 seconds ago       Up 4 seconds        0.0.0.0:7002->7002/tcp, 6379/tcp, 0.0.0.0:17002->17002/tcp   redis-7002
f1ac84714bf7        redis               "docker-entrypoint.s…"   6 seconds ago       Up 4 seconds        0.0.0.0:7001->7001/tcp, 6379/tcp, 0.0.0.0:17001->17001/tcp   redis-7001
0db76b9cbe64        redis               "docker-entrypoint.s…"   6 seconds ago       Up 5 seconds        0.0.0.0:7000->7000/tcp, 6379/tcp, 0.0.0.0:17000->17000/tcp   redis-7000
# 重点如下。-------------------------------------------------------------------------------------------------
# 主机
127.0.0.1:7000> info replication #查看主从信息
# Replication
role:master
connected_slaves:2
slave0:ip=172.18.0.1,port=7001,state=online,offset=392,lag=0
slave1:ip=172.18.0.1,port=7002,state=online,offset=392,lag=1
master_replid:e2c07eadf81344899ffd7cec60036686885c2947
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
# 从机,得用ip才行,我真是服了。就算是本机127也不行。
[root@centos8 ~]# docker exec -it redis-7001 /bin/bash
root@cb475fe3b9e0:/data# redis-cli -h 192.168.106.129 -p 7001
192.168.106.129:7001> info replication
# Replication
role:master
connected_slaves:0
master_replid:868aadcb711e66461f5cd50b5ef59cf9cacbb26c
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
192.168.106.129:7001> SLAVEOF 192.168.106.129 7000 #设置为从机,二号机也是一样。
OK
192.168.106.129:7001> info replication 
# Replication
role:slave
master_host:192.168.106.129
master_port:7000
master_link_status:up
master_last_io_seconds_ago:3
master_sync_in_progress:0
slave_repl_offset:336
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:e2c07eadf81344899ffd7cec60036686885c2947
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:336
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:336

真实的从主配置应该在配置文件中配置,这样的话是永久的,我们这里使用的是命令,暂时的!

操作

主机可以写,从机不能写只能读!主机中的所有信息和数据,都会自动被从机保存!

# 主机可写可读
127.0.0.1:7000> set name cuixiaoyan
OK
127.0.0.1:7000> get name
"cuixiaoyan"
# 从机只能读
192.168.106.129:7001> get name
"cuixiaoyan"
192.168.106.129:7001> set age 18
(error) READONLY You can't write against a read only replica.  

测试:主机断开连接,从机依旧连接到主机的,但是没有写操作,这个时候,主机如果回来了,从机依
旧可以直接获取到主机写的信息!
如果是使用命令行(如上),来配置的主从,这个时候如果重启了,就会变回主机!只要变为从机,立马就会从
主机中获取值!

  • 先将7002从机停止,然后主机7000往里面放数据,从机7001获取没有问题,重新启动7002并进行连接主机也是可以获取全部的,尽管刚才它宕机了。就是下面的==增量复制==。
  • 主机7000如果宕机后,从机的绑定关系,依然还在。就只能提供查询操作,从机是不允许写操作的。
  • 这样就出问题了,我们需要在没有宕机的从机中,选出一个主机。使用 ==SLAVEOF no one== 让自己变成主机,让其他从机重新连接过来。
  • 如果这时候,之前的主机7000重新上线,就只能当做从机,去连接新的主机。==SLAVEOF== 192.168.106.129 7001

复制原理

Slave 启动成功连接到 master 后会发送一个sync同步命令
Master 接到命令,启动后台的存盘进程,同时收集所有接收到的用于修改数据集命令,在后台进程执行
完毕之后,master将传送整个数据文件到slave,并完成一次完全同步。
全量复制:而slave服务在接收到数据库文件数据后,将其存盘并加载到内存中。
增量复制:Master 继续将新的所有收集到的修改命令依次传给slave,完成同步
但是只要是重新连接master,一次完全同步(全量复制)将被自动执行! 我们的数据一定可以在从机中
看到!