功能概述

​ Redis Cluster是Redis的自带的官方分布式解决方案,提供数据分片、高可用功能,在3.0版本正式推出。

​ 使用Redis Cluster能达到负载均衡的问题,内部采用哈希分片规则:

​ 基础架构图如下所示:

​ 图中最大的虚线部分为一个Cluster集群,由6个Redis实例组成。

集群分片

​ 整个Cluster集群中有16384个槽位,必须要将这些槽位分别规划在3台Master中。

​ 如果有任意1个槽位没有被分配,则集群创建不成功。

​ 当集群中任意一个Master尝试进行写入操作后,会通过Hash算法计算出该条数据应该落在哪一个Master节点上。

​ 如下图所示:

​ 情况1:如果你未指定任何参数就进行写入,如在Master1上写入数据,经过内部计算发现该数据应该在Master2上写入时,会提示你应该进入Master2写入该条数据,执行并不会成功

​ 情况2:如果你指定了一个特定参数进行写入,如在Master1上写入数据,经过内部计算发现该数据应该在Master2上写入时,会自动将写入环境重定向至Master2,执行成功

​ 同理,读取数据也是这样,这个过程叫做MOVED重定向,如果你是情况1进行操作则必须手动进行重定向,情况2则会自动进行重定向。

集群通信

​ 集群中各个节点的信息是互通的,这种现象由Gossip(流言)协议产生。

​ Gossip协议规定每个集群节点之间互相交换信息,使其能够彼此知道对方的状态。

​ 在通信建立时,集群中的每一个节点都会单独的开辟一个TCP通道,用于与其他节点进行通信,这个通信端口会在基础端口上+10000。

​ 通信建立成功后,每个节点在固定周期内通过特定规则选择节点来发送ping消息(心跳机制)。

​ 当收到ping消息的节点则会使用pong消息作为回应,也就是说,当有一个新节点加入后,一瞬间集群中所有的其他节点也能够获取到该信息。

​ Gossip协议的主要职责就是进行集群中节点的信息交换,常见的Gossip协议消息有以下几点区分:

  • meet:用于通知新节点加入,消息发送者通知接受者加入到当前集群
  • ping:集群内每个节点与其他节点进行心跳检测的命令,用于检测其他节点是否在线,除此之外还能交换其他额外信息
  • pong:用于回复meet以及ping信息,表示已收到,能够正常通行。此外还能进行群发更新节点状态
  • fail:当其他节点收到fail消息后立马把对应节点更新为下线状态,此时集群开始进行故障转移

初步搭建

地址规划

​ 3台服务器,每台服务器开启2台实例构建基础主从。

​ 服务器采用centos7.3,Redis版本为6.2.1

​ 地址规划与结构图如下:

​ 在每个节点hosts文件中加入以下内容;

$ vim /etc/hosts

192.168.0.120 node1
192.168.0.130 node2
192.168.0.140 node3

集群准备

​ 为所有节点下载Redis:

$ cd ~
$ wget https://download.redis.io/releases/redis-6.2.1.tar.gz

​ 为所有节点配置目录:

$ mkdir -p /usr/local/redis_cluster/redis_63{79,80}/{conf,pid,logs}

​ 所有节点进行解压:

$ tar -zxvf redis-6.2.1.tar.gz -C /usr/local/redis_cluster/

​ 所有节点进行编译安装Redis:

$ cd /usr/local/redis_cluster/redis-6.2.1/
$ make && make install

​ 书写集群配置文件,注意!Redis普通服务会有2套配置文件,一套为普通服务配置文件,一套为集群服务配置文件,我们这里是做的集群,所以书写的集群配置文件,共6份:

$ vim /usr/local/redis_cluster/redis_6379/conf/redis.cnf

# 快速修改::%s/6379/6380/g

