chinaab 发表于 2018-11-2 13:38:40

Redis(五)、Redis数据库集群相关

  Redis数据库集群
第1章 集群简介
  Redis 集群是一个分布式(distributed)、容错(fault-tolerant)的 Redis 实现, 集群可以使用的功能是普通单机 Redis 所能使用的功能的一个子集(subset),是一个可以在多个 Redis 节点之间进行数据共享的设施(installation)。
  Redis 集群中不存在中心(central)节点或者代理(proxy)节点, 集群的其中一个主要设计目标是达到线性可扩展性(linear scalability)。
  Redis 集群不支持那些需要同时处理多个键的 Redis 命令, 因为执行这些命令需要在多个 Redis 节点之间移动数据, 并且在高负载的情况下, 这些命令将降低 Redis 集群的性能, 并导致不可预测的行为。
  Redis 集群通过分区(partition)来提供一定程度的可用性(availability): 即使集群中有一部分节点失效或者无法进行通讯, 集群也可以继续处理命令请求。
  Redis 集群提供了以下两个好处:
  q将数据自动切分(split)到多个节点的能力。
  q当集群中的一部分节点失效或者无法进行通讯时, 仍然可以继续处理命令请求的能力。
第2章 集群数据共享
  Redis 集群使用数据分片(sharding)而非一致性哈希(consistency hashing)来实现: 一个 Redis 集群包含 16384 个哈希槽(hash slot), 数据库中的每个键都属于这 16384 个哈希槽的其中一个, 集群使用公式 CRC16(key) % 16384 来计算键 key 属于哪个槽, 其中 CRC16(key) 语句用于计算键 key 的 CRC16 校验和 。
  集群中的每个节点负责处理一部分哈希槽。 举个例子, 一个集群可以有三个哈希槽, 其中:
  节点 A 负责处理 0 号至 5500 号哈希槽。
  节点 B 负责处理 5501 号至 11000 号哈希槽。
  节点 C 负责处理 11001 号至 16384 号哈希槽。
  这种将哈希槽分布到不同节点的做法使得用户可以很容易地向集群中添加或者删除节点。 比如说,如果用户将新节点 D 添加到集群中, 那么集群只需要将节点 A 、B 、 C 中的某些槽移动到节点 D 就可以了。与此类似, 如果用户要从集群中移除节点 A , 那么集群只需要将节点 A 中的所有哈希槽移动到节点 B 和节点 C , 然后再移除空白(不包含任何哈希槽)的节点 A 就可以了。
  因为将一个哈希槽从一个节点移动到另一个节点不会造成节点阻塞, 所以无论是添加新节点还是移除已存在节点, 又或者改变某个节点包含的哈希槽数量, 都不会造成集群下线。
第3章 集群中的主从复制
  为了使得集群在一部分节点下线或者无法与集群的大多数(majority)节点进行通讯的情况下, 仍然可以正常运作, Redis 集群对节点使用了主从复制功能: 集群中的每个节点都有 1 个至 N 个复制品(replica), 其中一个复制品为主节点(master), 而其余的 N-1 个复制品为从节点(slave)。
  在之前列举的节点 A 、B 、C 的例子中, 如果节点 B 下线了, 那么集群将无法正常运行, 因为集群找不到节点来处理 5501 号至 11000号的哈希槽。
  另一方面, 假如在创建集群的时候(或者至少在节点 B 下线之前), 我们为主节点 B 添加了从节点 B1 , 那么当主节点 B 下线的时候, 集群就会将 B1 设置为新的主节点, 并让它代替下线的主节点 B , 继续处理 5501 号至 11000 号的哈希槽, 这样集群就不会因为主节点 B 的下线而无法正常运作了。不过如果节点 B 和 B1 都下线的话, Redis 集群还是会停止运作。
