开发者社区> 技术小能手> 正文
阿里云
为了无法计算的价值
打开APP
阿里云APP内打开

Redis集群搭建

简介: Redis集群搭建
+关注继续查看

Redis 是一个开源的 key-value 存储系统,由于出众的性能,大部分互联网企业都用来做服务器端缓存。Redis 在3.0版本前只支持单实例模式,虽然支持主从模式、哨兵模式部署来解决单点故障,但是现在互联网企业动辄大几百G的数据,可完全是没法满足业务的需求,所以,Redis 在 3.0 版本以后就推出了集群模式。

Redis 集群采用了P2P的模式,完全去中心化。Redis 把所有的 Key 分成了 16384 个 slot,每个 Redis 实例负责其中一部分 slot 。集群中的所有信息(节点、端口、slot等),都通过节点之间定期的数据交换而更新。
Redis 客户端可以在任意一个 Redis 实例发出请求,如果所需数据不在该实例中,通过重定向命令引导客户端访问所需的实例。

安装环境
OS: centos 7.2.1511
redis : 最新版 v4.0.1

单台redis安装
下载

wget http://download.redis.io/releases/redis-4.0.10.tar.gz
tar zxvf redis-4.0.10.tar.gz
mv redis-4.0.10 /usr/local/redis/

如果是离线安装,则需要从官网下载指定版本,然后上传到生产环境。这里安装的是最新版redis,指定安装路径 /usr/local/redis/

编译安装

cd /usr/local/redis
make
make install

安装完成,这时候会在/usr/local/bin/目录下看到redis-server、redis-cli等可执行脚本,进入看一下,如果没有,就要去解压目录复制进去了。

image

配置redis.conf
redis.conf在默认在安装目录下

$ vim /usr/local/redis/redis.conf

这里要修改两个地方,一个bind和daemonize就行。

要注意的点:
bind这里配置要注意,默认是只有一个127.0.0.1,这个时候只能自己连接,其他局域网内是连接不上的。所以,需要配置多个 IP ,这样就可以局域网内进行连接了。我设置的0.0.0.0,虽然这不太安全,方便我在其它地方连接。
daemonize是设置是否后台启动 Redis,默认no,正常都需要以服务形式启动 Redis,所以这里设置为yes。
可以设置密码 requirepass mypassord
redis v3.0+版本增加了保护机制,默认protected-mode yes, 这样目标机器调用可能会报错,需要设置为no

关于更多配置文件参数的解释,可以参考:
https://github.com/linli8/cnblogs/blob/master/redis%E5%89%AF%E6%9C%AC.conf

启动redis

cd /usr/local/bin/
redis-server /usr/local/redis/redis.conf

测试redis服务
端口已开启:

netstat -anp | grep 6379

命令行连接:

  redis redis-cli
127.0.0.1:6379> keys *
1) "city"
2) "usage"
3) "idc"
4) "region"
127.0.0.1:6379> set name jzhou
OK
127.0.0.1:6379> get name
"jzhou"
127.0.0.1:6379>

关闭服务
可以通过杀进程的方式强制关闭服务,也可以通过命令:

redis-cli shutdown

通过 netstat 可以看出来端口已经是TIME_WAIT状态了

以上是centos7单机部署redis的过程,下面集群搭建和上述类似,不过在目录结构和配置文件不同,当然,遇到的坑也多,主要配置集群依赖一些外部包,但说实话光搭建个集群是没有啥技术含量但.....

redis集群搭建
简介
redis-cluster架构设计

image

架构细节:
所有的redis节点彼此互联(PING-PONG机制),内部使用二进制协议优化传输速度和带宽.
节点的fail是通过集群中超过半数的节点检测失效时才生效.
客户端与redis节点直连,不需要中间proxy层.客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可
redis-cluster把所有的物理节点映射到[0-16383]slot上,cluster 负责维护node<->slot<->key
Redis集群预分好16384个桶,当需要在 Redis 集群中放置一个 key-value 时,根据 CRC16(key) mod 16384的值,决定将一个key放到哪个桶中。

