Redis 之 主从、哨兵、集群

主从复制

原理

slave启动后会给master发送sync同步命令,master接到命令后,启动后台的存盘进程,同时收集所有接收到的
用于修改数据命令集命令,在后台执行进程完毕之后,master将所有数据文件发送到slave,完成一次完全同步。

全量复制:slave启动时。
增量复制:全量复制之后,master后续命令更新采用增量复制。

图示

在这里插入图片描述

配置:

master不需要配置,只需要配置slave即可。

修改配置文件:
#redis_6380.conf
port 6380
pidfile /var/run/redis_6380.pid
dbfilename dump_6380.rdb

#redis_6381.conf
port 6381
pidfile /var/run/redis_6381.pid
dbfilename dump_6381.rdb

启动slave服务

./redis-server ../etc/redis_6380.conf
./redis-server ../etc/redis_6381.conf

登陆客户端:

127.0.0.1:6379> set k1 v1
OK
127.0.0.1:6379> set k2 v2
OK

127.0.0.1:6380> get k1
"v1"
127.0.0.1:6380> get k2
"v2"

127.0.0.1:6381> get k1
"v1"
127.0.0.1:6381> get k2
"v2"

读写模式

master写,slave读

缺点

master宕机之后,只能读取,不能在写入

哨兵模式

原理

解决主从复制中master宕机之后不能写入问题。
master挂了,哨兵会选举slave中一个为master。如果master又启动了,被哨兵转换为slave。

图示

在这里插入图片描述

配置

#修改配置文件sentinel_6379.conf
port 26379
sentinel monitor mymaster 127.0.0.1 6379 1

启动

#方法一:
 ./redis-sentinel ../etc/sentinel_6379.conf
#方法二:
 ./redis-server ../etc/sentinel_6379.conf --sentinel

测试

#关闭master
127.0.0.1:6379> shutdown

查看sentinel日志

在这里插入图片描述
得到6381被选为master

登陆6381并设置key,在6380可以获取对应key。实现master自动转换。

优点

1.哨兵集群,基于主从复制模式,所有主从配置优点它都有
2.主从可以转换,系统的可用性更好

缺点

1.在线扩容很难
2.哨兵模式配置很麻烦

cluster集群模式

由来

为了解决哨兵模式不能在线扩容而产生的

特点

  • 所有的redis节点彼此互联(PING-PONG机制),内部使用二进制协议优化传输速度和带宽。
  • 节点的fail是通过集群中超过半数的节点检测失效时才生效。
  • 客户端与redis节点直连,不需要中间代理层.客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可。

工作方式

在redis的每一个节点上,都有两个关键点,一个是插槽(slot),它的的取值范围是:0-16383。还有一个就是cluster,可以理解为是一个集群管理的插件。
当我们的存取的key到达的时候,redis会根据crc16的算法得出一个结果,然后把结果对 16384 求余数,这样每个 key 都会对应一个编号在 0-16383 (2^14)之间的哈希槽,通过这个值,去找到对应的插槽所对应的节点,然后直接自动跳转到这个对应的节点上进行存取操作。

为了保证高可用,redis-cluster集群引入了主从模式,一个主节点对应一个或者多个从节点,当主节点宕机的时候,就会启用从节点。当其它主节点ping一个主节点A时,如果半数以上的主节点与A通信超时,那么认为主节点A宕机了。
如果主节点A和它的从节点A1都宕机了,那么该集群就无法再提供服务了。

创建集群听起来很难的样子,其实redis已经帮我们做了大部分工作,只需要我们做少量配置即可。

流程

1.开启至少6个实例
2.执行创建集群命令即可

配置

编写redis_*.conf配置文件

#这里只说一个配置,其他配置都一样,就是改下端口号而已
#重新从源码包中将配置文件移动到新创建的目录cluster中,并复制6个,命名redis_7001.conf--redis_7006.conf
#这里只说redis_7001.conf,其他类似
port 7001    #不同实例
pidfile /var/run/redis_7001.pid  #记录每个实例的pid
dbfilename dump_7001.rdb          #如果使用RDB就改这个
appendfilename "appendonly_7001.aof" #如果使用aof就改这个
daemonize yes	#开启后台运行
protected-mode no    #集群模式要关闭保护模式
appendonly yes      #如果使用aof还要开启这个
cluster-enabled yes   #启用集群
cluster-config-file nodes-7001.conf  #和端口一起改变,Redis群集节点每次发生更改时自动保留群集配置
cluster-node-timeout 5000 #Redis群集节点可以不可用的最长时间,在这个时间段内而不会将其视为失败