第4章 集群的一致性保证
  Redis 集群不保证数据的强一致性(strong consistency): 在特定条件下, Redis 集群可能会丢失已经被执行过的写命令。
  使用异步复制(asynchronous replication)是 Redis 集群可能会丢失写命令的其中一个原因。 考虑以下这个写命令的例子:
  1、客户端向主节点 B 发送一条写命令。
  2、主节点 B 执行写命令,并向客户端返回命令回复。
  3、主节点 B 将刚刚执行的写命令复制给它的从节点 B1 、 B2 和 B3 。
  可见, 主节点对命令的复制工作发生在返回命令回复之后, 因为如果每次处理命令请求都需要等待复制操作完成的话,那么主节点处理命令请求的速度将极大地降低 —— 我们必须在性能和一致性之间做出权衡。
  Redis 集群另外一种可能会丢失命令的情况是, 集群出现网络分裂(network partition), 并且一个客户端与至少包括一个主节点在内的少数(minority)实例被孤立。举个例子:
  1、假设集群包含 A 、 B 、 C 、 A1 、 B1 、 C1 六个节点,其中 A 、B 、C 为主节点,而 A1 、B1 、C1 分别为三个主节点的从节点, 另外还有一个客户端 Z1 。
  2、假设集群中发生网络分裂, 那么集群可能会分裂为两方, 大多数(majority)的一方包含节点 A 、C 、A1 、B1 和 C1 , 而少数(minority)的一方则包含节点 B 和客户端 Z1 。
  3、在网络分裂期间, 主节点 B 仍然会接受 Z1 发送的写命令:
  4、如果网络分裂出现的时间很短, 那么集群会继续正常运行;
  5、但是, 如果网络分裂出现的时间足够长, 使得大多数一方将从节点 B1 设置为新的主节点, 并使用 B1 来代替原来的主节点 B , 那么 Z1 发送给主节点 B 的写命令将丢失。
  注意, 在网络分裂出现期间, 客户端 Z1 可以向主节点 B 发送写命令的最大时间是有限制的, 这一时间限制称为节点超时时间(node timeout), 是 Redis 集群的一个重要的配置选项。
  q对于大多数一方来说, 如果一个主节点未能在节点超时时间所设定的时限内重新联系上集群, 那么集群会将这个主节点视为下线, 并使用从节点来代替这个主节点继续工作。
  q对于少数一方, 如果一个主节点未能在节点超时时间所设定的时限内重新联系上集群, 那么它将停止处理写命令, 并向客户端报告错误。
第5章 创建并使用Redis集群
5.1 集群模式配置
  Redis 集群由多个运行在集群模式(cluster mode)下的 Redis 实例组成, 实例的集群模式需要通过配置来开启, 开启集群模式的实例将可以使用集群特有的功能和命令。
  以下是一个包含了最少选项的集群配置文件示例:
port 7000  
cluster-enabled yes                     #>> Performing hash slots allocation on 6 nodes...
  
Using 3 masters:
  
10.0.0.16:7000
  
10.0.0.16:7001
  
10.0.0.16:7002
  
Adding replica 10.0.0.16:7003 to 10.0.0.16:7000
  
Adding replica 10.0.0.16:7004 to 10.0.0.16:7001
  
Adding replica 10.0.0.16:7005 to 10.0.0.16:7002
  
M: 62d87bd83fd636e6ba1fe031777178cce8f9f776 10.0.0.16:7000
  
   slots:0-5460 (5461 slots) master
  
M: ccc65af4a214689b15d0cfd9dea584d214a0c2ad 10.0.0.16:7001
  
   slots:5461-10922 (5462 slots) master
  
M: 2366c6765ecf21ee86b064376693ce59047478a5 10.0.0.16:7002
  
   slots:10923-16383 (5461 slots) master
  
S: 19920c1ccf4be5849a1fca5d5f41643a3598cfcc 10.0.0.16:7003
  
   replicates 62d87bd83fd636e6ba1fe031777178cce8f9f776
  
S: 60c3b5d3c1a53328046b627bd015da99e30436c0 10.0.0.16:7004
  
   replicates ccc65af4a214689b15d0cfd9dea584d214a0c2ad
  
S: 287a24936fa3c0c29ce33d768921769cf1969115 10.0.0.16:7005
  
   replicates 2366c6765ecf21ee86b064376693ce59047478a5
  
Can I set the above configuration? (type 'yes' to accept):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 (using node 10.0.0.16:7000)
  
M: 62d87bd83fd636e6ba1fe031777178cce8f9f776 10.0.0.16:7000
  
   slots:0-5460 (5461 slots) master
  
   1 additional replica(s)
  
