redis:redis cluster集群实践

2023-10-27

redis集群参数配置

我们后面会部署一个Redis集群作为例子,在那之前,先介绍一下集群在redis.conf中的参数。

  • cluster-enabled <yes/no>: 如果配置yes则开启集群功能,此redis实例作为集群中的一个节点,否则,它是一个普通的单一的redis实例。

  • cluster-config-file <filename>: 注意,虽然此配置的名字叫做“集群配置文件”,但是此配置不能人工编辑,它是集群节点自动维护的文件,主要用于记录集群中有哪些节点、他们的状态以及一些持久化参数等,方便在重启时恢复这些状态。通常是在收到请求之后这个文件就会被更新

  • cluster-node-timeout <milliseconds>: 这是集群中的节点能够失联的最大时间,超过这个时间,该节点就会被认为故障。如果主节点超过这个时间还是不可达,则用它的从节点将启动故障迁移,升级成主节点。注意,任何一个节点在这个时间之内如果还是没有连上大部分的主节点,则此节点将停止接收任何请求

  • cluster-slave-validity-factor <factor>: 如果设置成0,则无论从节点与主节点失联多久,从节点都会尝试升级成主节点。如果设置成正数,则cluster-node-timeout乘以cluster-slave-validity-factor得到的时间,是从节点与主节点失联后,此从节点数据有效的最长时间,超过这个时间,从节点不会启动故障迁移。假设cluster-node-timeout=5,cluster-slave-validity-factor=10,则如果从节点跟主节点失联超过50秒,此从节点不能成为主节点。注意,如果此参数配置成非0,将可能出现由于某主节点失联却没有从节点能够顶上的情况,从而导致集群不能正常工作,在这种情况下,只有等原来的主节点重新回归集群,集群才能恢复运作

  • cluster-migration-barrier <count>:主节点需要的最小从节点数,只有达到这个数,主节点失败时,它的从节点才会进行迁移

  • cluster-require-full-coverage <yes/no>:在部分key所在的节点不可用时,如果此参数设置为“yes”(默认),则整个集群停止接受操作;如果此参数设置为“no”,则集群依然可以为可达节点上dekey提供读操作

搭建并使用redis集群

要创建集群,实现需要以集群模式与新的空redis实例,也就是说,以普通模式启动的redis是不能作为集群的节点的,需要以集群模式启用的redis实例才能具有集群节点的特性、支持集群的指令,称为集群的节点。

下面是一个最小选项的集群配置文件

port 7000
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes

开启集群模式只需要打开cluster-enabled即可。每一个redis实例都包含一个配置文件,默认是nodes.conf,用于存储此节点的一些配置信息。这个配置文件由redis集群的节点自行创建和更新,不能由人手动的去修改。

一个最下的集群需要最少三个主节点。第一次测试,强烈建议你配置6个节点:三个主节点、三个从节点。

开始测试,步骤如下:先进入新的目录,以redis实例的端口为目录名,创建目录,我们将在这些目录里运行我们的实例。

类似这样:

mkdir cluster-test
cd cluster-test
mkdir 7000 7001 7002 7003 7004 7005

在7000-7005的每个目录中创建配置文件redis.conf,内容就用上面的最简配置做模板,注意修改端口号,改为跟目录一致的端口。

把你的redis服务器(用GitHub中的不稳定分支的最新的代码编译来)拷贝到cluster-test目录,然后打开6个终端页准备测试。

在每个终端启动一个redis实例,指令类似这样:

[oceanstar@localhost 7000]$ cd 7000/
[oceanstar@localhost 7000]$ ls
redis.conf
[oceanstar@localhost 7000]$ ../redis-server ./redis.conf 
18037:C 13 Oct 2021 21:06:04.833 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
18037:C 13 Oct 2021 21:06:04.833 # Redis version=6.0.5, bits=64, commit=00000000, modified=0, pid=18037, just started
18037:C 13 Oct 2021 21:06:04.833 # Configuration loaded
18037:M 13 Oct 2021 21:06:04.833 # You requested maxclients of 10000 requiring at least 10032 max file descriptors.
18037:M 13 Oct 2021 21:06:04.833 # Server can't set maximum open files to 10032 because of OS error: Operation not permitted.
18037:M 13 Oct 2021 21:06:04.833 # Current maximum open files is 4096. maxclients has been reduced to 4064 to compensate for low ulimit. If you need higher maxclients increase 'ulimit -n'.
18037:M 13 Oct 2021 21:06:04.834 * No cluster configuration found, I'm a6167ddab7475a9c09000f65e438b684c85ebae7
                _._                                                  