# 守护进行模式启动
daemonize yes # 设置数据库数量,默认数据库为0
databases 16 # 绑定地址,需要修改
bind 192.168.0.120 # 绑定端口,需要修改
port 6379 # pid文件存储位置,文件名需要修改
pidfile /usr/local/redis_cluster/redis_6379/pid/redis_6379.pid # log文件存储位置,文件名需要修改
logfile /usr/local/redis_cluster/redis_6379/logs/redis_6379.log # RDB快照备份文件名,文件名需要修改
dbfilename redis_6379.rdb # 本地数据库存储目录,需要修改
dir /usr/local/redis_cluster/redis_6379 # 集群相关配置
# 是否以集群模式启动
cluster-enabled yes # 集群节点回应最长时间,超过该时间被认为下线
cluster-node-timeout 15000 # 生成的集群节点配置文件名,文件名需要修改
cluster-config-file nodes_6379.conf

启动集群

启动集群

​ 在启动集群时,会按照Redis服务配置文件的配置项判断是否启动集群模式,如图所示:

​ 每个节点上执行以下2条命令进行服务启动:

$ redis-server /usr/local/redis_cluster/redis_6379/conf/redis.cnf
$ redis-server /usr/local/redis_cluster/redis_6380/conf/redis.cnf

​ 集群模式启动,它的进行后会加上[cluster]的字样:

$ ps -ef | grep redis
root 51311 1 0 11:30 ? 00:00:00 redis-server 192.168.0.120:6379 [cluster]
root 51329 1 0 11:30 ? 00:00:00 redis-server 192.168.0.120:6380 [cluster]
root 51396 115516 0 11:31 pts/1 00:00:00 grep --color=auto redis

​ 同时,查看一下集群节点配置文件,会发现生成了一组集群信息,每个Redis服务都是不同的:

$ cat /usr/local/redis_cluster/redis_6379/nodes_6379.conf
c8a8c7d52e6e7403e799c75302b6411e2027621b :0@0 myself,master - 0 0 0 connected
vars currentEpoch 0 lastVoteEpoch 0 $ cat /usr/local/redis_cluster/redis_6380/nodes_6380.conf
baa10306639fcaca833db0d521235bc9593dbeca :0@0 myself,master - 0 0 0 connected
vars currentEpoch 0 lastVoteEpoch 0 # 第一段信息是这个Redis服务作为集群节点的一个身份编码
# 别名为集群的node-id

加入集群

​ 现在虽然说每个服务都成功启动了,但是彼此之间并没有任何联系。

​ 所以下一步要做的就是将6个服务加入至一个集群中,如下操作示例:

$ redis-cli -h node1 -p 6379

node1:6379> cluster meet 192.168.0.130 6379
node1:6379> cluster meet 192.168.0.140 6379
node1:6379> cluster meet 192.168.0.120 6380
node1:6379> cluster meet 192.168.0.130 6380
node1:6379> cluster meet 192.168.0.140 6380

​ 查看当前集群所有的节点:

node1:6379> cluster nodes

214dc5a10149091047df1c61fd3415d91d6204ea 192.168.0.130:6379@16379 master - 0 1617291123000 1 connected
baa10306639fcaca833db0d521235bc9593dbeca 192.168.0.120:6380@16380 master - 0 1617291120000 3 connected
7a151f97ee9b020a3c954bbf78cd7ed8a674aa70 192.168.0.140:6379@16379 master - 0 1617291123000 2 connected
bae708f7b8df32edf4571c72bbf87715eb45c169 192.168.0.130:6380@16380 master - 0 1617291124175 4 connected
fd1dde2a641727e52b4e82cfb351fe3c17690a17 192.168.0.140:6380@16380 master - 0 1617291124000 0 connected
c8a8c7d52e6e7403e799c75302b6411e2027621b 192.168.0.120:6379@16379 myself,master - 0 1617291121000 5 connected

​ 查看端口监听,可以发现Gossip监听的1000+端口出现了,此时代表集群各个节点之间已经能互相通信了:

$ netstat -lnpt | grep redis
tcp 0 0 192.168.0.120:6379 0.0.0.0:* LISTEN 51311/redis-server
tcp 0 0 192.168.0.120:6380 0.0.0.0:* LISTEN 51329/redis-server
tcp 0 0 192.168.0.120:16379 0.0.0.0:* LISTEN 51311/redis-server
tcp 0 0 192.168.0.120:16380 0.0.0.0:* LISTEN 51329/redis-server