S: 287a24936fa3c0c29ce33d768921769cf1969115 10.0.0.16:7005
  
   slots: (0 slots) slave
  
   replicates 2366c6765ecf21ee86b064376693ce59047478a5
  
M: ccc65af4a214689b15d0cfd9dea584d214a0c2ad 10.0.0.16:7001
  
   slots:5461-10922 (5462 slots) master
  
   1 additional replica(s)
  
M: 2366c6765ecf21ee86b064376693ce59047478a5 10.0.0.16:7002
  
   slots:10923-16383 (5461 slots) master
  
   1 additional replica(s)
  
S: 60c3b5d3c1a53328046b627bd015da99e30436c0 10.0.0.16:7004
  
   slots: (0 slots) slave
  
   replicates ccc65af4a214689b15d0cfd9dea584d214a0c2ad
  
S: 19920c1ccf4be5849a1fca5d5f41643a3598cfcc 10.0.0.16:7003
  
   slots: (0 slots) slave
  
   replicates 62d87bd83fd636e6ba1fe031777178cce8f9f776
  
All nodes agree about slots configuration.
  
>>> Check for open slots...
  
>>> Check slots coverage...
  
All 16384 slots covered. # set foo bar  
-> Redirected to slot located at 10.0.0.16:7002
  
OK
  
10.0.0.16:7002> set hello world
  
-> Redirected to slot located at 10.0.0.16:7000
  
OK
  
10.0.0.16:7000> get foo
  
-> Redirected to slot located at 10.0.0.16:7002
  
"bar"
  
10.0.0.16:7002> get hello
  
-> Redirected to slot located at 10.0.0.16:7000
  
"world"
  
10.0.0.16:7000>
第6章 集群重新分片
  重新分片操作基本上就是将某些节点上的哈希槽移动到另外一些节点上面, 和创建集群一样, 重新分片也可以使用 redis-trib 程序来执行。
  原hash槽分配:
  10.0.0.16:7000---- 0-5460
  10.0.0.16:7001---- 5461-10922
  10.0.0.16:7002---- 10923-16383
  q执行以下命令可以开始一次重新分片操作:
  ./redis-trib.rb reshard 10.0.0.16:7000
  你只需要指定集群中其中一个节点的地址, redis-trib 就会自动找到集群中的其他节点。目前 redis-trib 只能在管理员的协助下完成重新分片的工作, 要让 redis-trib 自动将哈希槽从一个节点移动到另一个节点, 目前来说还做不到。
  q设定打算移动哈希槽的数量
  执行 redis-trib 的第一步就是设定你打算移动的哈希槽的数量:
>>> Performing Cluster Check (using node 10.0.0.16:7000)  
M: 62d87bd83fd636e6ba1fe031777178cce8f9f776 10.0.0.16:7000
  
   slots:0-5460 (5461 slots) master
  
   1 additional replica(s)
  
S: 287a24936fa3c0c29ce33d768921769cf1969115 10.0.0.16:7005
  
   slots: (0 slots) slave
  
   replicates 2366c6765ecf21ee86b064376693ce59047478a5
  
M: ccc65af4a214689b15d0cfd9dea584d214a0c2ad 10.0.0.16:7001
  
   slots:5461-10922 (5462 slots) master
  
   1 additional replica(s)
  
M: 2366c6765ecf21ee86b064376693ce59047478a5 10.0.0.16:7002
  
   slots:10923-16383 (5461 slots) master
  
   1 additional replica(s)
  
S: 60c3b5d3c1a53328046b627bd015da99e30436c0 10.0.0.16:7004
  
   slots: (0 slots) slave
  
   replicates ccc65af4a214689b15d0cfd9dea584d214a0c2ad
  
S: 19920c1ccf4be5849a1fca5d5f41643a3598cfcc 10.0.0.16:7003
  
   slots: (0 slots) slave
  
   replicates 62d87bd83fd636e6ba1fe031777178cce8f9f776
  
All nodes agree about slots configuration.
  
>>> Check for open slots...
  
>>> Check slots coverage...
  
All 16384 slots covered.
  