从前台日志中我们可以看到,由于没有nodes.conf文件,每个节点都给自己一个新的ID。

  • 这个ID将一直被此节点占用,作为此节点在整个集群中的唯一标识。

  • 节点区分其他节点也是通过此ID来标识,而非IP或者端口。IP可以改,端口可以改,但是此ID不能该,直到这个节点离开集群。

  • 这个ID称为节点ID(Node ID)

18037:M 13 Oct 2021 21:06:04.834 * No cluster configuration found, I'm a6167ddab7475a9c09000f65e438b684c85ebae7
               

另外开一个终端,可以看到生成了nodes.conf和appendonly.aof问题

[oceanstar@localhost 7000]$ ls
appendonly.aof  nodes.conf  redis.conf
[oceanstar@localhost 7000]$ cat nodes.conf 
a6167ddab7475a9c09000f65e438b684c85ebae7 :0@0 myself,master - 0 0 0 connected
vars currentEpoch 0 lastVoteEpoch 0
[oceanstar@localhost 7000]$ cat appendonly.aof 
[oceanstar@localhost 7000]$ 

创建集群

现在6个实例已经运行起来了,我们需要给节点写一些有意义的配置来创建集群,redis5通过redis-cli就可以创建集群。运行如下命令:

$ ./redis-cli --cluster create 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 --cluster-replicas 1
>>> Performing hash slots allocation on 6 nodes...
Master[0] -> Slots 0 - 5460
Master[1] -> Slots 5461 - 10922
Master[2] -> Slots 10923 - 16383
Adding replica 127.0.0.1:7004 to 127.0.0.1:7000
Adding replica 127.0.0.1:7005 to 127.0.0.1:7001
Adding replica 127.0.0.1:7003 to 127.0.0.1:7002
>>> Trying to optimize slaves allocation for anti-affinity
[WARNING] Some slaves are in the same host as their master
M: a6167ddab7475a9c09000f65e438b684c85ebae7 127.0.0.1:7000
   slots:[0-5460] (5461 slots) master
M: 697ed75764e5dc8d0ecefc8bc78b1ac0deb7822a 127.0.0.1:7001
   slots:[5461-10922] (5462 slots) master
M: 45d9ea3a8abc9baade3873358b9bb515a010515d 127.0.0.1:7002
   slots:[10923-16383] (5461 slots) master
S: 5a901c8d7324b28fb882c1f45533776f68a3cb86 127.0.0.1:7003
   replicates a6167ddab7475a9c09000f65e438b684c85ebae7
S: 6680c148565a1f14cda6bb48d0fad49bebaf0fac 127.0.0.1:7004
   replicates 697ed75764e5dc8d0ecefc8bc78b1ac0deb7822a
S: ecebb8f92f2cccfd2ac530e75d0475c5f030577d 127.0.0.1:7005
   replicates 45d9ea3a8abc9baade3873358b9bb515a010515d
Can I set the above configuration? (type 'yes' to accept): 

我们创建create创建新的集群,选项选项 --cluster-replicas 1表示为每一个主服务器配置一个从服务器。其余的参数是要创建的集群中各实例的地址列表。

我们创建的集群有三个主节点和三个从节点。

redis将会给你一些配置建议,输入yes表示接收。集群会被配置并彼此连接好,意思是各节点实例被引导彼此通话并最终形成集群。最后如果一切顺利,将会看到如下信息:

[OK] All 16384 slots covered

这表示,16384个哈希槽都被主节点正常服务着。

此时,进入7000的目录:可以看到生成了一个dump.rdb, appendonly.aof 和redis.conf依然没有变化,但是nodes.conf更新了

[oceanstar@localhost 7001]$ cd ../7000/
[oceanstar@localhost 7000]$ ls
appendonly.aof  dump.rdb  nodes.conf  redis.conf