快速生成其他配置文件
上面生成了7001的配置文件,复制5个,一次进入文件中将7001全文替换成对应端口即可。

:%s/7001/7003/g

写一个启动脚本,一个关闭脚本,并添加执行权限
vi cluster_start.sh

#!/bin/sh
set -e

./redis-server ../cluster/redis_7001.conf
./redis-server ../cluster/redis_7002.conf
./redis-server ../cluster/redis_7003.conf
./redis-server ../cluster/redis_7004.conf
./redis-server ../cluster/redis_7005.conf
./redis-server ../cluster/redis_7006.conf
#!/bin/sh
set -e

./redis-cli -p 7001 shutdown
./redis-cli -p 7002 shutdown
./redis-cli -p 7003 shutdown
./redis-cli -p 7004 shutdown
./redis-cli -p 7005 shutdown
./redis-cli -p 7006 shutdown

chmod +x cluster_start.sh
chmod +x cluster_stop.sh

不过对于关闭服务,我还是喜欢比较暴力的手段

killall redis-server

嘿嘿!!

启动实例

./cluster_start.sh

查看

ps -ef| grep redis

在这里插入图片描述

创建集群

./redis-cli --cluster create 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005 127.0.0.1:7006 --cluster-replicas 1

在这里插入图片描述
它会自动创建主从节点,并且分配不同的slots范围。如果你想多几个从节点,创建 时

	--cluster-replicas 1

指定。前提是开启的实例要够。

单独开启或者关闭集群

创建好之后,以后只需要开启或者关闭,不需要再次创建了。
在源码中找到管理脚本:

redis-5.0.8/utils/create-cluster/create-cluster

修改脚本里面的port(设置7000)和nodes(6),执行脚本,集群就会开启或者关闭。
我建议还是看一下这个脚本怎么玩的。别被坑了

./create-cluster start/stop

注意

创建集群之后启动实例命令就和一般的不一样了。我把脚本文件start过程贴一下:

 ./redis-server --port $PORT --cluster-enabled yes --cluster-config-file nodes_${PORT}.conf --cluster-node-timeout $TIMEOUT --appendonly yes --appendfilename appendonly_${PORT}.aof --dbfilename dump_${PORT}.rdb --logfile ${PORT}.log --daemonize yes

登陆测试

./redis-cli -c -p 7001

-c:表示集群

redis cluster 命令说明

命令 说明
//集群(cluster)
CLUSTER INFO 打印集群的信息
CLUSTER NODES 列出集群当前已知的所有节点(node),以及这些节点的相关信息。
//节点(node)
CLUSTER MEET <ip> <port> 将 ip 和 port 所指定的节点添加到集群当中,让它成为集群的一份子。
CLUSTER FORGET <node_id> 从集群中移除 node_id 指定的节点。
CLUSTER REPLICATE <node_id> 将当前节点设置为 node_id 指定的节点的从节点。
CLUSTER SAVECONFIG 将节点的配置文件保存到硬盘里面。
//槽(slot)
CLUSTER ADDSLOTS <slot> [slot …] 将一个或多个槽(slot)指派(assign)给当前节点。
CLUSTER DELSLOTS <slot> [slot …] 移除一个或多个槽对当前节点的指派。
CLUSTER FLUSHSLOTS 移除指派给当前节点的所有槽,让当前节点变成一个没有指派任何槽的节点。
CLUSTER SETSLOT <slot> NODE <node_id> 将槽 slot 指派给 node_id 指定的节点,如果槽已经指派给另一个节点,那么先让另一个节点删除该槽>,然后再进行指派。
CLUSTER SETSLOT <slot> MIGRATING <node_id> 将本节点的槽 slot 迁移到 node_id 指定的节点中。
CLUSTER SETSLOT <slot> IMPORTING\ <node_id> 从 node_id 指定的节点中导入槽 slot 到本节点。
CLUSTER SETSLOT <slot> STABLE 取消对槽 slot 的导入(import)或者迁移(migrate)。
//键 (key)
CLUSTER KEYSLOT <key> 计算键 key 应该被放置在哪个槽上。
CLUSTER COUNTKEYSINSLOT <slot> 返回槽 slot 目前包含的键值对数量。
CLUSTER GETKEYSINSLOT <slot> 返回 count 个 slot 槽中的键。