How many slots do you want to move (from 1 to 16384)? 1000      #How many slots do you want to move (from 1 to 16384)? 1000  
What is the receiving node ID? 62d87bd83fd636e6ba1fe031777178cce8f9f776
  q设置源节点
  接下来, redis-trib 会向你询问重新分片的源节点(source node),也就是要从哪个节点中取出 1000 个哈希槽, 并将这些槽移动到目标节点上面。如果我们不打算从特定的节点上取出指定数量的哈希槽,那么可以向 redis-trib 输入 all ,这样的话,集群中的所有主节点都会成为源节点, redis-trib 将从各个源节点中各取出一部分哈希槽, 凑够 1000 个, 然后移动到目标节点上面:
What is the receiving node ID? 62d87bd83fd636e6ba1fe031777178cce8f9f776  
Please enter all the source node IDs.
  
Type 'all' to use all the nodes as source nodes for the hash slots.
  
Type 'done' once you entered all the source nodes IDs.
  
Source node #1:all      #>> Performing Cluster Check (using node 10.0.0.16:7000)
  
M: 62d87bd83fd636e6ba1fe031777178cce8f9f776 10.0.0.16:7000
  
   slots:0-5961,10923-11421 (6461 slots) master
  
   1 additional replica(s)
  
S: 287a24936fa3c0c29ce33d768921769cf1969115 10.0.0.16:7005
  
   slots: (0 slots) slave
  
   replicates 2366c6765ecf21ee86b064376693ce59047478a5
  
M: ccc65af4a214689b15d0cfd9dea584d214a0c2ad 10.0.0.16:7001
  
   slots:5962-10922 (4961 slots) master
  
   1 additional replica(s)
  
M: 2366c6765ecf21ee86b064376693ce59047478a5 10.0.0.16:7002
  
   slots:11422-16383 (4962 slots) master
  
   1 additional replica(s)
  
S: 60c3b5d3c1a53328046b627bd015da99e30436c0 10.0.0.16:7004
  
   slots: (0 slots) slave
  
   replicates ccc65af4a214689b15d0cfd9dea584d214a0c2ad
  
S: 19920c1ccf4be5849a1fca5d5f41643a3598cfcc 10.0.0.16:7003
  
   slots: (0 slots) slave
  
   replicates 62d87bd83fd636e6ba1fe031777178cce8f9f776
  
All nodes agree about slots configuration.
  
>>> Check for open slots...
  
>>> Check slots coverage...
  
All 16384 slots covered.
  需要注意的就是, 在三个主节点中, 节点 127.0.0.1:7000 包含了 6461 个哈希槽, 而节点 127.0.0.1:7001 和节点 127.0.0.1:7002 都只包含了 4961 个哈希槽, 因为后两者都将自己的 500 个哈希槽移动到了节点 127.0.0.1:7000 。
第7章 集群节点管理
7.1 添加节点
  根据新添加节点的种类, 我们需要用两种方法来将新节点添加到集群里面:
  q如果要添加的新节点是一个主节点, 那么我们需要创建一个空节点(empty node), 然后将某些哈希槽移动到这个空节点里面。
  q如果要添加的新节点是一个从节点, 那么我们需要将这个新节点设置为集群中某个节点的复制品(replica)。
7.1.1 新增一个空的节点
  同理,再启动一个新的7006端口的Redis节点,过程见redis(一)、入门。
7.1.2 新增节点加入集群
  执行以下命令, 将这个新节点添加到集群里面:
./redis-trib.rb add-node 10.0.0.16:7006 10.0.0.16:7000  命令中的 add-node 表示我们要让 redis-trib 将一个节点添加到集群里面, add-node 之后跟着的是新节点的 IP 地址和端口号, 再之后跟着的是集群中任意一个已存在节点的 IP 地址和端口号, 这里我们使用的是 10.0.0.16:7000 。
  通过 cluster nodes 命令, 我们可以确认新节点 10.0.0.16:7006 已经被添加到集群里面了:
# redis-cli -c -h 10.0.0.16 -p 7000 cluster nodes  
287a24936fa3c0c29ce33d768921769cf1969115 10.0.0.16:7005 slave 2366c6765ecf21ee86b064376693ce59047478a5 0 1523112658032 6 connected
  