[oceanstar@localhost 7000]$ cat nodes.conf 
45d9ea3a8abc9baade3873358b9bb515a010515d 127.0.0.1:7002@17002 master - 0 1634131541538 3 connected 10923-16383
6680c148565a1f14cda6bb48d0fad49bebaf0fac 127.0.0.1:7004@17004 slave 697ed75764e5dc8d0ecefc8bc78b1ac0deb7822a 0 1634131541438 5 connected
a6167ddab7475a9c09000f65e438b684c85ebae7 127.0.0.1:7000@17000 myself,master - 0 1634131541000 1 connected 0-5460
ecebb8f92f2cccfd2ac530e75d0475c5f030577d 127.0.0.1:7005@17005 slave 45d9ea3a8abc9baade3873358b9bb515a010515d 0 1634131541538 6 connected
5a901c8d7324b28fb882c1f45533776f68a3cb86 127.0.0.1:7003@17003 slave a6167ddab7475a9c09000f65e438b684c85ebae7 0 1634131540429 4 connected
697ed75764e5dc8d0ecefc8bc78b1ac0deb7822a 127.0.0.1:7001@17001 master - 0 1634131540000 2 connected 5461-10922
vars currentEpoch 6 lastVoteEpoch 0

[oceanstar@localhost 7000]$ cat dump.rdb 
REDIS0009�  redis-ver6.0.5�
redis-bits�@�ctime�T�faused-mem��$�repl-stream-db��repl-id(98aac086839c32aab06769c8d35a5aff405b448e�
                                                                                                    repl-offset��
                                                                                                                 aof-preamble�� ��!�DH[oceanstar@localhost 7000]$ 

ps:一个错误,可以看出集群至少需要三个节点

$ ./redis-cli --cluster create 127.0.0.1:7000 127.0.0.1:7001
'*** ERROR: Invalid configuration for cluster creation.
*** Redis Cluster requires at least 3 master nodes.
*** This is not possible with 2 nodes and 0 replicas per node.
*** At least 3 nodes are required.

ps:在redis旧版本中src目录下有个叫做redis-trib.rb的工具,也是用来创建集群的,在6.0版本的时候已经不再可用了,如果你运行将会:

$ ./redis-trib.rb 
WARNING: redis-trib.rb is not longer available!   警告:redis-trib。Rb不再可用!
You should use redis-cli instead.  您应该使用redis-cli。

All commands and features belonging to redis-trib.rb have been moved
to redis-cli.  属于redis-trib的所有命令和特性。Rb已经移动到redis-cli。
In order to use them you should call redis-cli with the --cluster
option followed by the subcommand name, arguments and options.  为了使用它们,您应该使用——cluster选项,后跟子命令名、参数和选项来调用redis-cli。

Use the following syntax:   使用以下语法:
redis-cli --cluster SUBCOMMAND [ARGUMENTS] [OPTIONS]

Example:   例子:
redis-cli --cluster info 127.0.0.1:7000

To get help about all subcommands, type:   要获取关于所有子命令的帮助,输入:
redis-cli --cluster help

使用create cluster脚本创建redis集群

如果你不想同如上手动配置和执行单个实例来创建redis集群,那么可以使用当前方法

只要在Redis发行版中检查utils/create-cluster目录。里面有一个名为create-cluster的脚本(与包含它的目录同名),它是一个简单的bash脚本。为了启动一个6个节点、3个主节点和3个从节点的集群,只需输入以下命令:

create-cluster start
create-cluster create

当redis-cli实用程序希望您接受集群布局时,请在步骤2中回复yes。

您现在可以与集群进行交互,默认情况下第一个节点将在端口30001启动。当你完成时,用以下命令停止集群:

create-cluster stop.

有关如何运行脚本的更多信息,请阅读该目录中的README。

使用集群

redis集群新阶段的一个问题时客户单实现很少,下面列出了一些实现:redis-rb-cluster(官方)、redis-py-cluster、predis、jedis等

测试redis集群一个比较简单的方法就是使用redis-rb-cluster或者redis-cli,接下来我们以redis-cli为例来进行演示:

$ ./redis-cli  -c -p 7000
127.0.0.1:7000> set foo bar
-> Redirected to slot [12182] located at 127.0.0.1:7002
OK
127.0.0.1:7002> set hello world
-> Redirected to slot [866] located at 127.0.0.1:7000
OK
127.0.0.1:7000> get foo
-> Redirected to slot [12182] located at 127.0.0.1:7002
"bar"
127.0.0.1:7002> get hello
-> Redirected to slot [866] located at 127.0.0.1:7000
"world"
127.0.0.1:7000> 

注意:如果你是使用脚本创建的集群节点,那么默认断开可能从30001开始。

redis-cli对集群的支持是非常基本的,所以它总是依靠redis集群节点来将它转向(redirect)正确的节点。一个真正的(seriout)集群客户端应该做的比这更好:它应该用缓存记录起始哈希槽与节点地址之间的映射(map),从而直接将命令发送到正确的节点上面。这种映射只会在集群的配置出现某些修改时变化,比如说,在一次故障转移之后,或者系统管理员通过添加节点或者移除节点来修改了集群的布局之后。。。

使用redis-rb-cluster写一个实例

注意,example.rb内部如下:

require './cluster'

if ARGV.length != 2
    startup_nodes = [
        {:host => "127.0.0.1", :port => 7000},
        {:host => "127.0.0.1", :port => 7001}
    ]
else
    startup_nodes = [
        {:host => ARGV[0], :port => ARGV[1].to_i}
    ]
end

rc = RedisCluster.new(startup_nodes,32,:timeout => 0.1)

last = false

while not last
    begin
        last = rc.get("__last__")
        last = 0 if !last
    rescue => e
        puts "error #{e.to_s}"
        sleep 1
    end
end

((last.to_i+1)..1000000000).each{|x|
    begin
        rc.set("foo#{x}",x)
        puts rc.get("foo#{x}")
        rc.set("__last__",x)
    rescue => e
        puts "error #{e.to_s}"
    end
    sleep 0.1
}

运行它:

ruby ./example.rb
1
2
3
4
5
6
7
8
9
^C (I stopped the program here)

集群重新分片

现在,让我们尝试对集群进行重新分片操作。在执行重新分片的过程中,请让你的example.rb程序处于运行状态,这样你可以看到,重新分片并不会对正在运行的集群程序产生任何影响,你也可以考虑将example.rb中的sleep调用删掉,从而让重新分片操作有一些更严重的写负载。

重新分片操作基本上就是将某些节点上的哈希槽移动到另一些节点上面,与集群创建类似,它是使用redis-cli实用程序完成的。

要开始重分片只需键入:

redis-cli --cluster reshard 127.0.0.1:7000

只需要指定一个节点,redis-cli会自动找到其他节点。

目前,redis cli只能在管理员的协助下完成重新分片的工作,要让redis-cli自动将哈希槽从一个节点移动到另一个节点,目前来说还做不到。所以,第一个问题是:你想移动多少个槽(从1到16384)

我们尝试重新分片1000个槽重新,如果example.rb程序一直运行这的话,现在1000个槽里面应该有不少键了

除了1要知道需要移动的哈希槽的数量之外,redis-cli还需要知道重新分配的目标,也就是负责接收这100个槽的节点,我将使用第一个主节点,即127.0.0.1:7000,但是我需要指定实例的节点ID。redis-cli已经将其打印在列表中,但如果需要,我始终可以使用以下命令找到节点的ID:

# ./redis-cli -p 7000 cluster nodes | grep myself
97a3a64667477371c4479320d683e4c8db5858b1127.0.0.1:7000@17000 myself,master - 0 1634136384000 1 connected 0-5460

所以我的目标节点是97a3a64667477371c4479320d683e4c8db5858b1。

第三个问题是:从哪些节点获取这些键。我输入的是all,这样就会从其他每个master上去一些哈希槽。

最终确认之后,您将看到每个redis-cl移动的槽的信息以及每个移动的key1的信息被打印出来。

在重新分片的过程中,你得例子程序是不会受到影响的,你可以停止或者重启多次。

在重新分片结束之后你可以通过如下命令检查集群状态:

redis-cli --cluster check 127.0.0.1:7000

所有的槽将像往常一样被覆盖,但是这次在127.0.0.1:7000的master将有更多的散列槽,大约在6461左右。

为重分片操作编写脚本

重分片操作可以自动执行,而不需要以交互式手动输入参数:

redis-cli --cluster reshard <host>:<port> --cluster-from <node-id> --cluster-to <node-id> --cluster-slots <number of slots> --cluster-yes

如果你经常重分片,这允许构建一些自动化,但是目前redis-cli还没有办法自动重新平衡集群,检查集群节点上的键的分布,并根据需要智能移动插槽。该功能将在未来添加。

一个更有趣的示例应用程序

我们早期编写的示例应用程序不是很好。它以一种简单的方式写入集群,甚至不检查写入的内容是否正确。

因此,在redis-rb-cluster存储库中,有一个更有趣的应用程序,称为consistency-test.rb。它使用一组计数器(默认为1000),并发送INCR命令以增加计数器。

然而,应用程序不只是编写,它还做了两件额外的事情:

  • 当使用incr更新计数器时,应用程序将记住写入操作
  • 他还在每次写入之前读取随机计数器,并检测该值是否是我们所期望的值,并将其与内存中的值进行比较。

这意味着这个应用程序是一个简单的一致性检测器,能够告诉你集群是否丢失了一些写操作,或者是否介绍了我们没有收到确认的写操作。在第一种情况下,我们会看到计数器的值小于我们记忆中的值,而在第二种情况下,计算器的值会更大。

运行一致性测试应用程序每秒生成一行输出:

$ 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) |