这些命令是集群所独有的。执行上述命令要先登录

查看cluster信息

127.0.0.1:7001> CLUSTER info    ##查看cluster信息
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6
cluster_size:3
cluster_current_epoch:6
cluster_my_epoch:1
cluster_stats_messages_ping_sent:2242
cluster_stats_messages_pong_sent:2286
cluster_stats_messages_sent:4528
cluster_stats_messages_ping_received:2281
cluster_stats_messages_pong_received:2242
cluster_stats_messages_meet_received:5
cluster_stats_messages_received:4528
127.0.0.1:7001> CLUSTER NODES      ##查看节点信息, node-id 就是第一列字符
ba5de67fdb5786436a85af94b756e222e460782e 127.0.0.1:7006@17006 slave 587bde2531213f68721a47629ffa73f02aa4a901 0 1587219713720 6 connected
66503dd0a778be6219b72523e7067701ef195d2e 127.0.0.1:7002@17002 master - 0 1587219713515 2 connected 5461-10922
adff8ad98fa736c0dec59504c9d327a6e8c6aa96 127.0.0.1:7004@17004 slave 6c73487c7ba28b701538663640161a7ea8ae5a5e 0 1587219713515 4 connected
6c73487c7ba28b701538663640161a7ea8ae5a5e 127.0.0.1:7001@17001 myself,master - 0 1587219714000 1 connected 0-5460
383c0994ab130e32b34dca84ae9b69cd771c782b 127.0.0.1:7005@17005 slave 66503dd0a778be6219b72523e7067701ef195d2e 0 1587219713515 5 connected
587bde2531213f68721a47629ffa73f02aa4a901 127.0.0.1:7003@17003 master - 0 1587219714771 3 connected 10923-16383

##查看当前服务的主从关系
127.0.0.1:7001> info replication
# Replication
role:master
connected_slaves:1
slave0:ip=127.0.0.1,port=7004,state=online,offset=1106,lag=1
master_replid:74a6e347a1ae2ba4d8cd3f17d678fa924dc53166
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:1106
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:1106

##查看slots范围
127.0.0.1:7001> CLUSTER SLOTS
1) 1) (integer) 0
   2) (integer) 5460
   3) 1) "127.0.0.1"
      2) (integer) 7001
      3) "6c73487c7ba28b701538663640161a7ea8ae5a5e"
   4) 1) "127.0.0.1"
      2) (integer) 7004
      3) "adff8ad98fa736c0dec59504c9d327a6e8c6aa96"
2) 1) (integer) 5461
   2) (integer) 10922
   3) 1) "127.0.0.1"
      2) (integer) 7005
      3) "383c0994ab130e32b34dca84ae9b69cd771c782b"
   4) 1) "127.0.0.1"
      2) (integer) 7002
      3) "66503dd0a778be6219b72523e7067701ef195d2e"
3) 1) (integer) 10923
   2) (integer) 16383
   3) 1) "127.0.0.1"
      2) (integer) 7003
      3) "587bde2531213f68721a47629ffa73f02aa4a901"
   4) 1) "127.0.0.1"
      2) (integer) 7006
      3) "ba5de67fdb5786436a85af94b756e222e460782e"


##设置键值,可以发现存储在不同地方,自动切换到不同的节点
127.0.0.1:7001> set k1 v1
-> Redirected to slot [12706] located at 127.0.0.1:7003
OK
127.0.0.1:7003> set k2 v2
-> Redirected to slot [449] located at 127.0.0.1:7001
OK
127.0.0.1:7001> get k1
-> Redirected to slot [12706] located at 127.0.0.1:7003
"v1"
127.0.0.1:7003> get k2
-> Redirected to slot [449] located at 127.0.0.1:7001
"v2"