环境准备
Redis集群中要求奇数节点,所以至少要有三个节点,并且每个节点至少有一备份节点,所以至少需要6个redis服务实例。

这里演示的是我搭的生产环境redis集群,3台服务器,每台起3个服务,共9个节点,生产环境搭建的很顺利,但测试环境一台服务器开6个端口遇到了很多问题,各种依赖包问题,后续会说明。

三台服务器

172.28.37.29
172.28.37.30
172.18.38.219
(每台服务器redis三个端口号 7000~7002)

按照上面搭建单台redis服务的方式在三台服务器分别安装redis,从配置文件开始会有所不同。下面会说明搭建过程。

依赖包安装
注意,下述均安装最新版本,否则会和redis版本不匹配

lib
zlib
ruby
rubugems

开始集群搭建
1.准备目录结构
三台机器一样,建立如下目录结构:

$ mkdir -p /usr/local/redis/redis-cluster/{7000,7001,7002}

分别进入每个端口目录创建配置文件:

cd  /usr/local/redis/redis-cluster/7000 && touch redis.conf
port 7000   # 端口7000,7001,7002,与目录对应
bind 172.28.37.29 #默认ip为127.0.0.1,需要改为其他节点机器可访问的ip,否则创建集群时无法访问对应的端口,无法创建集群
daemonize yes   #redis后台运行
cluster-enabled yes  #开启集群
cluster-config-file nodes_7000.conf  #集群的配置,配置文件首次启动自动生成 7000,7001,7002  
cluster-node-timeout 8000   #请求超时,默认15秒,可自行设置
appendonly yes  #开启aof持久化模式,每次写操作请求都追加到appendonly.aof文件中
appendfsync always  #每次有写操作的时候都同步
logfile "/data/redis/logs/redis.log" #redis服务日志
pidfile /var/run/redis_7000.pid  #pidfile文件对应7000,7001,7002

注意,上述有些配置项要对应服务和目录,三个目录按照上述配置好后,启动服务

3.启动/关闭集群服务
可以在每个服务器上写一个启动脚本start-redis.sh:

for((i=0;i<3;i++)); 
do /usr/local/bin/redis-server /usr/local/redis/redis-cluster/700$i/redis.conf; 
done

关闭服务类似:
for((i=0;i<=2;i++));
do /usr/local/bin/redis-cli -c -h $IP -p 700$i shutdown;
done
$IP分别为三台服务器IP。

这时只是启动了9个单独的redis服务,它们还不是一个集群,下面就说明创建集群

4.创建集群
注意:在任意一台上运行 不要在每台机器上都运行,一台就够了

Redis 官方提供了 redis-trib.rb 这个工具,就在解压目录的 src 目录中

在其中一台执行:

$ cd /root/redis-4.0.10/src
$ ./redis-trib.rb create --replicas 1 172.28.37.29:7000 172.28.37.29:7001 172.28.37.29:7002 172.28.37.30:7000 172.28.37.30:7001 172.28.37.30:7002 172.18.38.219:7000 172.18.38.219:7001 172.18.38.219:7002

敲完这个命令后会提示是否按照默认的推荐方式配置集群主从,一般选yes就行了

image

截图中看出,推荐了4个masters,5个从节点

>>> Creating cluster
>>> Performing hash slots allocation on 9 nodes...
Using 4 masters:
172.28.37.29:7000
172.28.37.30:7000
172.18.38.219:7000
172.28.37.29:7001
Adding replica 172.18.38.219:7001 to 172.28.37.29:7000
Adding replica 172.28.37.29:7002 to 172.28.37.30:7000
Adding replica 172.28.37.30:7002 to 172.18.38.219:7000
Adding replica 172.18.38.219:7002 to 172.28.37.29:7001
Adding replica 172.28.37.30:7001 to 172.28.37.29:7000

下面这个显示了集群和slot分配结果

image

5.集群验证
参数 -C 可连接到集群,因为 redis.conf 将 bind 改为了ip地址,所以 -h 参数不可以省略,-p 参数为端口号

