Redis Cluster集群的介绍以及搭建

文章目录

    • 前言
    • Redis集群介绍
    • Redis 集群的数据分片
    • Redis集群的主从复制模型
    • Redis 一致性保证
    • 搭建并使用Redis集群
        • 搭建集群
    • 模拟集群down掉的两种情况
        • 第一种情况
        • 解决办法
        • 第二种情况
        • 解决办法
    • 脚本方式创建和管理集群

集群教程:http://www.redis.cn/topics/cluster-tutorial.html

前言

  • (1)Redis-Cluster采用无中心结构
    每个节点都和其它节点通过互ping保持连接,每个节点保存整个集群的状态信息,可以通过连接任意节点读取或者写入数据(甚至是没有数据的空节点)。
  • (2)只有当集群中的大多数节点同时fail整个集群才fail
    一般情况下是集群当中超过一半以上的节点fail的时候,集群才会fail
  • (3)整个集群有16384个slot
    当需要在 Redis 集群中放置一个key-value 时,根据 CRC16(key) mod 16384的值,决定将一个key放到哪个桶中。
    读取一个key时也是相同的算法。
  • (4)当主节点fail时从节点会升级为主节点,fail的主节点online之后自动变成了从节点

Redis集群介绍

Redis 集群是一个提供在多个Redis间节点间共享数据的程序集。

Redis集群并不支持处理多个keys的命令,因为这需要在不同的节点间移动数据,从而达不到像Redis那样的性能,在高负载的情况下可能会导致不可预料的错误.

Redis 集群通过分区来提供一定程度的可用性,在实际环境中当某个节点宕机或者不可达的情况下继续处理命令. Redis 集群的优势:

  • 自动分割数据到不同的节点上。
  • 整个集群的部分节点失败或者不可达的情况下能够继续处理命令。

Redis 集群的数据分片

Redis 集群没有使用一致性hash, 而是引入了哈希槽的概念.

Redis 集群有16384个哈希槽,每个key通过CRC16校验后对16384取模来决定放置哪个槽.集群的每个节点负责一部分hash槽,举个例子,比如当前集群有3个节点,那么:

  • 节点 A 包含 0 到 5500号哈希槽.
  • 节点 B 包含5501 到 11000 号哈希槽.
  • 节点 C 包含11001 到 16384号哈希槽.

这种结构很容易添加或者删除节点. 比如如果我想新添加个节点D, 我需要从节点 A, B, C中得部分槽到D上. 如果我想移除节点A,需要将A中的槽移到B和C节点上,然后将没有任何槽的A节点从集群中移除即可. 由于从一个节点将哈希槽移动到另一个节点并不会停止服务,所以无论添加删除或者改变某个节点的哈希槽的数量都不会造成集群不可用的状态.

Redis集群的主从复制模型

为了使在部分节点失败或者大部分节点无法通信的情况下集群仍然可用,所以集群使用了主从复制模型,每个节点都会有N-1个复制品.

在我们例子中具有A,B,C三个节点的集群,在没有复制模型的情况下,如果节点B失败了,那么整个集群就会以为缺少5501-11000这个范围的槽而不可用.

然而如果在集群创建的时候(或者过一段时间)我们为每个节点添加一个从节点A1,B1,C1,那么整个集群便有三个master节点和三个slave节点组成,这样在节点B失败后,集群便会选举B1为新的主节点继续服务,整个集群便不会因为槽找不到而不可用了

不过当B和B1 都失败后,集群是不可用的.

Redis 一致性保证