该行显示执行的读写次数以及错误数(由于系统不可用而导致错误导致查询不被接受)。

如果发现不一致,将在输出中添加新行。比如,如果在程序运行时手动重置计数器,会发生如下情况:

$ redis-cli -h 127.0.0.1 -p 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 |

当我将计数器设置为0时,实际值是114,因此程序报告114丢失的写操作(集群不记住的INCR命令)。

这个程序作为测试用例更有趣,所以我们将使用它来测试Redis集群故障转移。

测试故障转移

注意,在执行本节操作的过程中,请一直运行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

现在我们可以查看一致性测试的输出,看看它报告了什么。

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) |

可以看到,在故障转移期间,系统无法接收578个读和577个写,但是在数据库中没有创建不一致。这听起来可能意外,因为之前我们说过,redis集群在故障转移期间可能会丢失写操作,因为它使用异步复制。我们没有说的是,丢失命令是不太可能发生的,因为redis几乎是同时执行将命令回复发送给客户端,以及将命令复制给从节点这两个操作,所以实际上造成命令丢失的时间窗口是非常小的。不过,尽管出现的几率小,但是还是有可能会丢失的。所以我们对redis集群不能提供强一致的说法仍然是正确的。现在,我们来看看集群在执行故障转移后,主从节点的布局情况:

$ 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

现在master在端口7000、7001和7005上运行。以前的master,也就是运行在端口7002上的Redis实例,现在是7005的slave。

手动故障转移

有时候在主节点没有任何问题的情况下强制手动故障转移也是很有必要的,比如想要升级主节点的redis进程,我们可以通过故障转移将其转为slave再进行升级操作来避免对集群的可用性造成很大影响。

redis集群使用cluster failover命令来进行故障转移,不过在想要被转移的主节点的从节点上执行【手动故障转移】比【主节点失败自动故障转移】更安全,因为手动故障转移是客户端的切换是在确保新的主节点完全复制了失败的旧的主节点数据的前提下发生的,从而避免了数据的丢失。

执行手动故障转移从节点日志如下:

# Manual failover user request accepted.
# Received replication offset for paused master manual failover: 347540
# All master replication stream processed, manual failover can start.
# Start of election delayed for 0 milliseconds (rank #0, offset 347540).
# Starting a failover election for epoch 7545.
# Failover election won: I'm the new master.

其基本过程如下:客户端不再连接我们淘汰的主节点,同时主节点向从节点发送复制偏移量,从节点得到复制偏移量之后故障转移开始,接着通知主节点进行配置切换,当客户端在旧的主节点上解锁后重新连接到新的主节点上。

添加一个新节点

添加一个新节点基本上就是添加一个空节点,然后移动一些数据给它。有两种情况:

  • 添加一个主节点
  • 添加一个从节点(添加丛节点时需要将这个新的节点设置为集群中的某个节点的复制)

两种情况的第一步都是要添加一个空的节点:启动新的7006节点,使用的配置文件和一起一样,只是端口号不同

现在,我们可以像往常一样使用redis cli将节点添加到现有集群中。

redis-cli --cluster add-node 127.0.0.1:7006 127.0.0.1:7000