[root@172-28-37-29 src]# redis-cli -c -p 7000 -h 172.28.37.29
172.28.37.29:7000> set name zhoujie
-> Redirected to slot [5798] located at 172.28.37.30:7000
OK
172.28.37.30:7000> get name
"zhoujie"
172.28.37.30:7000>

可以看到在29的7000上设置了name,重定向到了30的7000节点。到此为止集群搭建成功!

友情提示:
当出现集群无法启动时,删除集群配置文件,再次重新启动每一个redis服务,然后重新构件集群环境。

redis-trib.rb命令常见用法
1)列出集群节点-cluster nodes

[root@172-28-37-30 src]# redis-cli -h 172.28.37.30  -c -p 7000
172.28.37.30:7000> cluster nodes
0d260c47f10ecbbfd9c3c1707da82a3dd7951313 172.18.38.219:7001@17001 slave f85a9a80aca5e4c4a1437c7b58abd5895ee66855 0 1531497002061 8 connected
6d3db545319a8d41f4ad0666885856257fc2ab5f 172.18.38.219:7002@17002 slave 0cdeba26690238582ad7705abac6de71d1817c9e 0 1531497002062 9 connected
3f6c1449e60fe0d868e0bdc655165419ed7cd193 172.18.38.219:7000@17000 master - 0 1531497003000 7 connected 8192-12287
4004ad507da2e7cbae465d7f01864d53972f595c 172.28.37.30:7002@17002 slave 3f6c1449e60fe0d868e0bdc655165419ed7cd193 0 1531497003062 7 connected
f85a9a80aca5e4c4a1437c7b58abd5895ee66855 172.28.37.29:7000@17000 master - 0 1531497004064 1 connected 0-4095
7fc5072406e47cd58822f17f5e1ce3b15328352e 172.28.37.30:7000@17000 myself,master - 0 1531497002000 4 connected 4096-8191
fb4554a4fa2bd4af1c213b90ec32d3f7fb12e87b 172.28.37.30:7001@17001 slave f85a9a80aca5e4c4a1437c7b58abd5895ee66855 0 1531497005066 5 connected
967243e807a1c0c32ad56db47007c54a2d1d6e2e 172.28.37.29:7002@17002 slave 7fc5072406e47cd58822f17f5e1ce3b15328352e 0 1531497004064 4 connected
0cdeba26690238582ad7705abac6de71d1817c9e 172.28.37.29:7001@17001 master - 0 1531497004064 2 connected 12288-16383
172.28.37.30:7000>

2)查看集群信息- cluster info

172.28.37.30:7000> cluster info
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:9
cluster_size:4
cluster_current_epoch:9
cluster_my_epoch:4
cluster_stats_messages_ping_sent:2243335
cluster_stats_messages_pong_sent:2220197
cluster_stats_messages_meet_sent:4
cluster_stats_messages_sent:4463536
cluster_stats_messages_ping_received:2220192
cluster_stats_messages_pong_received:2243339
cluster_stats_messages_meet_received:5
cluster_stats_messages_received:4463536
172.28.37.30:7000>

3)检查集群状态-check
下面内容是测试环境搭建的,一台服务器6个节点

[root@192-168-151-110 redis]# /root/redis-4.0.10/src/redis-trib.rb check 192.168.151.110:7000
>>> Performing Cluster Check (using node 192.168.151.110:7000)
M: 7bf58adaafbfee1643785ea7b5da723d6595bbaf 192.168.151.110:7000
  slots:0-5460 (5461 slots) master
additional replica(s)
S: 90072487e6227544c079b2d8214ef5fd050575b5 192.168.151.110:7004
  slots: (0 slots) slave
  replicates f7374d1b48562c9e54523948915c99bb00a12ba7
M: c6cf17370fc94aabc88e862fa72229ebd9b94166 192.168.151.110:7002
  slots:10923-16383 (5461 slots) master
additional replica(s)
S: 59d25294cbfb63f2d4d75410e66ce58899c65469 192.168.151.110:7003
  slots: (0 slots) slave
  replicates 7bf58adaafbfee1643785ea7b5da723d6595bbaf