主从配置

​ 6个服务之间并没有任何主从关系,所以现在进行主从配置,记录下上面cluster nodes命令输出的node-id信息,只记录主节点:

hostname 节点 node-id
node1 192.168.0.120:6379 c8a8c7d52e6e7403e799c75302b6411e2027621b
node2 192.168.0.130:6379 214dc5a10149091047df1c61fd3415d91d6204ea
node3 192.168.0.140:6379 7a151f97ee9b020a3c954bbf78cd7ed8a674aa70

​ 首先是node1的6380,将它映射到node2的6379:

$ redis-cli -h node1 -p 6380
node1:6380> cluster replicate 214dc5a10149091047df1c61fd3415d91d6204ea

​ 然后是node2的6380,将它映射到node3的6379:

$ redis-cli -h node2 -p 6380
node2:6380> cluster replicate 7a151f97ee9b020a3c954bbf78cd7ed8a674aa70

​ 最后是node3的6380,将它映射到node1的6379:

$ redis-cli -h node3 -p 6380
node3:6380> cluster replicate c8a8c7d52e6e7403e799c75302b6411e2027621b

​ 查看集群节点信息,内容有精简:

$ redis-cli -h node1 -p 6379

node1:6379> cluster nodes
192.168.0.130:6379@16379 master
192.168.0.120:6380@16380 slave
192.168.0.140:6379@16379 master
192.168.0.130:6380@16380 slave
192.168.0.140:6380@16380 slave
192.168.0.120:6379@16379 myself,master # myself表示当前登录的是那个服务

分配槽位

​ 接下来我们要开始分配槽位了,为了考虑今后的写入操作能分配均匀,槽位也要进行均匀分配。

​ 仅在Master上进行分配,从库不进行分配,仅做备份和读库使用。

​ 使用python计算每个master节点分多少槽位:

$ python3

>>> divmod(16384,3)
(5461, 1)

​ 槽位分配情况如下,槽位号从0开始,到16383结束,共16384个槽位:

节点 槽位数量
node1:6379 0 - 5461
node2:6379 5461 - 10922
node3:6379 10922 - 16383

​ 开始分配:

$ redis-cli -h node1 -p 6379 cluster addslots {0..5461}
$ redis-cli -h node2 -p 6379 cluster addslots {5462..10922}
$ redis-cli -h node3 -p 6379 cluster addslots {10923..16383}

​ 检查槽位是否分配政策,这里进行内容截取:

$ redis-cli -h node1 -p 6379

node1:6379> CLUSTER nodes
192.168.0.130:6379@16379 master - 0 1617292240544 1 connected 5462-10922
192.168.0.140:6379@16379 master - 0 1617292239000 2 connected 10923-16383
192.168.0.120:6379@16379 myself,master - 0 1617292238000 5 connected 0-5461 # 看master节点的最后

检查状态

​ 使用以下命令检查集群状态,这里我遇到一个问题,插槽都已经成功分配了但是没有同步,导致集群启动不了:

$ redis-cli -h node1 -p 6379

node1:6379> CLUSTER info
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:5
cluster_my_epoch:5
cluster_stats_messages_ping_sent:2825
cluster_stats_messages_pong_sent:2793
cluster_stats_messages_meet_sent:5
cluster_stats_messages_sent:5623
cluster_stats_messages_ping_received:2793
cluster_stats_messages_pong_received:2830
cluster_stats_messages_received:5623

MOVED重定向

​ 现在我们在node1的master节点上进行写入:

$ redis-cli -h node1 -p 6379

node1:6379> set k1 "v1"
(error) MOVED 12706 192.168.0.140:6379

​ 它会提示你去node2的master上进行写入。

​ 这个就是MOVED重定向。

-c参数

​ 如何解决这个问题?其实在登录的时候加上参数-c即可,-c参数无所谓你的Redis是否是集群模式,建议任何登录操作都加上,这样即使是Redis集群也会自动进行MOVED重定向:

$ redis-cli -c -h node1 -p 6379