Redis 并不能保证数据的强一致性. 这意味这在实际中集群在特定的条件下可能会丢失写操作.

  • 第一个原因是因为集群是用了异步复制. 写操作过程:
  • 客户端向主节点B写入一条命令.
  • 主节点B向客户端回复命令状态.
  • 主节点将写操作复制给他得从节点 B1, B2 和 B3.
  • 主节点对命令的复制工作发生在返回命令回复之后, 因为如果每次处理命令请求都需要等待复制操作完成的话, 那么主节点处理命令请求的速度将极大地降低 —— 我们必须在性能和一致性之间做出权衡。 注意:Redis 集群可能会在将来提供同步写的方法。Redis 集群另外一种可能会丢失命令的情况是集群出现了网络分区, 并且一个客户端与至少包括一个主节点在内的少数实例被孤立
  • 举个例子 假设集群包含 A 、 B 、 C 、 A1 、 B1 、 C1 六个节点, 其中 A 、B 、C 为主节点, A1 、B1 、C1 为A,B,C的从节点, 还有一个客户端 Z1, 假设集群中发生网络分区,那么集群可能会分为两方,大部分的一方包含节点 A 、C 、A1 、B1 和 C1 ,小部分的一方则包含节点 B 和客户端 Z1 。Z1仍然能够向主节点B中写入, 如果网络分区发生时间较短,那么集群将会继续正常运作,如果分区的时间足够让大部分的一方将B1选举为新的master,那么Z1写入B中得数据便丢失了.
  • 注意, 在网络分裂出现期间, 客户端 Z1 可以向主节点 B 发送写命令的最大时间是有限制的, 这一时间限制称为节点超时时间(node timeout), 是 Redis 集群的一个重要的配置选项。

搭建并使用Redis集群

  • overcommit_memory是什么?

overcommit_memory是一个内核对内存分配的一种策略。 具体可见/proc/sys/vm/overcommit_memory下的值

overcommit_memory有什么作用?
overcommit_memory取值又三种分别为0, 1, 2
overcommit_memory=0, 表示内核将检查是否有足够的可用内存供应用进程使用;
如果有足够的可用内存,内存申请允许;否则,内存申请失败,并把错误返回给应用进程。
overcommit_memory=1, 表示内核允许分配所有的物理内存,而不管当前的内存状态如何。
overcommit_memory=2, 表示内核允许分配超过所有物理内存和交换空间总和的内存

进行实验之前,首先修改内核的内存策略。

内核的内存策略 设置为1 意思是直接放行 因为fork的时候大量占内存 如果内存不够会被kill掉
[root@server1 ~]# cd /proc/sys/vm/
[root@server1 vm]# cat overcommit_memory    #默认为0
0
[root@server1 vm]# echo 1 > overcommit_memory    #设置为1
[root@server1 vm]# cat overcommit_memory 
1

Redis Cluster集群的介绍以及搭建_第1张图片

搭建集群

  • 首先, 让我们建立一个新目录, 并创建六个以端口号为名字的子目录, 稍后我们在将每个目录中运行一个 Redis 实例: 命令如下:
[root@server1 ~]# cd /usr/local/
[root@server1 local]# mkdir redis-cluster
[root@server1 local]# cd redis-cluster/
[root@server1 redis-cluster]# mkdir 700{1..6}
[root@server1 redis-cluster]# ls
7001  7002  7003  7004  7005  7006
  • 在目录 7001 至 7006 中, 各创建一个 redis.conf 文件, 文件的内容编辑为以下, 但记得将配置中的端口号从 7001 改为与目录名字相同的号码。
[root@server1 redis-cluster]# cd 7001/
[root@server1 7001]# vim redis.conf

port 7001
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes
daemonize yes
  • 上述文件中, cluster-enabled 选项用于开实例的集群模式, 而 cluster-conf-file 选项则设定了保存节点配置文件的路径, 默认值为 nodes.conf节点配置文件,无须人为修改, 它由 Redis 集群在启动时创建, 并在有需要时自动进行更新。
    要让集群正常运作至少需要三个主节点,不过在刚开始试用集群功能时, 强烈建议使用六个节点: 其中三个为主节点, 而其余三个则是各个主节点的从节点。
  • 使用以下命令, 在每个标签页中打开一个实例:
[root@server1 7001]# redis-server ./redis.conf 
1250:C 15 Aug 2019 10:39:18.205 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
1250:C 15 Aug 2019 10:39:18.205 # Redis version=5.0.3, bits=64, commit=00000000, modified=0, pid=1250, just started
1250:C 15 Aug 2019 10:39:18.205 # Configuration loaded
[root@server1 7001]# ps ax
  • 下图中,我们将6个节点(6个实例已经全部打开)
    Redis Cluster集群的介绍以及搭建_第2张图片