测试故障转移

./redis-cli -p 7002 debug segfault

故障前:
在这里插入图片描述
故障后:
在这里插入图片描述
7002完蛋,7005变为master

重启7002服务

./redis-server ../cluster/redis_7002.conf

在这里插入图片描述
重启7002之后,发现它变成slave节点了。

手动故障转移

使用cluster failover 进行手动故障转移,必须在要转移的主服务器的一个从节点执行该命令。
这个命令告诉主节点下班,从节点成为主节点。有两个选项force和takeover。具体区别百度吧。

127.0.0.1:7004> CLUSTER FAILOVER 

上面的slots是redis自动分配的,如果你想自己设置每个节点,那么使用如下命令

127.0.0.1:7001> CLUSTER ADDSLOTS {0..m}

m最大值为16383

添加节点

a. 添加主节点

./redis-cli --cluster add-node 127.0.0.1:7007 127.0.0.1:7001

第一个参数为要添加的节点,第二个参数为已存在集群中的随机一个节点。

新添加的节点没有slots,所以需要从其他节点拿过来

分配插槽

./redis-cli --cluster reshard 127.0.0.1:7001

只需指定一个节点,其他会自动找到。接下来会输入需要移动的slots数量和目标ID以及从哪些节点获取slots。
在这里插入图片描述
可以把分配的过程理解成打扑克牌,all表示大家重新洗牌;输入某个主节点的node id,然后在输入done的话,就好比从某个节点,抽牌。

检查测试集群运行状况

./redis-cli --cluster check 127.0.0.1:7002

b. 添加从节点

添加从节点如果不指定主节点,程序会自动添加到从节点较少的主节点。

./redis-cli --cluster add-node 127.0.0.1:7008 127.0.0.1:7001 --cluster-slave --cluster-master-id 3c3a0c74aae0b56170ccb03a76b60cfe7dc1912e

c.从节点改变master

127.0.0.1:7008> CLUSTER REPLICATE 6c73487c7ba28b701538663640161a7ea8ae5a5e   //新master的node-id
OK

删除节点:

a. 删除主节点

如果主节点有从节点,将从节点转移到其他主节点(方法见上面c)
如果主节点有slot,去掉分配的slot,然后在删除主节点

去掉分配的slots

./redis-cli --cluster reshard 127.0.0.1:7007    #想要删除的主节点ip:port

在这里插入图片描述
也可以直接使用命令行参数移动slots

redis-cli --cluster  reshard 10.150.134.92:7001 --cluster-to 21c7c13ed399a466e7011d8037fad7bc05c9aecc --cluster-from 8fc5771cff9b54aad06541aded5253e804b2432b --cluster-slots [0-60] --cluster-yes

删除主节点

./redis-cli --cluster del-node 127.0.0.1:7001 'b39f84c35cfc0c11e9730b20d34b8d0766b181ce'

第一个参数为集群随机节点,第二个参数为要删除的节点ID

b. 删除从节点

./redis-cli --cluster del-node 127.0.0.1:7001 '3328859bf6d03844d12c7c94fe1a679b039652e9'

第一个参数为集群随机节点,第二个参数为要删除的节点ID

节点修复

./redis-cli --cluster fix ip:port

灾备恢复

方案

主节点不做RDB和AOF,从节点同时开启两个。
如果主节点挂了,将从节点的dump.rdb和appendonly.aof拷贝到主节点,重启主节点即可。文件读取顺序,先读AOF文件。

实际情况

少用AOF,恢复慢。从节点直接使用RDB,调高写入频率或者写一个计划任务来定期bgsave的快照存储。

实际redis监控工具

treeNMS

redis数据回写机制

同步save命令(容易系统死机,不推荐)
异步bgsave,主进程fork一个进程负责写,之后关闭。

系统设置参数:(内存申请直接放行)

sysctl vm.overcommit_memory=1

数据保存到同一个slots中(一个节点上)

使用{} tag:

127.0.0.1:7005> set foo1{my_tag} 333
OK
127.0.0.1:7005> set foo{my_tag} 222
OK

集群不能选择其他DB,只能使用DB0

即只能select 0

发布了193 篇原创文章 · 获赞 13 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/u013919153/article/details/105604334