redis高可用集群-redis cluster(cluster集群)简介和配置(3)
前面我介绍了 redis sentinel,既然有了sentinel,为什么还要一个cluster呢?
因为随着业务量的增加,不可避免要对redis进行扩容,扩容方式一般由2种:1. 垂直扩容 2. 水平扩容
垂直扩容:增加内存方式来增加整个缓存系统容量。比如从2G增加到4G
水平扩容:通过增加节点的方式来增加整个缓存系统的容量。 这种方式一般需要应用程序支持。
垂直扩容比较方便,但是受制于机制内存的限制,一个机器不可能无限增大内存, 所以到了一定阶段肯定要进行水平扩容。
但是水平扩容,就会涉及到数据迁移。 而迁移过程中,一方面要保持业务可用,另一方面也要尽量保证数据不丢失。 但是 sentinel 在这方面
几乎没有作用。 针对这些问题,redis的作者就开发出了一个解决方案 redis cluster, 所以redis cluster就应运而生了。
一:Redis Cluster 集群简介
------------------------------------------------------------------------------------------------------------------------------
Redis Cluster是Redis官方出的一个分布式解决方案, 是在Redis3.0正式版推出的,有效解决了Redis在单机、并发、流量等方面的瓶颈。
Redis 集群是一个可以在多个 Redis 节点之间进行数据共享的设施(installation)。
Redis 集群不支持那些需要同时处理多个键的 Redis 命令, 因为执行这些命令需要在多个 Redis 节点之间移动数据, 并且在高负载的情况下, 这些命令将降低 Redis 集群的性能, 并导致不可预测的行为。
Redis 集群通过分区(partition)来提供一定程度的可用性(availability): 即使集群中有一部分节点失效或者无法进行通讯, 集群也可以继续处理命令请求。
Redis 集群提供了以下两个好处:
- 将数据自动切分(split)到多个节点的能力。
- 当集群中的一部分节点失效或者无法进行通讯时, 仍然可以继续处理命令请求的能力
Redis 集群节点之间相互关系:
二:Redis分布式集群数据解决方案
-------------------------------------------------------------------------------------------------------------------------------------
一般分布式集群首要解决把整个数据集按照分区规则映射到多个节点的问题,即把数据集划分到多个节点上,每个节点负责整个数据的一个子集。
Redis集群使用数据分片(sharding)来提供数据分布的解决方案, 而不是 一致性哈希(consistency hashing)来实现的。
一个 Redis 集群包含 16384 个哈希槽(hash slot),范围是(0-16383), 数据库中的每个键都属于这 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 就可以了。
因为将一个哈希槽从一个节点移动到另一个节点不会造成节点阻塞, 所以无论是添加新节点还是移除已存在节点, 又或者改变某个节点包含的哈希槽数量, 都不会造成集群下线。
例子中的Redis 集群分区 和 槽范围示意图:
三:Redis集群中的主从复制
-----------------------------------------------------------------------------------------------------------------------------
为了使得集群在一部分节点下线或者无法与集群的大多数(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 集群还是会停止运作。
四:Redis集群数据一致性保证
---------------------------------------------------------------------------------------------------------------------------------
Redis 集群不保证数据的强一致性(strong consistency): 在特定条件下, Redis 集群可能会丢失已经被执行过的写命令。
使用异步复制(asynchronous replication)是 Redis 集群可能会丢失写命令的其中一个原因。 考虑以下这个写命令的例子:
客户端向主节点 B 发送一条写命令。
主节点 B 执行写命令,并向客户端返回命令回复。
主节点 B 将刚刚执行的写命令复制给它的从节点 B1 、 B2 和 B3 。
如你所见, 主节点对命令的复制工作发生在返回命令回复之后, 因为如果每次处理命令请求都需要等待复制操作完成的话, 那么主节点处理命令请求的速度将极大地降低 —— 我们必须在性能和一致性之间做出权衡。
Redis 集群另外一种可能会丢失命令的情况是, 集群出现网络分裂(network partition), 并且一个客户端与至少包括一个主节点在内的少数(minority)实例被孤立。
五:Redis集群配置
---------------------------------------------------------------------------------------------------------------------------
要让集群正常工作至少需要3个主节点,在这里我们要创建6个redis节点,其中三个为主节点,三个为从节点,对应的redis节点的ip和端口对应关系如下(为了简单演示都在同一台机器上面)
1. 下载版本,创建相应目录
前面我下载了redis版本,并且安装在了/usr/local/redis/ 下, 为了创建Redis集群配置,我们在这个目录下创建一个目录,make ./data/cluster,
然后在里面创建6个目录, cd ./data/cluster, mkdir 7000 7001 7002 7003 7004 7005
2. 需要配置文件
cp redis/redis.conf /usr/local/redis/data/cluster/7000/
修改配置项目:vi /usr/local/redis/data/cluster/7000/redis.conf
port 7000 daemonize yes cluster-enabled yes cluster-config-file nodes.conf cluster-node-timeout 5000 appendonly yes
文件中的 cluster-enabled 选项用于开实例的集群模式, 而 cluster-conf-file 选项则设定了保存节点配置文件的路径, 默认值为nodes.conf 。其他参数相信童鞋们都知道。节点配置文件无须人为修改, 它由 Redis 集群在启动时创建, 并在有需要时自动进行更新。
修改完成后,把修改完成的redis.conf复制到7001-7005目录下,并且端口修改成和文件夹对应。
3. 分别启动6个实例
# cd ../7001 # /usr/local/redis/bin/redis-server redis.conf # cd ../7002 # /usr/local/redis/bin/redis-server redis.conf # cd ../7003 # /usr/local/redis/bin/redis-server redis.conf # cd ../7004 # /usr/local/redis/bin/redis-server redis.conf # cd ../7005 # /usr/local/redis/bin/redis-server redis.conf
查看进程是否存在
# ps aux|grep redis root 23024 0.0 0.4 136932 7540 ? Ssl 21:28 0:00 /usr/local/redis/bin/redis-server 127.0.0.1:7000 [cluster] root 23136 0.0 0.4 136932 7536 ? Ssl 21:28 0:00 /usr/local/redis/bin/redis-server 127.0.0.1:7001 [cluster] root 23170 0.0 0.4 136932 7536 ? Ssl 21:28 0:00 /usr/local/redis/bin/redis-server 127.0.0.1:7002 [cluster] root 23188 0.0 0.4 136932 7536 ? Ssl 21:28 0:00 /usr/local/redis/bin/redis-server 127.0.0.1:7003 [cluster] root 23218 0.1 0.4 136932 7536 ? Ssl 21:28 0:00 /usr/local/redis/bin/redis-server 127.0.0.1:7004 [cluster] root 23276 0.0 0.4 136932 7540 ? Ssl 21:29 0:00 /usr/local/redis/bin/redis-server 127.0.0.1:7005 [cluster]
4. 执行创建集群的命令
首先安装ruby的依赖:
yum install ruby rubygems -y
安装gem-redis:
下载地址:wget https://rubygems.org/gems/redis/versions/3.2.2
注意:上面下载下来就是一个 3.2.2 这样命名的文件
用命令安装gem redis:
# gem install redis -v 3.2.2 Fetching: redis-3.2.2.gem (100%) Successfully installed redis-3.2.2 Parsing documentation for redis-3.2.2 Installing ri documentation for redis-3.2.2 1 gem installed
5. 复制集群管理程序到/usr/local/bin
cp /redis-3.2.9/src/redis-trib.rb /usr/local/bin/redis-trib
6. 创建集群:
redis-trib 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
# redis-trib 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 >>> Creating cluster >>> Performing hash slots allocation on 6 nodes... Using 3 masters: 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 Adding replica 127.0.0.1:7003 to 127.0.0.1:7000 Adding replica 127.0.0.1:7004 to 127.0.0.1:7001 Adding replica 127.0.0.1:7005 to 127.0.0.1:7002 M: 49b3e7a05b680484f959f91d3b7b7caa2c991908 127.0.0.1:7000 slots:0-5460 (5461 slots) master M: 3d99267c015d1f38170b03ebec9718d2914ce484 127.0.0.1:7001 slots:5461-10922 (5462 slots) master M: 9d9c0a5993c5a36e04a77f2fc36a10e72f117d1d 127.0.0.1:7002 slots:10923-16383 (5461 slots) master S: c43ecfb119f0a47bc1f53acf7d7ec40001b5de35 127.0.0.1:7003 replicates 49b3e7a05b680484f959f91d3b7b7caa2c991908 S: 560206fd404c7fe81ef9a9a20c35c2dc09a588f8 127.0.0.1:7004 replicates 3d99267c015d1f38170b03ebec9718d2914ce484 S: 104d81494a1688296677c5bc9d4d10c81a523ede 127.0.0.1:7005 replicates 9d9c0a5993c5a36e04a77f2fc36a10e72f117d1d Can I set the above configuration? (type 'yes' to accept):
输入 yes 后, 集群就会将配置应用到各个节点, 并连接起(join)各个节点 —— 也即是, 让各个节点开始互相通讯:
这个是接上面
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 127.0.0.1:7000) M: 49b3e7a05b680484f959f91d3b7b7caa2c991908 127.0.0.1:7000 slots:0-5460 (5461 slots) master 1 additional replica(s) M: 3d99267c015d1f38170b03ebec9718d2914ce484 127.0.0.1:7001 slots:5461-10922 (5462 slots) master 1 additional replica(s) S: 104d81494a1688296677c5bc9d4d10c81a523ede 127.0.0.1:7005 slots: (0 slots) slave replicates 9d9c0a5993c5a36e04a77f2fc36a10e72f117d1d S: 560206fd404c7fe81ef9a9a20c35c2dc09a588f8 127.0.0.1:7004 slots: (0 slots) slave replicates 3d99267c015d1f38170b03ebec9718d2914ce484 M: 9d9c0a5993c5a36e04a77f2fc36a10e72f117d1d 127.0.0.1:7002 slots:10923-16383 (5461 slots) master 1 additional replica(s) S: c43ecfb119f0a47bc1f53acf7d7ec40001b5de35 127.0.0.1:7003 slots: (0 slots) slave replicates 49b3e7a05b680484f959f91d3b7b7caa2c991908 [OK] All nodes agree about slots configuration. >>> Check for open slots... >>> Check slots coverage... [OK] All 16384 slots covered.
上面最后出现 2个 ok,正常安装完成
六:测试使用
---------------------------------------------------------------------------------------------------------------------------
我们用自带的 redis-cli 客户端来测试,在你的/redis/src/redis-cli
可以使用命令 redis-cli -c 来启动
增加一个值:
# redis-cli -c -p 7001 127.0.0.1:7001> set name cluster-test OK 127.0.0.1:7001> get name "cluster-test" 127.0.0.1:7001> set hello world -> Redirected to slot [866] located at 127.0.0.1:7000 OK 127.0.0.1:7000> get hello "world" 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> get foo "bar"
查看集群node信息
# redis-cli -p 7000 cluster nodes 3d99267c015d1f38170b03ebec9718d2914ce484 127.0.0.1:7001 master - 0 1533916800784 2 connected 5461-10922 104d81494a1688296677c5bc9d4d10c81a523ede 127.0.0.1:7005 slave 9d9c0a5993c5a36e04a77f2fc36a10e72f117d1d 0 1533916800784 6 connected 560206fd404c7fe81ef9a9a20c35c2dc09a588f8 127.0.0.1:7004 slave 3d99267c015d1f38170b03ebec9718d2914ce484 0 1533916800281 5 connected 49b3e7a05b680484f959f91d3b7b7caa2c991908 127.0.0.1:7000 myself,master - 0 0 1 connected 0-5460 9d9c0a5993c5a36e04a77f2fc36a10e72f117d1d 127.0.0.1:7002 master - 0 1533916800281 3 connected 10923-16383 c43ecfb119f0a47bc1f53acf7d7ec40001b5de35 127.0.0.1:7003 slave 49b3e7a05b680484f959f91d3b7b7caa2c991908 0 1533916800284 4 connected
参考:
http://redisdoc.com/topic/cluster-tutorial.html#
http://www.cnblogs.com/gomysql/p/4395504.html