S: 6256051389337640691e4b44d7de2b7b8c8fa25f 192.168.151.110:7005
  slots: (0 slots) slave
  replicates c6cf17370fc94aabc88e862fa72229ebd9b94166
M: f7374d1b48562c9e54523948915c99bb00a12ba7 192.168.151.110:7001
  slots:5461-10922 (5462 slots) master
additional replica(s)
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
[root@192-168-151-110 redis]#

4)其它常用命令
create:创建一个集群环境host1:port1 ... hostN:portN(集群中的主从节点比例)
call:可以执行redis命令
add-node:将一个节点添加到集群里,第一个参数为新节点的ip:port,第二个参数为集群中任意一个已经存在的节点的ip:port
del-node:移除一个节点
reshard:重新分片

集群操作

//集群(cluster)

CLUSTER INFO 打印集群的信息

CLUSTER NODES 列出集群当前已知的所有节点(node),以及这些节点的相关信息。

//节点(node)

CLUSTER MEET <ip> <port> 将 ip 和 port 所指定的节点添加到集群当中,让它成为集群的一份子。

CLUSTER FORGET <node_id> 从集群中移除 node_id 指定的节点。

CLUSTER REPLICATE <node_id> 将当前节点设置为 node_id 指定的节点的从节点。

CLUSTER SAVECONFIG 将节点的配置文件保存到硬盘里面。

//槽(slot)

CLUSTER ADDSLOTS <slot> [slot ...] 将一个或多个槽(slot)指派(assign)给当前节点。

CLUSTER DELSLOTS <slot> [slot ...] 移除一个或多个槽对当前节点的指派。

CLUSTER FLUSHSLOTS 移除指派给当前节点的所有槽,让当前节点变成一个没有指派任何槽的节点。

CLUSTER SETSLOT <slot> NODE <node_id> 将槽 slot 指派给 node_id 指定的节点,如果槽已经指派给另一个节点,那么先让另一个节点删除该槽>,然后再进行指派。

CLUSTER SETSLOT <slot> MIGRATING <node_id> 将本节点的槽 slot 迁移到 node_id 指定的节点中。

CLUSTER SETSLOT <slot> IMPORTING <node_id> 从 node_id 指定的节点中导入槽 slot 到本节点。

CLUSTER SETSLOT <slot> STABLE 取消对槽 slot 的导入(import)或者迁移(migrate)。

//键 (key)

CLUSTER KEYSLOT <key> 计算键 key 应该被放置在哪个槽上。

CLUSTER COUNTKEYSINSLOT <slot> 返回槽 slot 目前包含的键值对数量。

CLUSTER GETKEYSINSLOT <slot> <count> 返回 count 个 slot 槽中的键。

向集群中添加节点或删除节点
我们新建两个服务,按照之前搭建的集群方式新增俩个节点:(一主一从 master、slave)。
Mater:7007 slave:7008
创建7007/7008文件夹。拷贝redis.conf文件到对于的7007,7008目录下 ,再进行修改配置文件。
启动7007和7008俩个服务并查看服务状态。

1.集群中添加一个主节点
步骤一:使用add-node命令:绿色为新增节点,红色为已知存在节点

[root@wlan124 local]# /usr/local/redis/src/redis-trib.rb add-node 192.168.151.110:7007   
192.168.151.110:7001

注意:当添加节点成功以后,新增的节点不会有任何数据,因为他没有分配任何slot。需要为新节点手动分配slot。

步骤二:reshard命令,分配slot:

[root@wlan124 local]# /usr/local/redis-3.0.0/src/redis-trib.rb reshard  
192.168.151.110:7007

提示一

How many slots do you want to move (from 1 to 16384)? 2000

提示二

What is the receiving node ID? 382634a4025778c040b7213453fd42a709f79e28

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

提示三

Do you want to proceed with the proposed reshard plan (yes/no)? yes

