redis 主从同步到分布式集群

在这里插入图片描述
Redis 集群是一个提供在多个Redis节点间共享数据的程序集
通过集群的配置可以解决:机器故障、容量瓶颈、QPS瓶颈等

主从同步

redis主从结构有一主多从和级联结构

一主多从:master将数据同步给多个slave节点
级联结构:主从结构下支持从从同步,可以减轻主节点的同步负担

在这里插入图片描述
运用场景

  • 数据备份:主节点将数据同步给从节点,当主节点服务发生异常,可以切换到从节点继续提供服务
  • 读写分离:写请求只发给主节点,读请求可以发给任何一个节点,在高并发的场景下,由于从服务分担了一部分读请求,可以使系统整体的吞吐量提升

主从同步机制

redis主从同步分为两个过程:全量同步和增量同步
从节点刚加入集群时会进行一次全量同步,然后通过增量同步将主节点的数据同步到从节点

首先了解三个概念:

  • runid:服务器运行id,可以唯一标识redis节点
  • offset:复制偏移量,从节点用来记录数据同步位置
  • buffer:主节点会将客户端请求的写命令缓存到buffer中
全量同步

在这里插入图片描述

  • slave连接master并发送同步命令 psync ? -1(?为 master runid,-1为slave offset,第一次建立连接slave不知道master的runid,也没有偏移量)
  • master接收命令判断出当前为全量复制,将runid和offect发送给slave
  • master fork子进程执行bgsave,此时master正常接收外部请求并缓存客户端的写命令
  • slave接收rdb文件,清空旧数据后将rdb文件加载到内存
  • master收到从节点rdb加载完成的信息后,将缓存区内的数据发送给slave
  • slave接收并更新数据

注:master在执行bgsave的同时接收客户端的请求,原因是fork子进程的时候操作系统采用写时复制(copy-on-write)策略,当父进程执行写操作时,会将数据页面复制一份出来进行修改

增量同步

redis同步的是指令流

  • 主节点将写操作的命令记录buffer,异步写入到从节点
  • 从节点接收并更新数据,每隔1s向master发送REPLCONF ACK命令反馈自己的偏移量

注:buffer是一个定长的环形数组,当空间被写满时,会从头开始覆盖前面的内容
因此如果任意一个从节点掉线时间过长,没有同步的指令有可能已经被后续的指令流覆盖掉,这时候需要重新做全量复制

在这里插入图片描述

sentinel(哨兵)

主从备份的情况下,当主节点挂掉时需要将其中一台从节点升为主节点,继续提供服务,这时需要人工也不高效,sentinel就是为此设计的,当发生故障时可以自动进行主从切换
在这里插入图片描述
sentinel通过ping以及info来持续监控和发现节点变化

客户端如何向集群读写:
client端首先会连接sentinel,向sentinel询问master或slave的地址,根据返回IP地址连接访问

# 通过discover_master、discover_slave方法获取所有master IP、slave IP
sentinel.discover_master('redis-cluster')
sentinel.discover_slave('redis-cluster')

# 通过master_for、slave_for方法可以从连接池拿出一个连接使用
sentinel.master_for('redis-cluster')
sentinel.slave_for('redis-cluster')


在这里插入图片描述

分布式集群

主从同步可以解决机器故障,也可以提升系统整体的吞吐量,但当数据量越来越大的时候主从也无能为力,分布式集群可以很好的解决系统容量瓶颈

分布式的情况下:

  • 节点之间是相互通信
  • 每个节点都会负责读写

在这里插入图片描述

槽位分片原理

redis 采用的是哈希槽的概念进行数据分片,内置16384个槽位

  1. redis key 通过crc16算法得到一个哈希值
  2. 哈希值对16384取模来确定槽位

计算公式: crc16(key)% 16384

在这里插入图片描述

集群搭建

接下来将搭建一个简单的redis集群,了解它组成的方式以及内部通信的基本模型,集群结构如下:
node1(6380),slave1(6383)
node2(6381),slave2(6384)
node3(6382),slave3(6385)

搭建流程
在这里插入图片描述
1、启动所有redis节点

创建node1配置文件node1.conf

port 6380
daemonize yes
logfile "6380.log"
dir "/opt/redis/data/"
dbfilename "dump-6380.rdb"
cluster-enabled yes
cluster-config-file nodes-6380.conf
cluster-require-full-coverage no
bind 0.0.0.0

启动node1服务执行: redis-server node1-conf
查看服务是否启动成功:redis-servps -ef | grep redis

( 以此类推修改配置文件端口号启动剩余5个节点 )

2、meet操作

集群中节点之间是相互通信的,所有节点共享信息,但在这之前需要先认识对方,也就是需要执行meet操作,假设A B之间相互认识,A C之间相互认识,那么通过 A,B和C也就自然认识了

meet操作执行:

redis-cli -p 6380 cluster meet 127.0.0.1 6381
redis-cli -p 6380 cluster meet 127.0.0.1 6382
redis-cli -p 6380 cluster meet 127.0.0.1 6383
redis-cli -p 6380 cluster meet 127.0.0.1 6384
redis-cli -p 6380 cluster meet 127.0.0.1 6385