node1:6379> set k1 "v1"
-> Redirected to slot [12706] located at 192.168.0.140:6379
OK

​ 一并对主从进行验证,这条数据是写入至了node3的Master中,我们登录node2的Slave中进行查看:

$ redis-cli -h node2 -p 6380 -c

node2:6380> keys *
1) "k1"

故障转移

故障模拟

​ 模拟node1的6379下线宕机,此时应该由node3的6380接管它的工作:

$ redis-cli -h node1 -p 6379 shutdown

​ 登录集群任意节点查看目前的集群节点信息:

node2:6379> cluster nodes

214dc5a10149091047df1c61fd3415d91d6204ea 192.168.0.130:6379@16379 myself,master - 0 1617294532000 1 connected 5462-10922
bae708f7b8df32edf4571c72bbf87715eb45c169 192.168.0.130:6380@16380 slave 7a151f97ee9b020a3c954bbf78cd7ed8a674aa70 0 1617294533000 2 connected # 已下线
c8a8c7d52e6e7403e799c75302b6411e2027621b 192.168.0.120:6379@16379 master,fail - 1617294479247 1617294475173 5 disconnected 7a151f97ee9b020a3c954bbf78cd7ed8a674aa70 192.168.0.140:6379@16379 master - 0 1617294536864 2 connected 10923-16383 # 自动升级为主库,并且插槽也转移了
fd1dde2a641727e52b4e82cfb351fe3c17690a17 192.168.0.140:6380@16380 master - 0 1617294536000 6 connected 0-5461 baa10306639fcaca833db0d521235bc9593dbeca 192.168.0.120:6380@16380 slave 214dc5a10149091047df1c61fd3415d91d6204ea 0 1617294535853 1 connected

恢复工作

​ 重启node1的6379:

$ redis-server /usr/local/redis_cluster/redis_6379/conf/redis.cnf

​ 登录node1的6379,发现他已经自动的进行上线了,并且作为node3中6380的从库:

$ redis-cli -h node1 -p 6379

node1:6379> cluster nodes
# 自动上线
c8a8c7d52e6e7403e799c75302b6411e2027621b 192.168.0.120:6379@16379 myself,slave fd1dde2a641727e52b4e82cfb351fe3c17690a17 0 1617294746000 6 connected

cluster命令

​ 以下是集群中常用的可执行命令,命令执行格式为:

cluster 下表命令

​ 命令如下,未全,如果想了解更多请执行cluster help操作:

命令 描述
INFO 返回当前集群信息
MEET <ip> <port> [<bus-port>] 添加一个节点至当前集群
MYID 返回当前节点集群ID
NODES 返回当前节点的集群信息
REPLICATE <node-id> 将当前节点作为某一集群节点的从库
RESET [HARD|SOFT] 重置当前节点信息
ADDSLOTS <slot> [<slot> ...] 为当前集群节点增加一个或多个插槽位,推荐在bash shell中执行,可通过{int..int}指定多个插槽位
DELSLOTS <slot> [<slot> ...] 为当前集群节点删除一个或多个插槽位,推荐在bash shell中执行,可通过{int..int}指定多个插槽位
FLUSHSLOTS 删除当前节点中所有的插槽信息
FORGET <node-id> 从集群中删除某一节点
COUNT-FAILURE-REPORTS <node-id> 返回当前集群节点的故障报告数量
COUNTKEYSINSLOT <slot> 返回某一插槽中的键的数量
GETKEYSINSLOT <slot> <count> 返回当前节点存储在插槽中的key名称。
KEYSLOT <key> 返回该key的哈希槽位
SAVECONFIG 保存当前集群配置,进行落盘操作
SLOTS 返回该插槽的信息