如果,这里使用add-node命令指定新节点的地址作为第一个参数,将集群中一个随机现有节点的地址作为第二个参数。

实际上,这里的redis-cli几乎没有帮助我们,它只是向节点发送了一个CLUSTER MEET消息,这也是可以手动完成的。然而,redis-cli还会在操作之前检查集群的状态,因此,即使您知道内部是如何工作的,始终通过redis-cli执行集群操作也是一个好主意。

现在我们可以连接新节点,看看它是否真的加入了集群:

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-cli将集群中的某些哈希通移动到新节点里面,新节点就会成为真正的主节点了

添加一个从节点

添加一个新的Replica可以通过两种方式执行。最明显的方法是再次使用redis-cli,但是使用——cluster-slave选项,如下所示:

redis-cli --cluster add-node 127.0.0.1:7006 127.0.0.1:7000 --cluster-slave

注意,这里的命令与添加新主机的命令完全相同,此处并没有指定添加的这个从节点的主节点,此时,redis-cli将在副本较少的主机中添加新节点作为随机主机的副本。

你可以通过如下命令指定主节点:

redis-cli --cluster add-node 127.0.0.1:7006 127.0.0.1:7000 --cluster-slave --cluster-master-id 3c3a0c74aae0b56170ccb03a76b60cfe7dc1912e

也可以使用cluster replicate命令添加,这个命令可以改变一个从节点的主节点。

例如,需要给主节点127.0.0.1:7005添加从节点,7005节点哈希槽范围11423-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

节点3 c3a0c…现在有两个丛节点,运行在端口7002(现有的一个)和7006(新的一个)。

删除一个节点

使用delet -node删除丛节点

redis-cli --cluster del-node 127.0.0.1:7000 `<node-id>`

第一个参数是任意一个节点的地址,第二个节点是你想要移除的节点地址

使用通用的方法移除主节点,只不过在移除主节点之后,需要确保这个主节点时空的,如果不是空的,需要把这个节点的数据重新分配到其他主节点上。

删除主节点的另一种方法是在一个从节点上执行手动故障转移,被移除的主节点会作为一个从节点存在,不过这种情况下不会减少集群节点的数量,也需要重新分片数据

从节点迁移

在redis集群中会存在改变一个从节点的主节点情况,需要使用如下命令:

CLUSTER REPLICATE <master-node-id>

create-cluster stop.

有关如何运行脚本的更多信息,请阅读该目录中的README。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