查看帮助:[root@server1 7006]# redis-cli --help

  • 现在我们已经有了六个正在运行中的 Redis 实例, 接下来我们需要使用这些实例来创建集群,并为每个节点编写配置文件。这个命令在这里用于创建一个新的集群选项–replicas 1 表示我们希望为集群中的每个主节点创建一个从节点。之后跟着的其他参数则是这个集群实例的地址列表,3个master3个slave
[root@server1 7006]# 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
  • redis-trib 会打印出一份配置, 如果觉得没问题的话, 就可以输入 yes , redis-trib 就会将这份配置应用到集群当中,让各个节点开始互相通讯,最后可以得到如下信息:
    Redis Cluster集群的介绍以及搭建_第3张图片
    Redis Cluster集群的介绍以及搭建_第4张图片
  • 上图表示集群中的 16384 个槽都有至少一个主节点在处理, 集群运作正常。

模拟集群down掉的两种情况

第一种情况

当哈希槽的数量不够时,整个集群会down掉,数据库中的数据无法查询。

  • 我们先来查询每个master节点对应的slave是谁。下图表示server1是master,他的slave是server4
[root@server1 7006]# redis-cli -c -p 7001      #默认为本机localhost,所以只用加端口就行。
127.0.0.1:7001> info

Redis Cluster集群的介绍以及搭建_第5张图片

  • 下图查询结果显示server2是master,他对应的slave是sever5。
[root@server1 7006]# redis-cli -c -p 7002
127.0.0.1:7002> info

Redis Cluster集群的介绍以及搭建_第6张图片
所以本次实验的master——slave对应关系如下:
server1——server4
server2——server5
server3——server6

  • 登陆server2(master)后,向数据库中插入数据,并查询是否插入成功。此时,我们发现无论登陆哪一个节点都可以查询到刚插入的数据。
127.0.0.1:7002> set name zyw
OK
127.0.0.1:7002> get name
"zyw"

[root@server1 7006]# redis-cli -c -p 7004    #任何一个节点都可以查询到数据。
127.0.0.1:7004> get name
-> Redirected to slot [5798] located at 127.0.0.1:7002
"zyw"

Redis Cluster集群的介绍以及搭建_第7张图片

  • 查看帮助:[root@server1 7006]# redis-cli --cluster help
  • 我们可以通过下面两条命令查看集群中节点的具体信息,此时主从状态正常。且server2中有一对键值对。
[root@server1 7006]# redis-cli --cluster check 127.0.0.1:7001
[root@server1 7006]# redis-cli --cluster info 127.0.0.1:7001

Redis Cluster集群的介绍以及搭建_第8张图片
Redis Cluster集群的介绍以及搭建_第9张图片

  • 我们接下来关闭刚才存入数据的server2(master)节点,并且查看进程确认它是否成功关闭。
[root@server1 7006]# redis-cli -p 7002
127.0.0.1:7002> shutdown

[root@server1 7006]# ps ax

Redis Cluster集群的介绍以及搭建_第10张图片

  • server2关闭成功,查询整个集群的状态,状态正常,这是因为此时server5已经变为了新的master(原来server2的slave),且键值对现在在新master(server5)上。哈希槽的数量也正常。
[root@server1 7006]# redis-cli --cluster info 127.0.0.1:7001
[root@server1 7006]# redis-cli --cluster check 127.0.0.1:7001

Redis Cluster集群的介绍以及搭建_第11张图片

Redis Cluster集群的介绍以及搭建_第12张图片

  • 集群状态正常,所以此时登陆任意一个节点依然可以查询到数据。
[root@server1 7006]# redis-cli -c -p 7001
127.0.0.1:7001> get name

Redis Cluster集群的介绍以及搭建_第13张图片

  • 然后我们再down掉server5(新master),查看进程确认server5被成功down掉。
[root@server1 7006]# redis-cli -c -p 7005
127.0.0.1:7005> shutdown
not connected> 

Redis Cluster集群的介绍以及搭建_第14张图片

  • 查看此时集群的状态,集群此时两主两从,哈希槽的状态异常,因为缺少了一个主,数量不够。
[root@server1 7006]# redis-cli --cluster check 127.0.0.1:7001 
[root@server1 7006]# redis-cli --cluster info 127.0.0.1:7001

Redis Cluster集群的介绍以及搭建_第15张图片
Redis Cluster集群的介绍以及搭建_第16张图片

  • 登陆,当我们再次查询数据的时候,并不能查询到,因为此时显示整个集群已经down掉了。