Redis 超详细的手动搭建Cluster集群步骤的更多相关文章

  1. 在wildfly 21中搭建cluster集群

    目录 简介 下载软件和相关组件 配置domain 创建应用程序 部署应用程序 集群配置 总结 简介 wildfly是一个非常强大的工具,我们可以轻松的使用wildfly部署应用程序,更为强大的是,wi ...

  2. OceanBase数据库实践入门——手动搭建OceanBase集群

    前言 目前有关OceanBase功能.案例.故事的文章已经很多,对OceanBase感兴趣的朋友都想安装一个数据库试试.本文就是分享初学者如何手动搭建一个OceanBase集群.这也是学习理解Ocea ...

  3. 【Kubernetes学习笔记】-kubeadm 手动搭建kubernetes 集群

    目录 K8S 组件构成 环境准备 (以ubuntu系统为例) 1. kubernetes集群机器 2. 安装 docker. kubeadm.kubelet.kubectl 2.1 在每台机器上安装 ...

  4. [补充资料] 手动搭建 Cloudera 集群

    本课主题 集群搭建 设置 Web 服务器 启动 ClouderManager 登入 Cloudera Manager 引言 这部份是一个补充资料,记录如何安装 Cloudera 服务器 集群搭建 查看 ...

  5. Docker 搭建 ELK 集群步骤

    前言 本篇文章主要介绍在两台机器上使用 Docker 搭建 ELK. 正文 环境 CentOS 7.7 系统 Docker version 19.03.8 docker-compose version ...

  6. Redis搭建(七):Redis的Cluster集群动态增删节点

    一.引言 上一篇文章我们一步一步的教大家搭建了Redis的Cluster集群环境,形成了3个主节点和3个从节点的Cluster的环境.当然,大家可以使用 Cluster info 命令查看Cluste ...

  7. Redis Cluster 集群搭建与扩容、缩容

    说明:仍然是伪集群,所有的Redis节点,都在一个服务器上,采用不同配置文件,不同端口的形式实现 前提:已经安装好了Redis,本文的redis的版本是redis-6.2.3 Redis的下载.安装参 ...

  8. Docker搭建RabbitMQ集群

    Docker搭建RabbitMQ集群 Docker安装 见官网 RabbitMQ镜像下载及配置 见此博文 集群搭建 首先,我们需要启动运行RabbitMQ docker run -d --hostna ...

  9. 超详细,多图文使用galera cluster搭建mysql集群并介绍wsrep相关参数

    超详细,多图文使用galera cluster搭建mysql集群并介绍wsrep相关参数 介绍galera cluster原理的文章已经有一大堆了,百度几篇看一看就能有相关了解,这里就不赘述了.本文主 ...

随机推荐

  1. py conda 换源

    安装软件 $ conda install wxpython 如果出现http错误,安装OpenSSL $ conda config --add channels https://mirrors.tun ...

  2. wxPython 创建基本窗口

    $ pip install wxPython import wx class MyFrame(wx.Frame): def __init__(self, parent, title): super(M ...

  3. Flutter 区分开发环境和生产环境

    Uri _baseUrl; final isProd = const bool.fromEnvironment('dart.vm.product'); if (isProd) { _baseUrl = ...

  4. 「NGK每日快讯」2021.1.11日NGK第69期官方快讯!

  5. 15_MySQL·WHERE子句中条件执行的顺序

  6. 使用stress进行压力测试

    本文转载自使用stress进行压力测试 导语 stress,顾名思义是一款压力测试工具.你可以用它来对系统CPU,内存,以及磁盘IO生成负载. 安装stress 几乎所有主流的linux发行版的软件仓 ...

  7. @media屏幕适应

    /** 屏幕特殊处理 我们用min-width时,小的放上面大的在下面,同理如果是用max-width那么就是大的在上面,小的在下面 **/ @media screen and (max-width: ...

  8. java与freemarker遍历map

    一.java遍历MAP /** * 1.把key放到一个集合里,遍历key值同时根据key得到值 (推荐) */ Set set =map.keySet(); Iterator it=set.iter ...

  9. linux之安装nginx

    nginx官网:http://nginx.org/en/download.html 1.安装nginx所需环境 a)  PCRE pcre-devel 安装 # yum install -y pcre ...

  10. python爬虫登录保持及对http总结

    [前言]这几天一直看python爬虫登录保持.实现接口太多,太乱,新手难免云山雾罩.各种get.post,深入理解一下,其实就是由于http的特性需要这些操作.http是一种无状态.不保存上次通信结果 ...