测试环境两台:
下面开始集群的搭建和管理:首先介绍一下我们的实验环境
对于少数一方, 如果一个主节点未能在节点超时时间所设定的时限内重新联系上集群, 那么它将停止处理写命令, 并向客户端报告错误。
对于大多数一方来说, 如果一个主节点未能在节点超时时间所设定的时限内重新联系上集群, 那么集群会将这个主节点视为下线, 并使用从节点来代替这个主节点继续工作。
注意, 在网络分裂出现期间, 客户端 Z1 可以向主节点 B 发送写命令的最大时间是有限制的, 这一时间限制称为节点超时时间(node timeout), 是 Redis 集群的一个重要的配置选项:
但是, 如果网络分裂出现的时间足够长, 使得大多数一方将从节点 B1 设置为新的主节点, 并使用 B1 来代替原来的主节点 B , 那么 Z1 发送给主节点 B 的写命令将丢失。
如果网络分裂出现的时间很短, 那么集群会继续正常运行;
在网络分裂期间, 主节点 B 仍然会接受 Z1 发送的写命令:
假设集群中发生网络分裂, 那么集群可能会分裂为两方, 大多数(majority)的一方包含节点 A 、C 、A1 、B1 和 C1 , 而少数(minority)的一方则包含节点 B 和客户端 Z1 。
举个例子, 假设集群包含 A 、 B 、 C 、 A1 、 B1 、 C1 六个节点, 其中 A 、B 、C 为主节点, 而 A1 、B1 、C1 分别为三个主节点的从节点, 另外还有一个客户端 Z1 。
Redis 集群另外一种可能会丢失命令的情况是, 集群出现网络分裂(network partition), 并且一个客户端与至少包括一个主节点在内的少数(minority)实例被孤立。
如你所见, 主节点对命令的复制工作发生在返回命令回复之后, 因为如果每次处理命令请求都需要等待复制操作完成的话, 那么主节点处理命令请求的速度将极大地降低 —— 我们必须在性能和一致性之间做出权衡。
主节点 B 将刚刚执行的写命令复制给它的从节点 B1 、 B2 和 B3 。
主节点 B 执行写命令,并向客户端返回命令回复。
客户端向主节点 B 发送一条写命令。
使用异步复制(asynchronous replication)是 Redis 集群可能会丢失写命令的其中一个原因。 考虑以下这个写命令的例子:
Redis 集群不保证数据的强一致性(strong consistency): 在特定条件下, Redis 集群可能会丢失已经被执行过的写命令。
redis 集群的数据一致性:
不过如果节点 B 和 B1 都下线的话, Redis 集群还是会停止运作。
另一方面, 假如在创建集群的时候(或者至少在节点 B 下线之前), 我们为主节点 B 添加了从节点 B1 , 那么当主节点 B 下线的时候, 集群就会将 B1 设置为新的主节点, 并让它代替下线的主节点 B , 继续处理 5501 号至 11000 号的哈希槽, 这样集群就不会因为主节点 B 的下线而无法正常运作了。
在之前列举的节点 A 、B 、C 的例子中, 如果节点 B 下线了, 那么集群将无法正常运行, 因为集群找不到节点来处理 5501 号至 11000 号的哈希槽。
为了使得集群在一部分节点下线或者无法与集群的大多数(majority)节点进行通讯的情况下, 仍然可以正常运作, Redis 集群对节点使用了主从复制功能: 集群中的每个节点都有 1 个至 N 个复制品(replica), 其中一个复制品为主节点(master), 而其余的 N-1 个复制品为从节点(slave)。
redis 集群中的主从复制:
因为将一个哈希槽从一个节点移动到另一个节点不会造成节点阻塞, 所以无论是添加新节点还是移除已存在节点, 又或者改变某个节点包含的哈希槽数量, 都不会造成集群下线。
与此类似, 如果用户要从集群中移除节点 A , 那么集群只需要将节点 A 中的所有哈希槽移动到节点 B 和节点 C , 然后再移除空白(不包含任何哈希槽)的节点 A 就可以了。
如果用户将新节点 D 添加到集群中, 那么集群只需要将节点 A 、B 、 C 中的某些槽移动到节点 D 就可以了。
这种将哈希槽分布到不同节点的做法使得用户可以很容易地向集群中添加或者删除节点。 比如说:
节点 C 负责处理 11001 号至 16384 号哈希槽。
节点 B 负责处理 5501 号至 11000 号哈希槽。
节点 A 负责处理 0 号至 5500 号哈希槽。
集群中的每个节点负责处理一部分哈希槽。 举个例子, 一个集群可以有三个哈希槽, 其中:
Redis 集群使用数据分片(sharding)而非一致性哈希(consistency hashing)来实现: 一个 Redis 集群包含 16384 个哈希槽(hash slot), 数据库中的每个键都属于这 16384 个哈希槽的其中一个, 集群使用公式 CRC16(key) % 16384 来计算键 key 属于哪个槽, 其中 CRC16(key) 语句用于计算键 key 的 CRC16 校验和 。
redis 集群数据共享:
当集群中的一部分节点失效或者无法进行通讯时, 仍然可以继续处理命令请求的能力。
将数据自动切分(split)到多个节点的能力。
Redis 集群提供了以下两个好处:
Redis 集群通过分区(partition)来提供一定程度的可用性(availability): 即使集群中有一部分节点失效或者无法进行通讯, 集群也可以继续处理命令请求。
Redis 集群不支持那些需要同时处理多个键的 Redis 命令, 因为执行这些命令需要在多个 Redis 节点之间移动数据, 并且在高负载的情况下, 这些命令将降低 Redis 集群的性能, 并导致不可预测的行为。
Redis 集群是一个可以在多个 Redis 节点之间进行数据共享的设施(installation)。
集群简介:
- server1:172.16.16.34
- server2:172.16.16.35
- redis版本:redis3.2
搭建环境:redis 集群,server1 有 7001,7002,7003 三主,server2 有 7001,7002,7003 三从,总共六个节点。这样做是为了保证 redis 的集群的高可用。redis 的复制也是采用异步复制的方式。
1,安装 redis
- cd /home/maxiangqian
- tar xzf redis-3.2.8.tar.gz
- cd redis-3.2.8
- yum install gcc
- make
2:创建 redis 目录文件夹
在 server1 和 server2 上都创建相应的文件夹:
- mkdir /home/redis7001/data
- mkdir -p /home/redis7001/data /home/redis7001/log /home/redis7001/tmp
- mkdir -p /home/redis7002/data /home/redis7002/log /home/redis7002/tmp
- mkdir -p /home/redis7003/data /home/redis7003/log /home/redis7003/tmp
3:为 server1 和 server2 的三个节点分别配置配置文件
以一个配置文件为例:
- port7001
- timeout 300
- daemonize yes
- pidfile "/home/redis7001/tmp/redis_7001.pid"
- loglevel notice
- logfile "/home/redis7001/log/redis_7001.log"
- databases 16
- save 900 1
- save 300 10
- save 60 10000
- stop-writes-on-bgsave-error yes
- rdbcompression yes
- rdbchecksum yes
- dbfilename "dump.rdb"
- dir "/home/redis7001/data"
- slave-serve-stale-data yes
- #slave-read-only yes # yes开启从库只读
- repl-diskless-sync no
- repl-diskless-sync-delay5
- repl-disable-tcp-nodelay no
- slave-priority100
- appendonly yes
- #appendfilename "appendonly.aof"
- appendfsync everysec
- no-appendfsync-on-rewrite no
- auto-aof-rewrite-percentage100
- auto-aof-rewrite-min-size 64mb
- lua-time-limit5000
- slowlog-log-slower-than10000
- slowlog-max-len128
- latency-monitor-threshold0
- requirepass "maxiangqianredis"
- masterauth "maxiangqianredis"
- #cluster
- cluster-enabled yes
- cluster-config-file /home/redis7001/nodes7001.conf
- cluster-node-timeout5000
上面是 redis7001 的配置文件内容
然后启动 7001 的 redis:
- redis-server /home/redis7001/redis7001.conf
我们看一下启动日志:
- 1574 : M 03 May 16 : 22 : 53.444 * No cluster configuration found,
- I 'm 363ecec54c92c2548dcab016146bdb4c104e5e84'
每个实例都会为自己生成一个唯一的 ID,用来识别集群中的唯一身份。
然后使用同样的方法启动其余五个实例
- server17001
- server1 7002
- server1 7003
- server2 7001
- server2 7002
- server2 7003
OK,现在已经有六个已经启动的 redis 实例了。我们下一步开始做集群
4:开始创建集群
- redis-trib.rb create --replicas1 10.103.16.34:7001 10.103.16.34:7002 10.103.16.34:7003 10.103.16.35:7001 10.103.16.35:7002 10.103.16.35:7003
执行报错:
- /usr/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:31:in`gem_original_require': no such file to load -- redis (LoadError)
- from/usr/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:31:in`require'
- from/home/maxiangqian/redis-3.2.8/src/redis-trib.rb:25
我们需要安装以下几个包:
- yum -y install zlib ruby rubygems
- gem install redis
然后重新启动创建集群的操作:
- [root@localhost redis7003]# redis-trib.rb create --replicas1 10.103.16.34:7001 10.103.16.34:7002 10.103.16.34:7003 10.103.16.35:7001 10.103.16.35:7002 10.103.16.35:7003>>> Creating cluster
- [ERR] Sorry, can't connect to node 10.103.16.34:7001
又报错了我擦。
网上各种搜资料咨询,最好还是发现不是什么版本问题,是因为我的配置文件里加了以下两行配置:
- requirepass"maxiangqianredis"
- masterauth "maxiangqianredis"
群集是不支持认证的,把这两行注释掉就好了,然后我们在执行创建群集的命令:
- [root@localhost redis7003]# redis-trib.rb create --replicas1 10.103.16.34:7001 10.103.16.34:7002 10.103.16.34:7003 10.103.16.35:7001 10.103.16.35:7002 10.103.16.35:7003>>> Creating cluster
- >>> Performing hash slots allocation on6 nodes...
- Using 3 masters:
- 10.103.16.35:7001
- 10.103.16.34:7001
- 10.103.16.35:7002
- Adding replica 10.103.16.34:7002to10.103.16.35:7001
- Adding replica 10.103.16.35:7003to10.103.16.34:7001
- Adding replica 10.103.16.34:7003to10.103.16.35:7002
- M: 363ecec54c92c2548dcab016146bdb4c104e5e84 10.103.16.34:7001
- slots:5461-10922(5462 slots) master
- S: 93a0e8d405959480fcbd310a5d15a92346c69d43 10.103.16.34:7002
- replicates d015a22abc57c021f568973f4f1c03c7a5c7b772
- S: 78f77749f9f9a5f0d7c99427e0311912a3fa04e7 10.103.16.34:7003
- replicates 89147e5837e378b69233dd2b8290267975719bc4
- M: d015a22abc57c021f568973f4f1c03c7a5c7b772 10.103.16.35:7001
- slots:0-5460(5461 slots) master
- M: 89147e5837e378b69233dd2b8290267975719bc4 10.103.16.35:7002
- slots:10923-16383(5461 slots) master
- S: ce9d635236567ccde4c864f78863fa0a4b26f25a 10.103.16.35:7003
- replicates 363ecec54c92c2548dcab016146bdb4c104e5e84
- Can I setthe above configuration? (type'yes'to accept):
OK,已经提示成功了,我们直接选择 yes 就好了。
- >>> Nodes configuration updated
- >>> Assign a different config epoch to each node
- >>> Sending CLUSTER MEET messages to join the cluster
- Waiting for the cluster to join..
- >>> Performing Cluster Check (usingnode10.103.16.34:7001)
- M: 363ecec54c92c2548dcab016146bdb4c104e5e84 10.103.16.34:7001
- slots:5461-10922(5462 slots) master
- 1 additional replica(s)
- S: 78f77749f9f9a5f0d7c99427e0311912a3fa04e7 10.103.16.34:7003
- slots: (0 slots) slave
- replicates 89147e5837e378b69233dd2b8290267975719bc4
- M: d015a22abc57c021f568973f4f1c03c7a5c7b772 10.103.16.35:7001
- slots:0-5460(5461 slots) master
- 1 additional replica(s)
- M: 89147e5837e378b69233dd2b8290267975719bc4 10.103.16.35:7002
- slots:10923-16383(5461 slots) master
- 1 additional replica(s)
- S: ce9d635236567ccde4c864f78863fa0a4b26f25a 10.103.16.35:7003
- slots: (0 slots) slave
- replicates 363ecec54c92c2548dcab016146bdb4c104e5e84
- S: 93a0e8d405959480fcbd310a5d15a92346c69d43 10.103.16.34:7002
- slots: (0 slots) slave
- replicates d015a22abc57c021f568973f4f1c03c7a5c7b772
- [OK] All nodes agree about slots configuration.
- >>> Checkfor open slots...
- >>> Check slots coverage...
- [OK] All 16384slots covered.
这样群集就设置成功了。
在 10.103.16.34:7001 创建 name 测试字符串,然后验证
查看一下集群的状态,测试一下:
- [root@mxqmongodb2 sa]# redis-cli -c -p7001
- 127.0.0.1:7001>get name
- -> Redirected to slot [5798] located at10.103.16.34:7001
- "txt"
- 10.103.16.34:7001> exit
- [root@mxqmongodb2 sa]# redis-cli -c -p7002
- 127.0.0.1:7002>get name
- -> Redirected to slot [5798] located at10.103.16.34:7001
- "txt"
- 10.103.16.34:7001> exit
- [root@mxqmongodb2 sa]# redis-cli -c -p7003
- 127.0.0.1:7003>get name
- -> Redirected to slot [5798] located at10.103.16.34:7001
- "txt"
5:我们接下来查看一下集群的基本信息:
- [root@localhost redis7003]# redis-cli -p7001 cluster nodes
- 78f77749f9f9a5f0d7c99427e0311912a3fa04e7 10.103.16.34:7003slave 89147e5837e378b69233dd2b8290267975719bc40 1493879665448 5 connected
- d015a22abc57c021f568973f4f1c03c7a5c7b772 10.103.16.35:7001master -0 1493879663946 4connected0-5460
- 89147e5837e378b69233dd2b8290267975719bc4 10.103.16.35:7002master -0 1493879664948 5connected10923-16383
- ce9d635236567ccde4c864f78863fa0a4b26f25a 10.103.16.35:7003slave 363ecec54c92c2548dcab016146bdb4c104e5e840 1493879665949 6 connected
- 93a0e8d405959480fcbd310a5d15a92346c69d43 10.103.16.34:7002slave d015a22abc57c021f568973f4f1c03c7a5c7b7720 1493879664446 4 connected
- 363ecec54c92c2548dcab016146bdb4c104e5e84 10.103.16.34:7001myself,master -0 0 1connected5461-10922
可以看到现在的集群有六个节点,三个主节点和三个从节点。而且每个主节点都会记录自己分配的哈希槽,从中我们可以看到
- 103.16.35:7001master -0 1493879663946 4connected0-5460
- 10.103.16.34:7001myself,master -0 0 1connected5461-10922
- 10.103.16.35:7002master -0 1493879664948 5connected10923-16383
当然我们也可以对这些节点的哈希槽进行重新的分配,我们现在打算将 103.16.35:7001 的前 100 个哈希槽移动到 10.103.16.34:7001
- [root@localhost redis7003]# redis-trib.rb reshard10.103.16.34:7001
然后会提示我输入数值以及从哪里迁移到哪里:
- How many slotsdoyou want to move (from 1to16384)100
- What isthe receiving node ID 363ecec54c92c2548dcab016146bdb4c104e5e84
- Please enter all the source node IDs.
- Type 'all'to use all the nodesassource nodesfor the hash slots.
- Type 'done' once you entered all the source nodes IDs.
- Source node #1:d015a22abc57c021f568973f4f1c03c7a5c7b772
- Source node #2:done
执行完以后就可以进行迁移了,迁移完以后我们再打印出来节点信息看一下:
[root@localhost redis7003]# redis-cli -p7001cluster nodes78f77749f9f9a5f0d7c99427e0311912a3fa04e710.103.16.34:7003slave 89147e5837e378b69233dd2b8290267975719bc4014938811679655connectedd015a22abc57c021f568973f4f1c03c7a5c7b77210.103.16.35:7001master -014938811664604connected101-546089147e5837e378b69233dd2b8290267975719bc410.103.16.35:7002master -014938811669625connected10923-16383ce9d635236567ccde4c864f78863fa0a4b26f25a10.103.16.35:7003slave 363ecec54c92c2548dcab016146bdb4c104e5e84014938811674657connected93a0e8d405959480fcbd310a5d15a92346c69d4310.103.16.34:7002slave d015a22abc57c021f568973f4f1c03c7a5c7b772014938811679654connected363ecec54c92c2548dcab016146bdb4c104e5e8410.103.16.34:7001myself,master -007connected0-1005461-10922我们可以很清楚的看到已经迁移成功了。
首先我们要看一下集群的主节点信息:
6:我们来测试一下集群的故障转移功能
- [root@localhost redis7003]# redis-cli -p7001cluster nodes | grep master
- d015a22abc57c021f568973f4f1c03c7a5c7b772 10.103.16.35:7001master -0 1493883826713 4connected101-5460
- 89147e5837e378b69233dd2b8290267975719bc4 10.103.16.35:7002master -0 1493883827213 5connected10923-16383
- 363ecec54c92c2548dcab016146bdb4c104e5e84 10.103.16.34:7001myself,master -0 0 7connected0-100 5461-10922
我们现在要使 10.103.16.35:7001 这个主节点断掉,然后重启看一下基本信息
- [root@mxqmongodb2 sa]# /home/maxiangqian/redis-3.2.8/src/redis-cli -p7001
- 127.0.0.1:7001> SHUTDOWN
- not connected> exit
- [root@mxqmongodb2 sa]# redis-server /home/redis7001/redis7001.conf
然后再打印一下集群信息看一下:
- [root@localhost redis7003]# redis-cli -p7001 cluster nodes
- 78f77749f9f9a5f0d7c99427e0311912a3fa04e7 10.103.16.34:7003slave 89147e5837e378b69233dd2b8290267975719bc40 1493884247801 5 connected
- d015a22abc57c021f568973f4f1c03c7a5c7b772 10.103.16.35:7001slave 93a0e8d405959480fcbd310a5d15a92346c69d430 1493884247300 8 connected
- 89147e5837e378b69233dd2b8290267975719bc4 10.103.16.35:7002master -0 1493884246798 5connected10923-16383
- ce9d635236567ccde4c864f78863fa0a4b26f25a 10.103.16.35:7003slave 363ecec54c92c2548dcab016146bdb4c104e5e840 1493884246298 7 connected
- 93a0e8d405959480fcbd310a5d15a92346c69d43 10.103.16.34:7002master -0 1493884248301 8connected101-5460
- 363ecec54c92c2548dcab016146bdb4c104e5e84 10.103.16.34:7001myself,master -0 0 7connected0-100 5461-10922
通过信息我们可以很明显的看到了 10.103.16.35:7001 这个主节点已经变成了从节点,而本身他的从节点也上升为主节点了。
主节点:
我们先看一下怎么添加节点,添加节点分为两类(主节点或者从节点)
7:集群的节点管理:
但是我们需要注意的是在故障转移的时间段内,一些 10.103.16.35:7001 的写操作是会丢失的。直到他的从库提升为主库为止,这是 redis 为了保证数据一致性而采取的措施。
- ./redis-trib.rb add-node10.103.16.34:7004 10.103.16.34:7001
这样我们就把 10.103.16.34:7004 添加为集群的新的主节点,不过我们要注意的是,这时候他仅仅是一个没有哈希槽的主节点,并不会存储任何数据。
从节点:
我们可以使用 redis-trib 程序, 将集群中的某些哈希桶移动到新节点里面, 新节点就会成为真正的主节点了。
- ./redis-trib.rb add-node10.103.16.34:7004 10.103.16.34:7001
- redis 10.103.16.34::7004> cluster replicate 3c3a0c74aae0b56170ccb03a76b60cfe7dc1912e
将新节点指定为 ID 为 3c3a0c74aae0b56170ccb03a76b60cfe7dc1912e 的从节点。
接下来我们看一下怎么移除某个节点,语法格式如下:
- ./redis-trib del-node127.0.0.1:7000``
但是我们要注意一点,移除主节点的时候必须保证主节点是空的,也就是事先将要移除的主节点的哈希槽给转移到其他的主节点上。
来源: http://www.linuxidc.com/Linux/2017-05/144178.htm