主从复制,是指将一台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!
只配置从库,不用配置主库!
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
复制三个配置文件,修改对应信息。
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.
测试:主机断开连接,从机依旧连接到主机的,但是没有写操作,这个时候,主机如果回来了,从机依 旧可以直接获取到主机写的信息! 如果是使用命令行(如上),来配置的主从,这个时候如果重启了,就会变回主机!只要变为从机,立马就会从 主机中获取值!
复制原理
Slave 启动成功连接到 master 后会发送一个sync同步命令 Master 接到命令,启动后台的存盘进程,同时收集所有接收到的用于修改数据集命令,在后台进程执行 完毕之后,master将传送整个数据文件到slave,并完成一次完全同步。 全量复制:而slave服务在接收到数据库文件数据后,将其存盘并加载到内存中。 增量复制:Master 继续将新的所有收集到的修改命令依次传给slave,完成同步 但是只要是重新连接master,一次完全同步(全量复制)将被自动执行! 我们的数据一定可以在从机中 看到!