提示一:是希望你需要多少个槽移动到新的节点上,可以自己设置,比如200个槽。
提示二:是你需要把这200个slot槽移动到那个节点上去(需要指定节点id),并且下个提示是输入all为从所有主节点(7001 7002 7003)中分别抽取相应的槽数(一共为200个槽到指定的新节点中!,并且会打印执行分片的计划。)
提示三:输入yes确认开始执行分片任务

2.集群中添加一个从节点
步骤一:使用add-node命令:绿色为新增节点,红色为已知存在节点

[root@wlan124 local]# /usr/local/redis/src/redis-trib.rb add-node 192.168.151.110:7008  
192.168.151.110:7001

步骤二:首先需要登录到7008节点的客户端,然后使用集群命令,执行replicate命令来指定当前节点的主节点id为哪一个。把当前的7008(slave)节点指定到一个主节点下(这里使用之前创建的7007主节点,绿色表示节点id)。

[root@wlan124 ~]# /usr/local/redis/bin/redis-cli -c -h 192.168.151.110 -p 7008

192.168.1.124:7008> cluster replicate 4d4cb840519eef342a5730168b6c7e14dd811542

(7007的id)

OK

3.集群中删除一个主节点
如果主节点有从节点,将从节点转移到其他主节点。如果主节点有slot,先将主节点里的slot分配到其他可用节点中,然后再删除节点才行,否则会有数据的丢失。

步骤一:删除7007(master)节点之前,我们需要先把其全部的数据(slot槽)移动到其他节点上去(目前只能把master的数据迁移到一个节点上,暂时做不了平均分配功能)。

[root@wlan124 ~]# /usr/local/redis/src/redis-trib.rb reshard 192.168.151.110:7007

How many slots do you want to move (from 1 to 16384)? 1999

(注释:这里不会是正好200个槽)

What is the receiving node ID? 614d0def75663f2620b6402a017014b57c912dad

(注释:这里是需要把数据移动到哪?7001的主节点id)

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:4d4cb840519eef342a5730168b6c7e14dd811542

(注释:这里是需要数据源,也就是我们的7007节点id)

Source node #2:done

(注释:这里直接输入done 开始生成迁移计划)

Do you want to proceed with the proposed reshard plan (yes/no)? yes

(注释:这里输入yes开始迁移)

步骤二:最后我们直接使用del-node命令删除7007主节点即可(蓝色表示7007的节点id)。

[root@wlan124 ~]# /usr/local/redis-3.0.0/src/redis-trib.rb del-node 192.168.151.110:7007 4d4cb840519eef342a5730168b6c7e14dd811542

4.集群中删除一个从节点
步骤一:删除从节点7008,输入del-node命令,指定删除节点ip和端口,以及节点id(蓝色为7008节点id),移除了7008 slave节点,前节点的服务进程也会随之销毁。

[root@wlan124 ~]# /usr/local/redis-3.0.0/src/redis-trib.rb del-node 192.168.151.110:7008 a78c8a41f6430b51a7eca1fdb50092c463a8f1ac

nodejs连接redis集群示例
目前用得最多的 Node.js Redis 库是 node redis,不过这个库基本已经不再维护了,存在很多 bug(在生产环境中碰到过),也缺失了很多功能(如 pipeling 和脚本优化)。而 ioredis 不仅支持了 Cluster 和 Sentinel,还在 API 层面和 node redis 保持了兼容。

const Redis = require('ioredis');
let redis_members = [{
 port: 7000,
 host: '172.28.37.29'
}, {
 port: 7001,
 host: '172.28.37.29'
}, {
 port: 7002,
 host: '172.28.37.29'
}, {
 port: 7000,
 host: '172.28.37.30'
}, {
 port: 7001,
 host: '172.28.37.30'
}, {
 port: 7002,
 host: '172.28.37.30'
}, {
 port: 7000,
 host: '172.18.38.219'
}, {
 port: 7001,
 host: '172.18.38.219'
}, {
 port: 7002,
 host: '172.18.38.219'
}]
var cluster = new Redis.Cluster(redis_members);

cluster.set('foo', 'bar');
cluster.get('foo', function (err, res) {
 console.log('=====',res) //===== bar
});