ccc65af4a214689b15d0cfd9dea584d214a0c2ad 10.0.0.16:7001 master - 0 1523112656012 8 connected 0-565 5962-10922 11422-11855
  
2366c6765ecf21ee86b064376693ce59047478a5 10.0.0.16:7002 master - 0 1523112651972 3 connected 11856-16383
  
62d87bd83fd636e6ba1fe031777178cce8f9f776 10.0.0.16:7000 myself,master - 0 0 7 connected 566-5961 10923-11421
  
60c3b5d3c1a53328046b627bd015da99e30436c0 10.0.0.16:7004 slave ccc65af4a214689b15d0cfd9dea584d214a0c2ad 0 1523112655003 8 connected
  
96fdc35b69c4f0929ba9ba5550a5fca8f3b0b514 10.0.0.16:7006 master - 0 1523112657022 0 connected
  
19920c1ccf4be5849a1fca5d5f41643a3598cfcc 10.0.0.16:7003 slave 62d87bd83fd636e6ba1fe031777178cce8f9f776 0 1523112652982 7 connected
  新节点现在已经连接上了集群, 成为集群的一份子, 并且可以对客户端的命令请求进行转向了, 但是和其他主节点相比, 新节点还有两点区别:
  1、新节点没有包含任何数据, 因为它没有包含任何哈希槽。
  2、尽管新节点没有包含任何哈希槽, 但它仍然是一个主节点, 所以在集群需要将某个从节点升级为新的主节点时, 这个新节点不会被选中。
7.1.3 添加为主节点
  当把节点添加进集群的时候,已经默认设置为主节点了,只是该节点没有数据而已。这时只需要我们将哈希槽移动到新的节点里面,新节点就会成为真正的主节点了。
  详细过程见第六章。
7.1.4 添加为slave节点
  使用客户端连接上新节点,并运行如下命令:
# redis-cli -c -h 10.0.0.16 -p 7006  
10.0.0.16:7006> cluster replicate 62d87bd83fd636e6ba1fe031777178cce8f9f776
  
OK
  
10.0.0.16:7006>
  注:以上这条命令也适合于随时修改从节点的master。
  q一步到位法:
redis-trib.rb add-node --slave --master-id 62d87bd83fd636e6ba1fe031777178cce8f9f77 10.0.0.16:7006 10.0.0.16:7000  
--slave:表示添加的是从节点
  
--master-id 62d87bd83fd636e6ba1fe031777178cce8f9f77:主节点的node id
  
10.0.0.16:7006:新的节点
  
10.0.0.16:7000:任何一个集群中的旧节点
  查看是否设置成功:
# redis-cli -c -h 10.0.0.16 -p 7000 cluster nodes | grep slave  
287a24936fa3c0c29ce33d768921769cf1969115 10.0.0.16:7005 slave 2366c6765ecf21ee86b064376693ce59047478a5 0 1523113268561 6 connected
  
60c3b5d3c1a53328046b627bd015da99e30436c0 10.0.0.16:7004 slave ccc65af4a214689b15d0cfd9dea584d214a0c2ad 0 1523113270579 8 connected
  
96fdc35b69c4f0929ba9ba5550a5fca8f3b0b514 10.0.0.16:7006 slave 62d87bd83fd636e6ba1fe031777178cce8f9f776 0 1523113269569 9 connected
  
19920c1ccf4be5849a1fca5d5f41643a3598cfcc 10.0.0.16:7003 slave 62d87bd83fd636e6ba1fe031777178cce8f9f776 0 1523113267550 7 connected
  
# cluster replicate 62d87bd83fd636e6ba1fe031777178cce8f9f776  q如果主节点有solt,去掉分配的solt
  详细过程见第6章,只需要把all替换为需删除的主节点即可。
  q删除主节点
/opt/redis/src/redis-trib.rb del-node 10.0.0.16:7006 '96fdc35b69c4f0929ba9ba5550a5fca8f3b0b514'第8章 Redis Cluster相关命令
//集群(cluster)  
CLUSTER INFO #
页: [1]
查看完整版本: Redis(五)、Redis数据库集群相关