Redis 集群教程
本文档是Redis集群的通常介绍,没有涉及复杂难懂的分布式概念的赘述,只是提供了从用户角度来如何搭建测试以及使用的方法,若是你打算使用并深刻了解Redis集群,推荐阅读完本章节后,仔细阅读 Redis 集群规范 一章。
本教程试图提供最终用户一个简单的关于集群和一致性特征的描述
请注意,本教程使用于Redis3.0(包括3.0)以上版本
若是你计划部署集群,那么咱们建议你从阅读这个文档开始。
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集群
搭建集群的第一件事情咱们须要一些运行在 集群模式的Redis实例. 这意味这集群并非由一些普通的Redis实例组成的,集群模式须要经过配置启用,开启集群模式后的Redis实例即可以使用集群特有的命令和特性了.
下面是一个最少选项的集群的配置文件:java
port 7000
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yesnode
文件中的 cluster-enabled 选项用于开实例的集群模式, 而 cluster-conf-file 选项则设定了保存节点配置文件的路径, 默认值为 nodes.conf.节点配置文件无须人为修改, 它由 Redis 集群在启动时建立, 并在有须要时自动进行更新。
要让集群正常运做至少须要三个主节点,不过在刚开始试用集群功能时, 强烈建议使用六个节点: 其中三个为主节点, 而其他三个则是各个主节点的从节点。
首先, 让咱们进入一个新目录, 并建立六个以端口号为名字的子目录, 稍后咱们在将每一个目录中运行一个 Redis 实例:命令以下:git
mkdir cluster-test
cd cluster-test
mkdir 7000 7001 7002 7003 7004 7005github
在文件夹 7000 至 7005 中, 各建立一个 redis.conf 文件, 文件的内容可使用上面的示例配置文件, 但记得将配置中的端口号从 7000 改成与文件夹名字相同的号码。
从 Redis Github 页面 的 unstable 分支中取出最新的 Redis 源码, 编译出可执行文件 redis-server , 并将文件复制到 cluster-test 文件夹, 而后使用相似如下命令, 在每一个标签页中打开一个实例:redis
cd 7000
../redis-server ./redis.conf数据库
实例打印的日志显示, 由于 nodes.conf 文件不存在, 因此每一个节点都为它自身指定了一个新的 ID :vim
[82462] 26 Nov 11:56:55.329 * No cluster configuration found, I'm 97a3a64667477371c4479320d683e4c8db5858b1api
实例会一直使用同一个 ID , 从而在集群中保持一个独一无二(unique)的名字。
搭建集群
如今咱们已经有了六个正在运行中的 Redis 实例, 接下来咱们须要使用这些实例来建立集群, 并为每一个节点编写配置文件。
经过使用 Redis 集群命令行工具 redis-trib , 编写节点配置文件的工做能够很是容易地完成: redis-trib 位于 Redis 源码的 src 文件夹中, 它是一个 Ruby 程序, 这个程序经过向实例发送特殊命令来完成建立新集群, 检查集群, 或者对集群进行从新分片(reshared)等工做。缓存
./redis-trib.rb create --replicas 1 127.0.0.1:7000 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安全
这个命令在这里用于建立一个新的集群, 选项–replicas 1 表示咱们但愿为集群中的每一个主节点建立一个从节点。
以后跟着的其余参数则是这个集群实例的地址列表,3个master3个slaveredis-trib 会打印出一份预想中的配置给你看, 若是你以为没问题的话, 就能够输入 yes , redis-trib 就会将这份配置应用到集群当中,让各个节点开始互相通信,最后能够获得以下信息:
[OK] All 16384 slots covered
这表示集群中的 16384 个槽都有至少一个主节点在处理, 集群运做正常。
Creating a Redis Cluster using the create-cluster script
If you don’t want to create a Redis Cluster by configuring and executingindividual instances manually as explained above, there is a much simplersystem (but you’ll not learn the same amount of operational details).
Just check utils/create-cluster directory in the Redis distribution.There is a script called create-cluster inside (same name as the directoryit is contained into), it’s a simple bash script. In order to starta 6 nodes cluster with 3 masters and 3 slaves just type the followingcommands:
create-cluster start
create-cluster create
Reply to yes in step 2 when the redis-trib utility wants you to acceptthe cluster layout.
You can now interact with the cluster, the first node will start at port 30001by default. When you are done, stop the cluster with:
create-cluster stop.
Please read the README inside this directory for more information on howto run the script.
使用集群
Redis 集群现阶段的一个问题是客户端实现不多。
如下是一些我知道的实现:
redis-rb-cluster 是我(@antirez)编写的 Ruby 实现, 用于做为其余实现的参考。 该实现是对 redis-rb 的一个简单包装, 高效地实现了与集群进行通信所需的最少语义(semantic).
redis-py-cluster 看上去是 redis-rb-cluster 的一个 Python 版本, 这个项目有一段时间没有更新了(最后一次提交是在六个月以前), 不过能够将这个项目用做学习集群的起点。
流行的 Predis 曾经对早期的 Redis 集群有过必定的支持, 但我不肯定它对集群的支持是否完整, 也不清楚它是否和最新版本的 Redis 集群兼容 (由于新版的 Redis 集群将槽的数量从 4k 改成 16k 了).
使用最多的时java客户端, Jedis 最近添加了对集群的支持, 详细请查看项目README中Jedis Cluster部分.
StackExchange.Redis 提供对 C# 的支持(而且包括大部分 .NET 下面的语言,好比: VB, F#等等)
thunk-redis 提供对 Node.js 和 io.js的支持。
Redis unstable 分支中的 redis-cli 程序实现了很是基本的集群支持, 可使用命令 redis-cli -c 来启动。
测试 Redis 集群比较简单的办法就是使用 redis-rb-cluster 或者 redis-cli , 接下来咱们将使用 redis-cli 为例来进行演示:
$ redis-cli -c -p 7000
redis 127.0.0.1:7000> set foo bar
-> Redirected to slot [12182] located at 127.0.0.1:7002
OK
redis 127.0.0.1:7002> set hello world
-> Redirected to slot [866] located at 127.0.0.1:7000
OK
redis 127.0.0.1:7000> get foo
-> Redirected to slot [12182] located at 127.0.0.1:7002
"bar"
redis 127.0.0.1:7000> get hello
-> Redirected to slot [866] located at 127.0.0.1:7000
"world"
注意: 若是你是使用脚本建立的集群节点,那么默认端口多是从30001开始。
redis-cli 对集群的支持是很是基本的, 因此它老是依靠 Redis 集群节点来将它转向(redirect)至正确的节点。一个真正的(serious)集群客户端应该作得比这更好: 它应该用缓存记录起哈希槽与节点地址之间的映射(map), 从而直接将命令发送到正确的节点上面。这种映射只会在集群的配置出现某些修改时变化, 好比说, 在一次故障转移(failover)以后, 或者系统管理员经过添加节点或移除节点来修改了集群的布局(layout)以后, 诸如此类。
使用redis-rb-cluster写一个例子
在展现如何使用集群进行故障转移、从新分片等操做以前, 咱们须要建立一个示例应用, 了解一些与 Redis 集群客户端进行交互的基本方法。
在运行示例应用的过程当中, 咱们会尝试让节点进入失效状态, 又或者开始一次从新分片, 以此来观察 Redis 集群在真实世界运行时的表现, 而且为了让这个示例尽量地有用, 咱们会让这个应用向集群进行写操做。
本节将经过两个示例应用来展现 redis-rb-cluster 的基本用法, 如下是本节的第一个示例应用, 它是一个名为 example.rb 的文件, 包含在redis-rb-cluster 项目里面
1 require './cluster'
2
3 startup_nodes = [
4 {:host => "127.0.0.1", :port => 7000},
5 {:host => "127.0.0.1", :port => 7001}
6 ]
7 rc = RedisCluster.new(startup_nodes,32,:timeout => 0.1)
8
9 last = false
10
11 while not last
12 begin
13 last = rc.get("last")
14 last = 0 if !last
15 rescue => e
16 puts "error #{e.to_s}"
17 sleep 1
18 end
19 end
20
21 ((last.to_i+1)..1000000000).each{|x|
22 begin
23 rc.set("foo#{x}",x)
24 puts rc.get("foo#{x}")
25 rc.set("last",x)
26 rescue => e
27 puts "error #{e.to_s}"
28 end
29 sleep 0.1
30 }
这个应用所作的工做很是简单: 它不断地以 foo<number> 为键, number 为值, 使用 SET 命令向数据库设置键值对:
SET foo0 0
SET foo1 1
SET foo2 2
And so forth…
代码中的每一个集群操做都使用一个 begin 和 rescue 代码块(block)包裹着, 由于咱们但愿在代码出错时, 将错误打印到终端上面, 而不但愿应用由于异常(exception)而退出。
代码的第七行是代码中第一个有趣的地方, 它建立了一个 Redis 集群对象, 其中建立对象所使用的参数及其意义以下:第一个参数是记录了启动节点的 startup_nodes 列表, 列表中包含了两个集群节点的地址。第二个参数指定了对于集群中的各个不一样的节点, Redis 集群对象能够得到的最大链接数 ,第三个参数 timeout 指定了一个命令在执行多久以后, 才会被看做是执行失败。
启动列表中并不须要包含全部集群节点的地址, 但这些地址中至少要有一个是有效的: 一旦 redis-rb-cluster 成功链接上集群中的某个节点时, 集群节点列表就会被自动更新, 任何真正的的集群客户端都应该这样作。
如今, 程序建立的 Redis 集群对象实例被保存到 rc 变量里面, 咱们能够将这个对象看成普通 Redis 对象实例来使用。
在十一至十九行, 咱们先尝试阅读计数器中的值, 若是计数器不存在的话, 咱们才将计数器初始化为 0 : 经过将计数值保存到 Redis 的计数器里面, 咱们能够在示例重启以后, 仍然继续以前的执行过程, 而没必要每次重启以后都从 foo0 开始从新设置键值对。为了让程序在集群下线的状况下, 仍然不断地尝试读取计数器的值, 咱们将读取操做包含在了一个 while 循环里面, 通常的应用程序并不须要如此当心。
二十一至三十行是程序的主循环, 这个循环负责设置键值对, 并在设置出错时打印错误信息。程序在主循环的末尾添加了一个 sleep 调用, 让写操做的执行速度变慢, 帮助执行示例的人更容易看清程序的输出。执行 example.rb 程序将产生如下输出:
ruby ./example.rb
1
2
3
4
5
6
7
8
9
^C (I stopped the program here)
这个程序并非十分有趣, 稍后咱们就会看到一个更有趣的集群应用示例, 不过在此以前, 让咱们先使用这个示例来演示集群的从新分片操做。
集群从新分片
如今, 让咱们来试试对集群进行从新分片操做。在执行从新分片的过程当中, 请让你的 example.rb 程序处于运行状态, 这样你就会看到, 从新分片并不会对正在运行的集群程序产生任何影响, 你也能够考虑将 example.rb 中的 sleep 调用删掉, 从而让从新分片操做在近乎真实的写负载下执行从新分片操做基本上就是将某些节点上的哈希槽移动到另一些节点上面, 和建立集群同样, 从新分片也可使用 redis-trib 程序来执行执行如下命令能够开始一次从新分片操做:
./redis-trib.rb reshard 127.0.0.1:7000
你只须要指定集群中其中一个节点的地址, redis-trib 就会自动找到集群中的其余节点。
目前 redis-trib 只能在管理员的协助下完成从新分片的工做, 要让 redis-trib 自动将哈希槽从一个节点移动到另外一个节点, 目前来讲还作不到
你想移动多少个槽( 从1 到 16384)?
咱们尝试从将100个槽从新分片, 若是 example.rb 程序一直运行着的话, 如今 1000 个槽里面应该有很多键了。
除了移动的哈希槽数量以外, redis-trib 还须要知道从新分片的目标, 也便是, 负责接收这 1000 个哈希槽的节点。
$ redis-cli -p 7000 cluster nodes | grep myself
97a3a64667477371c4479320d683e4c8db5858b1 :0 myself,master - 0 0 0 connected 0-5460
个人目标节点是 97a3a64667477371c4479320d683e4c8db5858b1.
如今须要指定从哪些节点来移动keys到目标节点 我输入的是all ,这样就会从其余每一个master上取一些哈希槽。
最后确认后你将会看到每一个redis-trib移动的槽的信息,每一个key的移动的信息也会打印出来在从新分片的过程当中,你的例子程序是不会受到影响的,你能够中止或者从新启动屡次。
在从新分片结束后你能够经过以下命令检查集群状态:
./redis-trib.rb check 127.0.0.1:7000
一个更有趣的程序
咱们在前面使用的示例程序 example.rb 并非十分有趣, 由于它只是不断地对集群进行写入, 但并不检查写入结果是否正确。 好比说, 集群可能会错误地将 example.rb 发送的全部 SET 命令都改为了 SET foo 42 , 但由于 example.rb 并不检查写入后的值, 因此它不会意识到集群实际上写入的值是错误的 由于这个缘由, redis-rb-cluster 项目包含了一个名为 consistency-test.rb 的示例应用, 这个应用比起 example.rb 有趣得多: 它建立了多个计数器(默认为 1000 个), 并经过发送 INCR 命令来增长这些计数器的值。
在增长计数器值的同时, consistency-test.rb 还执行如下操做:每次使用 INCR 命令更新一个计数器时, 应用会记录下计数器执行 INCR 命令以后应该有的值。 举个例子, 若是计数器的起始值为 0 , 而此次是程序第 50 次向它发送 INCR 命令, 那么计数器的值应该是 50 。
在每次发送 INCR 命令以前, 程序会随机从集群中读取一个计数器的值, 并将它与本身记录的值进行对比, 看两个值是否相同。
换句话说, 这个程序是一个一致性检查器(consistency checker): 若是集群在执行 INCR 命令的过程当中, 丢失了某条 INCR 命令, 又或者多执行了某条客户端没有确认到的 INCR 命令, 那么检查器将察觉到这一点 —— 在前一种状况中, consistency-test.rb 记录的计数器值将比集群记录的计数器值要大; 而在后一种状况中, consistency-test.rb 记录的计数器值将比集群记录的计数器值要小。
运行 consistency-test 程序将产生相似如下的输出:
$ ruby consistency-test.rb
925 R (0 err) | 925 W (0 err) |
5030 R (0 err) | 5030 W (0 err) |
9261 R (0 err) | 9261 W (0 err) |
13517 R (0 err) | 13517 W (0 err) |
17780 R (0 err) | 17780 W (0 err) |
22025 R (0 err) | 22025 W (0 err) |
25818 R (0 err) | 25818 W (0 err) |
结果展现了执行的读和 写,和错误(因为系统不可用而没有接受的查询发生的错误)的数量.
若是程序察觉了不一致的状况出现, 它将在输出行的末尾显式不一致的详细状况。好比说, 若是咱们在 consistency-test.rb 运行的过程当中, 手动修改某个计数器的值:
$ redis 127.0.0.1:7000> set key_217 0
OK
(in the other tab I see...)
94774 R (0 err) | 94774 W (0 err) |
98821 R (0 err) | 98821 W (0 err) |
102886 R (0 err) | 102886 W (0 err) | 114 lost |
107046 R (0 err) | 107046 W (0 err) | 114 lost |
在咱们修改计数器值的时候, 计数器的正确值是 114 (执行了 114 次 INCR 命令), 由于咱们将计数器的值设成了 0 , 因此 consistency-test.rb 会向咱们报告说丢失了 114 个 INCR 命令。
这个程序做为测试程序颇有意思,因此咱们用这个程序来测试故障恢复.
测试故障转移
在执行本节操做的过程当中, 请一直运行 consistency-test 程序。要触发一次故障转移, 最简单的办法就是令集群中的某个主节点进入下线状态。首先用如下命令列出集群中的全部主节点:
$ redis-cli -p 7000 cluster nodes | grep master
3e3a6cb0d9a9a87168e266b0a0b24026c0aae3f0 127.0.0.1:7001 master - 0 1385482984082 0 connected 5960-10921
2938205e12de373867bf38f1ca29d31d0ddb3e46 127.0.0.1:7002 master - 0 1385482983582 0 connected 11423-16383
97a3a64667477371c4479320d683e4c8db5858b1 :0 myself,master - 0 0 0 connected 0-5959 10922-11422
经过命令输出得知端口号为 7000 、 7001 和 7002 的节点都是主节点, 而后咱们能够经过向端口号为7002 的主节点发送 DEBUG SEGFAULT 命令, 让这个主节点崩溃:
$ redis-cli -p 7002 debug segfault
Error: Server closed the connection
如今,切换到运行着 consistency-test 的标签页, 能够看到, consistency-test 在 7002 下线以后的一段时间里将产生大量的错误警告信息:
18849 R (0 err) | 18849 W (0 err) |
23151 R (0 err) | 23151 W (0 err) |
27302 R (0 err) | 27302 W (0 err) |
... many error warnings here ...
29659 R (578 err) | 29660 W (577 err) |
33749 R (578 err) | 33750 W (577 err) |
37918 R (578 err) | 37919 W (577 err) |
42077 R (578 err) | 42078 W (577 err) |
从 consistency-test 的这段输出能够看到, 集群在执行故障转移期间, 总共丢失了 578 个读命令和 577 个写命令, 可是并无产生任何数据不一致。这听上去可能有点奇怪, 由于在教程的开头咱们提到过, Redis 使用的是异步复制, 在执行故障转移期间, 集群可能会丢失写命令。可是在实际上, 丢失命令的状况并不常见, 由于 Redis 几乎是同时执行将命令回复发送给客户端, 以及将命令复制给从节点这两个操做, 因此实际上形成命令丢失的时间窗口是很是小的。不过, 尽管出现的概率不高, 但丢失命令的状况仍是有可能会出现的, 因此咱们对 Redis 集群不能提供强一致性的这一描述仍然是正确的。如今, 让咱们使用 cluster nodes 命令,查看集群在执行故障转移操做以后, 主从节点的布局状况:
$ redis-cli -p 7000 cluster nodes
3fc783611028b1707fd65345e763befb36454d73 127.0.0.1:7004 slave 3e3a6cb0d9a9a87168e266b0a0b24026c0aae3f0 0 1385503418521 0 connected
a211e242fc6b22a9427fed61285e85892fa04e08 127.0.0.1:7003 slave 97a3a64667477371c4479320d683e4c8db5858b1 0 1385503419023 0 connected
97a3a64667477371c4479320d683e4c8db5858b1 :0 myself,master - 0 0 0 connected 0-5959 10922-11422
3c3a0c74aae0b56170ccb03a76b60cfe7dc1912e 127.0.0.1:7005 master - 0 1385503419023 3 connected 11423-16383
3e3a6cb0d9a9a87168e266b0a0b24026c0aae3f0 127.0.0.1:7001 master - 0 1385503417005 0 connected 5960-10921
2938205e12de373867bf38f1ca29d31d0ddb3e46 127.0.0.1:7002 slave 3c3a0c74aae0b56170ccb03a76b60cfe7dc1912e 0 1385503418016 3 connected
如今masters运行在 7000, 7001 和 7005端口上. 原来的master 7002如今变成了一个7005的一个从节点.
CLUSTER NODES 命令的输出看起来有点复杂,其实他很是的简单,含义以下:
节点ID
IP:端口
标志: master, slave, myself, fail, …
若是是个从节点, 这里是它的主节点的NODE ID
集群最近一次向节点发送 PING 命令以后, 过去了多长时间还没接到回复。.
节点最近一次返回 PONG 回复的时间。
节点的配置纪元(configuration epoch):详细信息请参考 Redis 集群规范 。
本节点的网络链接状况:例如 connected 。
节点目前包含的槽:例如 127.0.0.1:7001 目前包含号码为 5960 至 10921 的哈希槽。
手动故障转移
有的时候在主节点没有任何问题的状况下强制手动故障转移也是颇有必要的,好比想要升级主节点的Redis进程,咱们能够经过故障转移将其转为slave再进行升级操做来避免对集群的可用性形成很大的影响。
Redis集群使用 CLUSTER FAILOVER命令来进行故障转移,不过要被转移的主节点的从节点上执行该命令手动故障转移比主节点失败自动故障转移更加安全,由于手动故障转移时客户端的切换是在确保新的主节点彻底复制了失败的旧的主节点数据的前提下下发生的,因此避免了数据的丢失。
执行手动故障转移时从节点日志以下:
其基本过程以下:客户端再也不连接咱们淘汰的主节点,同时主节点向从节点发送复制偏移量,从节点获得复制偏移量后故障转移开始,接着通知主节点进行配置切换,当客户端在旧的master上解锁后从新链接到新的主节点上。
添加一个新节点
添加新的节点的基本过程就是添加一个空的节点而后移动一些数据给它,有两种状况,添加一个主节点和添加一个从节点(添加从节点时须要将这个新的节点设置为集群中某个节点的复制)
针对这两种状况,本节都会介绍,先从添加主节点开始.
两种状况第一步都是要添加 一个空的节点.
启动新的7006节点,使用的配置文件和之前的同样,只要把端口号改一下便可,过程以下:
在终端打开一个新的标签页.
进入cluster-test 目录.
建立并进入 7006文件夹.
和其余节点同样,建立redis.conf文件,须要将端口号改为7006.
最后启动节点 ../redis-server ./redis.conf
若是正常的话,节点会正确的启动.
接下来使用redis-trib 来添加这个节点到现有的集群中去.
./redis-trib.rb add-node 127.0.0.1:7006 127.0.0.1:7000
能够看到.使用addnode命令来添加节点,第一个参数是新节点的地址,第二个参数是任意一个已经存在的节点的IP和端口.咱们能够看到新的节点已经添加到集群中:
redis 127.0.0.1:7006> cluster nodes
3e3a6cb0d9a9a87168e266b0a0b24026c0aae3f0 127.0.0.1:7001 master - 0 1385543178575 0 connected 5960-10921
3fc783611028b1707fd65345e763befb36454d73 127.0.0.1:7004 slave 3e3a6cb0d9a9a87168e266b0a0b24026c0aae3f0 0 1385543179583 0 connected
f093c80dde814da99c5cf72a7dd01590792b783b :0 myself,master - 0 0 0 connected
2938205e12de373867bf38f1ca29d31d0ddb3e46 127.0.0.1:7002 slave 3c3a0c74aae0b56170ccb03a76b60cfe7dc1912e 0 1385543178072 3 connected
a211e242fc6b22a9427fed61285e85892fa04e08 127.0.0.1:7003 slave 97a3a64667477371c4479320d683e4c8db5858b1 0 1385543178575 0 connected
97a3a64667477371c4479320d683e4c8db5858b1 127.0.0.1:7000 master - 0 1385543179080 0 connected 0-5959 10922-11422
3c3a0c74aae0b56170ccb03a76b60cfe7dc1912e 127.0.0.1:7005 master - 0 1385543177568 3 connected 11423-16383
新节点如今已经链接上了集群, 成为集群的一份子, 而且能够对客户端的命令请求进行转向了, 可是和其余主节点相比, 新节点还有两点区别:
新节点没有包含任何数据, 由于它没有包含任何哈希槽.
尽管新节点没有包含任何哈希槽, 但它仍然是一个主节点, 因此在集群须要将某个从节点升级为新的主节点时, 这个新节点不会被选中。
接下来, 只要使用 redis-trib 程序, 将集群中的某些哈希桶移动到新节点里面, 新节点就会成为真正的主节点了。
添加一个从节点
有两种方法添加从节点,能够像添加主节点同样使用redis-trib 命令,也能够像下面的例子同样使用 –slave选项:
./redis-trib.rb add-node --slave 127.0.0.1:7006 127.0.0.1:7000
此处的命令和添加一个主节点命令相似,此处并无指定添加的这个从节点的主节点,这种状况下系统会在其余的复制集中的主节点中随机选取一个做为这个从节点的主节点。
你能够经过下面的命令指定主节点:
./redis-trib.rb add-node --slave --master-id 3c3a0c74aae0b56170ccb03a76b60cfe7dc1912e 127.0.0.1:7006 127.0.0.1:7000
也可使用CLUSTER REPLICATE 命令添加.这个命令也能够改变一个从节点的主节点。
例如,要给主节点 127.0.0.1:7005添加一个从节点,该节点哈希槽的范围1423-16383, 节点 ID 3c3a0c74aae0b56170ccb03a76b60cfe7dc1912e,咱们须要连接新的节点(已是空的主节点)并执行命令:
redis 127.0.0.1:7006> cluster replicate 3c3a0c74aae0b56170ccb03a76b60cfe7dc1912e
咱们新的从节点有了一些哈希槽,其余的节点也知道(过几秒后会更新他们本身的配置),可使用以下命令确认:
$ redis-cli -p 7000 cluster nodes | grep slave | grep 3c3a0c74aae0b56170ccb03a76b60cfe7dc1912e
f093c80dde814da99c5cf72a7dd01590792b783b 127.0.0.1:7006 slave 3c3a0c74aae0b56170ccb03a76b60cfe7dc1912e 0 1385543617702 3 connected
2938205e12de373867bf38f1ca29d31d0ddb3e46 127.0.0.1:7002 slave 3c3a0c74aae0b56170ccb03a76b60cfe7dc1912e 0 1385543617198 3 connected
节点 3c3a0c… 有两个从节点, 7002 (已经存在的) 和 7006 (新添加的).
移除一个节点
只要使用 del-node 命令便可:
./redis-trib del-node 127.0.0.1:7000 <node-id>
第一个参数是任意一个节点的地址,第二个节点是你想要移除的节点地址。
使用一样的方法移除主节点,不过在移除主节点前,须要确保这个主节点是空的. 若是不是空的,须要将这个节点的数据从新分片到其余主节点上.
替代移除主节点的方法是手动执行故障恢复,被移除的主节点会做为一个从节点存在,不过这种状况下不会减小集群节点的数量,也须要从新分片数据.
从节点的迁移
在Redis集群中会存在改变一个从节点的主节点的状况,须要执行以下命令 :
CLUSTER REPLICATE <master-node-id>
在特定的场景下,不须要系统管理员的协助下,自动将一个从节点从当前的主节点切换到另外一个主节 的自动从新配置的过程叫作复制迁移(从节点迁移),从节点的迁移可以提升整个Redis集群的可用性.
你能够阅读(Redis集群规范)/topics/cluster-spec了解细节.
简短的概况一下从节点迁移
集群会在有从节点数量最多的主节点上进行从节点的迁移.
要在一个主节点上添加多个从节点.
参数来控制从节点迁移 replica-migration-barrier:你能够仔细阅读redis.conf 。
问题和解决方法
./redis-trib.rb create --replicas 1 192.168.1.186:6380 192.168.1.186:6381 192.168.1.186:6382 192.168.1.186:6383 192.168.1.186:6384 192.168.1.186:6385
若是报错:
/usr/bin/env: ruby: No such file or directory
说明ruby没有安装
安装ruby
yum install ruby
若是报错:
no such file to load -- rubygems (LoadError)
安装rubygems
yum install rubygems
执行gem install redis来把gem和redis对接
若是报错:
redis required ruby version >= 2.2.2
升级ruby的版本信息
ruby的升级须要两个依赖 curl和RVM
安装culr
yum install curl
RVM
curl -L get.rvm.io | bash -s stable
若是出现如下错误:
Warning, RVM 1.26.0 introduces signed releases and automated check of signatures when GPG software found. Assuming you trust Michal Papis import the mpapis public key (downloading the signatures).
GPG signature verification failed for ‘/usr/local/rvm/archives/rvm-1.29.3.tgz‘ - ‘https://github.com/rvm/rvm/releases/download/1.29.3/1.29.3.tar.gz.asc‘! Try to install GPG v2 and then fetch the public key:
gpg2 --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 or if it fails:
command curl -sSL https://rvm.io/mpapis.asc | gpg2 --import -the key can be compared with:
https://rvm.io/mpapis.asc
https://keybase.io/mpapis
NOTE: GPG version 2.1.17 have a bug which cause failures during fetching keys from remote server. Please downgrade or upgrade to newer version (if available) or use the second method described above.
解决以上错误
使用curl -sSL https://rvm.io/mpapis.asc | gpg2 --import - 先生成密钥
gpg: 钥匙环‘/root/.gnupg/secring.gpg’已创建
gpg: /root/.gnupg/trustdb.gpg:创建了信任度数据库
gpg: 密钥 D39DC0E3:公钥“Michal Papis (RVM signing) <mpapis@gmail.com>”已导入
gpg: 合计被处理的数量:1
gpg: 已导入:1 (RSA: 1)
gpg: 没有找到任何绝对信任的密钥
再次运行curl -L get.rvm.io | bash -s stable
使用
source /usr/local/rvm/scripts/rvm
命令 使rvm当即生效
rvm list known查看当前可用ruby版本
从可用的ruby版本中选一个进行安装,可是所要安装的版本必需要大于2.2.2
rvm install x.x.x
rvm use x.x.x当即使用新安装的ruby版本
运行gem install redis
报错:
Creating cluster
[ERR] Sorry, can't connect to node 172.0.0.180:6379
有可能的缘由就是
一、172.0.0.180 的 redis服务没开启:
查看一下
[root@redis_2 ~]# ps aux | grep redis
root 2859 0.0 0.7 141012 7652 ? Ssl 18:19 0:00 /servers/redis/bin/redis-server ::1:6379 [cluster]
若是还没启动,执行:
[root@redis_2 ~]# /servers/redis/bin/redis-server /servers/redis/redis.conf
二、172.0.0.180 对应的端口 是否对外开放:
能够在172.0.0.188 链接看一下:
[root@redis_1 src]# /servers/redis/bin/redis-cli -h 172.0.0.180
若是出现:
Could not connect to Redis at 172.0.0.180:6379: Connection refused
能够执行:
[root@redis_2 ~]# firewall-cmd --zone=public --add-port=6379/tcp --permanent
[root@redis_2 ~]# firewall-cmd --reload
发现上面问题都处理了,仍是出现链接节点不上的状况的话,也有多是绑定的ip地址问题:
编辑配置文件:
[root@redis_2 ~]# vim /servers/redis/redis.conf
把bind 指令改成对应的ip
bind 172.0.0.180
关闭在启动:
[root@redis_2 ~]# /servers/redis/bin/redis-cli shutdown
[root@redis_2 ~]# /servers/redis/bin/redis-server /servers/redis/redis.conf
[ERR] Node 172.168.63.202:7001 is not empty. Either the nodealready knows other nodes (check with CLUSTER NODES) or contains some key in database 0.
解决方法:
1)、将须要新增的节点下aof、rdb等本地备份文件删除;
2)、同时将新Node的集群配置文件删除,即:删除你redis.conf里面cluster-config-file所在的文件;
3)、再次添加新节点若是仍是报错,则登陆新Node,./redis-cli–h x –p对数据库进行清除:
172.168.63.201:7001> flushdb #清空当前数据库
一直都在Waiting for the cluster to join.......
配置集群的时候在redis.conf配置文件中bind ip的时候是这样进行绑定的:
bind 127.0.0.1 机器ip
将绑定方式修改成:
bind 机器ip
错误信息:(error) MOVED 11469 172.16.35.15:7002
应该是你没有启动集群模式(即缺乏了那个"-c"):
redis-cli -c -h yourhost -p yourpost
https://www.evernote.com/shard/s736/sh/cc73e00c-1c0e-4bc2-9997-49e89f096c2f/0e356a4db3b927ed