你以为结束了?其实还没有!

集群搭建过程的各种奇葩错误这里汇总,当然下面错误不是一定会遇到,但不保证一定不会不遇到。生产环境我搭的挺顺利,但是测试环境几乎所有能遇到的问题全都遇到了,最后都解决了,特此记录!

原文发布时间为:2018-07-16
本文作者:单曲循环
本文来自云栖社区合作伙伴“Java知音”,了解相关信息可以关注“Java知音

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
[个人翻译]Redis 集群教程(下)
[个人翻译]Redis 集群教程(上) [个人翻译]Redis 集群教程(中) 官方原文地址:https://redis.io/topics/cluster-tutorial 水平有限,如果您在阅读过程中发现有翻译的不合理的地方,请留言,我会尽快修改,谢谢。
749 0
[个人翻译]Redis 集群教程(中)
[个人翻译]Redis 集群教程(上) [个人翻译]Redis 集群教程(下) 官方原文地址:https://redis.io/topics/cluster-tutorial 水平有限,如果您在阅读过程中发现有翻译的不合理的地方,请留言,我会尽快修改,谢谢。
989 0
Redis持久化之RDB(Redis DataBase)
RDB在指定的时间间隔内将内存中的数据集快照写入磁盘, 也就是行话讲的Snapshot快照,它恢复时是将快照文件直接读到内存里
24 0
13. Redis持久化之AOF
以日志的形式来记录每个写操作(增量保存),将Redis执行过的所有写指令记录下来(读操作不记录), 只许追加文件但不可以改写文件,redis启动之初会读取该文件重新构建数据,换言之,redis 重启的话就根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作
20 0
Redis---持久化 ( RDB AOF )
一、Redis提供了哪些持久化机制: 1). RDB持久化: 该机制是指在指定的时间间隔内将内存中的数据集快照写入磁盘。 2). AOF持久化: 机制将以日志的形式记录服务器所处理的每一个写操作,在Redis服务器启动之初会读取该文件来重新构建数据库,以保证启动后数据库中的数据是完整的。比如,一直在执行自加一的命令,然后我们可以直接用一个set来代替N个自加啊,自
2694 0
Redis的持久化机制
1 持久化 redis需要经常将内存中的数据同步到磁盘来保证持久化。 支持两种持久化方式:快照、Append-onlyfile。 2 快照 快照是默认的持久化方式。这种方式是将内存中数据以快照的方式写入到二进制文件中,默认的文件名为dump.rdb。可配置redis在n秒内若超过m个key被修改就自动做快照,默认快照保存配置如下: #900秒内若超过1个key被修改
1680 0
Redis协议简介及持久化Aof文件解析
本文主要对Redis的协议进行简单介绍并提供了一种方法用于解析AOF文件
8948 0
使用Redis搭建持久化K-V存储
最近在项目中需要在多机之间共享一些集合,Hash等有类型的数据结构,如果基于Mysql来存储的话需要预先定义一系列表结构并维护表结构和数据结构的一致性,后续还需要根据时间对数据库做旧数据清理工作,所以开始调研一些能满足下列需求的存储引擎。 具有高可用,持久化的特性。 数据可以设置失效时间,方便自动数据清理。 支持常用数据结构,如集合,有序集合,Hash map,列表等。 支持事务操作,
4549 0
Redis持久化方案
  前言:Redis的高性能是由于其将所有数据都存储在了内存中,为了使Redis在重启之后仍能保证数据不丢失,需要将数据从内存中同步到硬盘中,这一过程就是持久化。       Redis支持两种方式的持久化,一种是RDB方式,一种是AOF方式。可以单独使用其中一种或将二者结合使用。 RDB持
3925 0
+关注
技术小能手
云栖运营小编~
7194
文章
9
问答
文章排行榜
最热
最新
相关电子书
更多
低代码开发师(初级)实战教程
立即下载
阿里巴巴DevOps 最佳实践手册
立即下载
冬季实战营第三期:MySQL数据库进阶实战
立即下载