执行:redis-cli -p 6380 cluster nodes
在这里插入图片描述

3、指派槽

添加槽脚本:script add_slot.sh

for slot in $(seq $1 $2)
do
    redis-cli -p $3 cluster addslots ${slot}
done

集群内置16384个槽位,为每个节点分配槽执行:

sh add_slot.sh 0 5461 6380           
sh add_slot.sh 5462 10922 6381   
sh add_slot.sh 10923 16383 6382 

执行:redis-cli -p 6380 cluster nodes
在这里插入图片描述
4、主从复制

slave节点复制对应的master节点,执行:

redis-cli -p 6383 cluster replicate 35674ee715d50b485a4c8d8ffb9d3a8484516ab3
redis-cli -p 6384 cluster replicate b7b0fe7fcf686157d344b156324fda6e9d457ece
redis-cli -p 6385 cluster replicate 894f41ea105c774bdd54d90869e409991d88158c

执行:redis-cli -p 6380 cluster nodes
在这里插入图片描述
执行:redis-cli -p 6380 cluster info
在这里插入图片描述
可以看到集群搭建成功!!!

在这里插入图片描述


注:以上是redis集群原生搭建的过程,也可以使用第三方工具redis-trib快速搭建集群

apt install ruby-full
gem install redis
find / -name redis-trib.rb
cp /usr/share/doc/redis-tools/examples/redis-trib.rb /usr/local/bin/redis-trib.rb
redis-trib.rb create --replicas 1 127.0.0.1:6380 127.0.0.1:6381 127.

集群扩容

在这里插入图片描述

在集群中添加一个新的节点node4,以及从节点slave4
node4(6386),slave4(6387)

前3个步骤之前一样

# 创建配置文件
sed 's/6380/6386/g' node1.conf > node4.conf
sed 's/6380/6387/g' node1.conf > slave4.conf
# 启动 node4、slave4 redis server
redis-server node4-conf
redis-server slave-conf
# meet 加入集群
redis-cli -p 6380 cluster meet 127.0.0.1 6386
redis-cli -p 6380 cluster meet 127.0.0.1 6387
# 主从复制,将slave4配置成node4的从节点
redis-cli -p 6380 cluster nodes
redis-cli -p 6387 cluster replicate 6b314fc95063e73b4b1daa947674fdc5cb64fb21

执行:redis-cli -p 6380 cluster nodes
在这里插入图片描述
槽迁移

集群内置的16384个槽位,已经全部分给了node1、noed2、node3,新节点node4 加入集群需要将前3个节点的部分槽迁移进去

我们借助redis-trib进行槽迁移执行:redis-trib.rb reshard 127.0.0.1:6380
在这里插入图片描述
执行:redis-cli -p 6380 cluster nodes | grep master
在这里插入图片描述
可以看到0-1365、5462-628、10923-12287的槽位都迁移到新节点node4中了,集群扩容完成

集群缩容

集群缩容分两步下线槽迁移和忘记节点


# 下线槽迁移,从node4节点分别迁移到其它3个节点,并指定迁移槽数量
redis-trib.rb reshard --from 6b314fc95063e73b4b1daa947674fdc5cb64fb21 --to 35674ee715d50b485a4c8d8ffb9d3a8484516ab3 --slots 1366 127.0.0.1:6380
redis-trib.rb reshard --from 6b314fc95063e73b4b1daa947674fdc5cb64fb21 --to b7b0fe7fcf686157d344b156324fda6e9d457ece --slots 1365 127.0.0.1:6381
redis-trib.rb reshard --from 6b314fc95063e73b4b1daa947674fdc5cb64fb21 --to 894f41ea105c774bdd54d90869e409991d88158c --slots 1365 127.0.0.1:6382

# 忘记节点(先 slave 后 master)
redis-trib.rb del-node 127.0.0.1:6380 8db6504e8829e0595d046a08f6d8596c5289c352
redis-trib.rb del-node 127.0.0.1:6380 6b314fc95063e73b4b1daa947674fdc5cb64fb21

执行:redis-cli -p 6380 cluster nodes
在这里插入图片描述
可以看到node4、slave4都不在集群中了,slot也分别迁移回了其它3个节点,集群缩容完成

客户端路由

redis集群中节点之间是相互通信,每个节点都会负责读写,那么如果查询的key不在请求的节点上的,是如何返回查询结果呢?

moved重定向

  • 客户端请求任意节点,查询key1
  • 节点收到请求计算slot值

如果slot刚好在node1上,则直接返回value
在这里插入图片描述
如果slot不在则返回solt所在的节点,客户端重新发送请求
在这里插入图片描述
进行集群的扩容和缩容都会有slot迁移的过程,如果slot正在迁移过程中,客户端发送请求,这时redis服务如何返回查询结果?

ask 重定向

  • 客户端请求一个正在进行槽迁移的源节点
  • 服务端发现数据不在源节点,返回 -ASK targetNodeAddr
    -客户端发送ASKING到迁移节点
    -迁移节点响应后,客户端再次向目标节点发送查询请求
    在这里插入图片描述

OK,到这里redis主从以及分布式集群你应该有一个大致的了解



欢迎关注公众号,一起学习交流

在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值