redis:redis cluster集群实践 的相关文章

  • Redis hash写入速度非常慢

    我面临一个非常奇怪的问题 使用 Redis 时 我的写入速度非常糟糕 在理想的情况下 写入速度应该接近 RAM 上的写入速度 这是我的基准 package redisbenchmark import redis clients jedis
  • 如何将 ActionController::Live 与 Resque + Redis 一起使用(用于聊天应用程序)

    我正在尝试为我的 Rails 应用程序构建聊天功能 我在用ActionController Live Puma Resque Redis为了这 所以基本上在这种情况下 redissubscribe方法正在后台运行 使用resque 到目前为
  • 在 Kubernetes/Openshift 中将客户端-服务器流量保持在同一区域的最佳方法?

    我们运行兼容 Kubernetes OKD 3 11 的本地 私有云集群 其中后端应用程序与用作缓存和 K V 存储的低延迟 Redis 数据库进行通信 新的架构设计将在两个地理上分布的数据中心 区域 之间平均划分工作节点 我们可以假设节点
  • 无法启动redis.service:单元redis-server.service被屏蔽

    我在 ubuntu 16 04 上安装了 Redis 服务器 但是当我尝试使用启动redis服务时 sudo systemctl start redis 我收到消息 Failed to start redis service Unit re
  • 有没有办法在 ruby​​ 中重新定义 []=+

    我正在尝试编写一个简单的 DSL 针对 Redis 并且我想自己定义 I have def key val redis zadd name val key end 我想定义 def key val redis zincrby name va
  • 如何设置和获取Redis中存储的对象?

    我试图在 redis 中存储一个对象 当我获取该对象时 它似乎不起作用 I tried u User new u name blankman redis set test u x redis get test x name error 我想
  • 使用 Sentinels 升级 Redis 的最佳实践?

    我有 3 个 Redis 节点 由 3 个哨兵监视 我进行了搜索 文档似乎不清楚如何最好地升级此类配置 我目前使用的是 3 0 6 版本 我想升级到最新的 5 0 5 我对这方面的程序有几个疑问 升级两个大版本可以吗 我在我们的暂存环境中执
  • Java 将字节转换为二进制安全字符串

    我有一些以字节为单位的数据 我想将它们放入Redis中 但是Redis只接受二进制安全字符串 而我的数据有一些二进制非安全字节 那么如何将这些字节转换为二进制安全字符串以便将它们保存到 Redis 中呢 Base64 对我有用 但它使数据更
  • Spring Data JPA Redis:无法编写基于自定义方法的查询

    我已经使用 Redis 配置了 Spring Data JPA 并使用RedisRepositorieswith 提供了类似的方法find findAll 所有这些方法似乎都工作得很好 但我无法编写我的自定义方法 RedisEntity f
  • 如何使redis中的“HSET”子键“过期”?

    我需要使 Redis 哈希中所有超过 1 个月的密钥过期 这不可能 https github com antirez redis issues 167 issuecomment 2559040 为了保持 Redis 简单 https git
  • 如何在Redis中只保存一个数据库?

    我是 Redis 新手 有一个与备份相关的问题 目前 我有一个实例在 Windows 服务器上运行 在这个实例中 我当前有一项 工作 将数据存储在一个数据库中 我不想备份这些数据 我必须创造一份新工作 我的第一个想法是将数据存储在另一个数据
  • Redis+Docker+Django - 错误 111 连接被拒绝

    我正在尝试使用 Redis 作为使用 Docker Compose 的 Django 项目的 Celery 代理 我无法弄清楚我到底做错了什么 但尽管控制台日志消息告诉我 Redis 正在运行并接受连接 事实上 当我这样做时 docker
  • 节点应用程序之间共享会话?

    我目前有两个独立的节点应用程序在两个不同的端口上运行 但共享相同的后端数据存储 我需要在两个应用程序之间共享用户会话 以便当用户通过一个应用程序登录时 他们的会话可用 并且他们似乎已登录到另一个应用程序 在本例中 它是一个面向公众的网站和一
  • 在 Spring 4 中干掉通用的 RedisTemplate

    我读到你可以拥有 Autowired从 Spring 4 开始泛型 这太棒了 我有一个摘要RedisService我想参加的课程 Autowired一个通用的 RestTemplate 如下所示 public abstract class
  • 如何配置Lettuce Redis集群异步连接池

    我正在配置我的生菜重新分配池 当我按照官方文档配置时 连接池无法正常初始化 无法获取连接 官方文档指出 RedisClusterClient clusterClient RedisClusterClient create RedisURI
  • Spring Data Redis 覆盖默认序列化器

    我正在尝试创建一个RedisTemplatebean 将具有更新的值序列化器来序列化对象JSONredis 中的格式 Configuration class RedisConfig Bean name redisTemplate Prima
  • Laravel Redis 配置

    我目前正在使用 Laravel 和 Redis 创建一个应用程序 几乎一切都工作正常 我按照文档中的说明扩展了身份验证 用户可以订阅 登录 注销 我可以创建内容 所有内容都存储在 Redis 中 但我有一个问题 我无法运行 php arti
  • 超出 Redis 连接/缓冲区大小限制

    在对我们的应用程序服务器进行压力测试时 我们从 Redis 中得到以下异常 ServiceStack Redis RedisException 无法连接到 redis host 6379 处的 redis 实例 gt System Net
  • ServiceStack PooledRedisClientManager 故障转移如何工作?

    根据 git commit 消息 ServiceStack 最近添加了故障转移支持 我最初认为这意味着我可以关闭我的一个 Redis 实例 并且我的池客户端管理器将优雅地处理故障转移并尝试与我的备用 Redis 实例之一连接 不幸的是 我的
  • 检查 Redis 列表中是否已存在某个值

    我想知道是否有办法检查 redis 列表中是否已存在某个键 我无法使用集合 因为我不想强制唯一性 但我确实希望能够检查字符串是否确实存在 Thanks 您的选择如下 Using LREM如果发现则更换它 维护一个单独的SET与您的LIST

随机推荐