[root@server1 7006]# redis-cli -c -p 7001
127.0.0.1:7001> get name
(error) CLUSTERDOWN The cluster is down
127.0.0.1:7001> 

解决办法

  • 我们进入server2的目录7002下重新运行sever2的实例,因为server5变为了master,所以server2重启后是slave,此时集群中2个master3个slave,哈希槽的数量不够,所以依旧查询不到数据。
[root@server1 7006]# cd ../7002/
[root@server1 7002]# redis-server redis.conf

[root@server1 7002]# redis-cli -c -p 7001
127.0.0.1:7001> get name
(error) CLUSTERDOWN The cluster is down
127.0.0.1:7001> 

Redis Cluster集群的介绍以及搭建_第17张图片

  • 当我们重新运作server5之后,集群恢复,数据查询成功。
[root@server1 7004]# cd ../7005/
[root@server1 7005]# redis-server redis.conf

Redis Cluster集群的介绍以及搭建_第18张图片

  • 查看此时集群的状态,3主3从,哈希槽数量正常,集群状态正常。
[root@server1 7005]# redis-cli --cluster check 127.0.0.1:7001

Redis Cluster集群的介绍以及搭建_第19张图片

第二种情况

当同时down掉一半以上的master时,整个集群也会down掉。

  • 首先查询此时集群中master在哪个节点上,然后关闭两个节点的服务。
[root@server1 7005]# redis-cli  -p 7001 shutdown
[root@server1 7005]# redis-cli  -p 7003 shutdown
  • 查询此时集群的状态,1主3从。
[root@server1 7005]# redis-cli --cluster check 127.0.0.1:7002 
[root@server1 7005]# redis-cli --cluster info 127.0.0.1:7002

Redis Cluster集群的介绍以及搭建_第20张图片

  • 登陆后查询数据,可以看到查询失败,因为整个集群已经down掉了。(个人觉得这种情况的最终原因也是因为哈希槽的数量不够)
    Redis Cluster集群的介绍以及搭建_第21张图片

解决办法

  • 同样的,再次进入相应的目录中运行,集群恢复正常,查询成功。
[root@server1 7005]# cd ../7001/
[root@server1 7001]# redis-server redis.conf 
[root@server1 7001]# cd ../7003/
[root@server1 7003]# redis-server redis.conf 

[root@server1 7003]# redis-cli --cluster check 127.0.0.1:7002
[root@server1 7003]# redis-cli -c -p 7006
127.0.0.1:7006> get name
-> Redirected to slot [5798] located at 127.0.0.1:7005
"zyw"

Redis Cluster集群的介绍以及搭建_第22张图片

脚本方式创建和管理集群

我们也可以使用脚本的方式来创建和管理集群,这种方式更加的便捷。

  • 在解压后的目录下执行脚本。
[root@server2 ~]# cd redis-5.0.3
[root@server2 redis-5.0.3]# cd utils/
[root@server2 utils]# cd create-cluster/
[root@server2 create-cluster]# pwd
/root/redis-5.0.3/utils/create-cluster
[root@server2 create-cluster]# ./create-cluster start   #执行脚本
[root@server2 create-cluster]# ps ax

Redis Cluster集群的介绍以及搭建_第23张图片
Redis Cluster集群的介绍以及搭建_第24张图片

  • 创建集群,并查看此时集群的状态。
[root@server2 create-cluster]# ./create-cluster create

Redis Cluster集群的介绍以及搭建_第25张图片
Redis Cluster集群的介绍以及搭建_第26张图片

  • 为了便于我们将某一节点的服务重新开启,我们根据脚本文件自己写一个脚本,执行我们脚本时,后面加的端口号就是对应的要开启的节点的端口号。
[root@server2 create-cluster]# vim create-cluster 
[root@server2 create-cluster]# vim cluster_status.sh
PORT=$1
TIMEOUT=2000
NODES=6
REPLICAS=1

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
  • 例如:通过执行脚本来开启30001端口(server1)的redis
[root@server2 create-cluster]# sh cluster_status.sh 30001

Redis Cluster集群的介绍以及搭建_第27张图片

你可能感兴趣的:(Redis)