redis cluster 集群搭建

redis cluster 搭建

一、redis常用的三种集群模式

  1. 主从
    • 通过持久化功能,redis保证了即使在服务器重启的情况下也不会丢失(或少量丢失)数据,因为持久化会把内存中的数据保存在硬盘上。重启会从硬盘上加载数据。但是由于数据是存在一台服务器上,如果这台服务器出现硬盘故障等问题,也会导致数据丢失
    • 为了避免单点故障,通常的做法是将数据复制多个副本,以部署在不同的服务器上,这样即使有一台服务器出现故障,其他服务器依然可以提供服务。为此,reids提供了复制(replication)功能,可以实现一台数据库中的数据更新后,自动将更新的数据同步到其他服务器上
    • 在复制的概念中,数据库分为两类,一类是主数据库(master),另一类是从数据库(slaver)
      • 主数据库可以进行读写操作,当写操作导致数据变化时会自动将数据同步给从数据库。
      • 从数据库一般只是只读的,并接受数据库同步过的数据
      • 一个主数据库可以拥有多个从数据库,而一个从数据库只能拥有一个主数据库
  2. 哨兵
    • 第一种主从同步/复制的模式,当主服务器宕机后,需要手动把一台服务器切换为主服务器。这就需要人工干预,费时费力。还会造成一段时间内服务不可用。这不是一种推荐的方式,更多时候,我们优先考虑哨兵模式。
    • 哨兵模式是一种特殊的模式,首先redis提供了哨兵的命令,哨兵是一个独立的进程,作为进程,他会独立运行
    • 其原理是哨兵通过发送命令,等待redis服务器响应,从而监控运行的多个redis实例。
  3. cluster
    • redis的哨兵模式基本可以实现高可用,读写分离,但是在这种模式下,每台redis服务器都存储相同的数据,浪费内存。并且水平扩容很费劲。
    • 所以在redis 3.0上加入了cluster集群模式,实现了redis的分布式存储,也就是说每台redis节点上存储不同的内容。
    • 官方推荐cluster集群模式,水平扩容也方便。

二、redis cluster简介

  • redis 3.0版本之前,只支持单例模式,在3.0版本之后才支持集群
  • redis集群采用P2P模式,是完全去中心化的,不存在中心节点或者代理节点
  • redis集群是没有统一的入口的,客户端连接集群中的任意节点即可,集群内部的节点是相互通信的(Gossip通信协议, PING-PONG机制),每个节点都是一个redis实例
  • 为了实现集群的高可用,即判断节点是否健康,redis cluster有这么一个投票容错机制:如果集群中找过半数的节点投票认为某节点挂了,那么该节点就挂了(fail)。
  • 如何判断机器是否挂了呢: 如果集群中任意一个主节点挂了,而该节点又没有从节点(备份节点),那么这个集群就挂了。
  • 为什么任意一个主节点挂了(又没有对应的从节点)这个集群就挂了呢:是因为集群内置了16384(0~16383)个slot(哈希槽),并且把所有的物理节点映射到了这16384个slot上,或者说把这些slot均等的分配给了各个节点。
    • 当需要redis集群存放一个数据(key-value)时,redis会先对这个key进行crc16算法,然后得到一个结果
    • 再把这个结果对16384进行取余,这个余数会对应到(0~16383)其中一个槽,进而决定key-value存储在哪个节点中
    • 所以一旦某个主节点(又没有从节点)挂了,该节点的slot就无法使用了,那么就会导致集群无法正常工作
  • redis集群至少需要3个主节点:因为投票容错机制要求超过半数节点认为某节点挂了该节点才是挂了,所以2个节点服务构建集群。
  • redis集群至少需要6台服务器
    • 因为要保证集群的高可用,需要每个主节点都有至少一个从节点(备份节点)
    • 如果手上没那么多服务,也可以采用伪分布式集群搭法,即一台物理机启动多个redis实例

三、redis cluster搭建

目前手头上只有3台物理机, 所以采取每台服务器开启2台实例构建基础主从。

服务器:ubuntu 20.04

redis:6.2.6

地址规划与结构图:

redis物理节点部署.png

简单说明:

  • 每台物理机器有一个主节点(端口6379)
  • 每个主节点的从节点在其他物理机上(端口为6380),避免一台物理机挂掉之后,整个redis集群都不好使了

开始搭建

分别修改3台物理机的/etc/hosts文件,添加如下内容

192.168.100.101 node1
192.168.100.102 node2
192.168.100.103 node3

在node1(192.168.100.101)上进行操作:

# 我们准备把redis放在/opt/redis-cluster目录下

# 创建目录
mkdir /opt/redis-cluster
# 切换目录
cd /opt/redis-cluster

# 下载redis源码
wget https://download.redis.io/releases/redis-6.2.6.tar.gz

# 解压
tar -xavf redis-6.2.6.tar.gz

cd redis-6.2.6

# 如果需要,安装编辑工具make, gcc
apt install make
apt install gcc

# 编译,注意:如果不加MALLOC=libc,会报fatal error: jemalloc/jemalloc.h: 没有那个文件或目录
make MALLOC=libc

# 安装, 安装后redis命令会放在/usr/local/bin目录下
make install

# 为redis 创建配置目录
mkdir -p /opt/redis-cluster/redis_63{79,80}/{conf,pid,logs}

修改redis_6379配置:vim /opt/redis-cluster/redis_6379/conf/redis.cnf

# 守护进行模式启动
daemonize yes

# 设置数据库数量,默认数据库为0
databases 16

# 绑定地址,需要修改
bind 192.168.100.101

# 绑定端口,需要修改
port 6379

# pid文件存储位置,文件名需要修改
pidfile /opt/redis-cluster/redis_6379/pid/redis_6379.pid

# log文件存储位置,文件名需要修改
logfile /opt/redis-cluster/redis_6379/logs/redis_6379.log

# RDB快照备份文件名,文件名需要修改
dbfilename redis_6379.rdb

# 本地数据库存储目录,需要修改
dir /opt/redis-cluster/redis_6379

# 集群相关配置
# 是否以集群模式启动
cluster-enabled yes

# 集群节点回应最长时间,超过该时间被认为下线
cluster-node-timeout 15000

# 生成的集群节点配置文件名,文件名需要修改
cluster-config-file nodes_6379.conf

修改redis_6380配置:vim /opt/redis-cluster/redis_6380/conf/redis.cnf, 将上边配置文件中的79替换为80即可。

在node2和node3做同样的操作,或者直接吧node1上的redis-cluster目录拷贝到另外两台上

启动集群

每个节点上执行以下2条命令进行服务启动:

$ redis-server /opt/redis-cluster/redis_6379/conf/redis.cnf
$ redis-server /opt/redis-cluster/redis_6380/conf/redis.cnf

集群模式启动,进程后会加上[cluster]的字样:

root@node1:~$ ps -ef | grep redis
root      9422     1  0 16:33 ?        00:00:07 redis-server 192.168.100.101:6380 [cluster]
root     15148     1  0 17:45 ?        00:00:06 redis-server 192.168.100.101:6379 [cluster]
root     16125  9116  0 21:32 pts/1    00:00:00 grep --color=auto redis

加入集群

现在虽然说每个服务都成功启动了,但是彼此之间并没有任何联系。

所以下一步要做的就是将6个服务加入至一个集群中,如下操作示例(在任意节点执行都行):

$ redis-cli -h node1 -p 6379

node1:6379> cluster meet 192.168.0.102 6379
node1:6379> cluster meet 192.168.0.103 6379
node1:6379> cluster meet 192.168.0.101 6380
node1:6379> cluster meet 192.168.0.102 6380
node1:6379> cluster meet 192.168.0.103 6380

CLUSTER MEET命令被用来连接不同的开启集群支持的 Redis 节点,以进入工作集群。

查看当前集群所有的节点:

node1:6379> cluster nodes

05a31e3aeaea4d6da847dfcd2fbae82c3d122133 192.168.100.102:6380@16380 master - 0 1646818185880 4 connected
2e2271a5c0144d037a7888fb0ca42362a9e7f429 192.168.100.102:6379@16379 master - 0 1646818184000 1 connected
fd78fc80e90d469cb1347db82cce5f707f095845 192.168.100.103:6379@16379 master - 0 1646818185000 0 connected
3de43ea30f65fad909f0e5647028af2f35c360c2 192.168.100.101:6380@16380 master - 0 1646818182841 3 connected
e0867a4bca1758c7bcc9caa8f8a1c4ce4675ea51 192.168.100.103:6380@16380 master - 0 1646818186882 5 connected
9d6d3de12ee1fdf1711e40d6504dd2c13e95dcc0 192.168.100.101:6379@16379 myself,master - 0 1646818185000 2 connected

主从配置

6个服务之间并没有任何主从关系,所以现在进行主从配置,记录下上面cluster nodes命令输出的node-id信息,只记录主节点

hostname 节点 node-id
node1 192.168.0.101:6379 9d6d3de12ee1fdf1711e40d6504dd2c13e95dcc0
node2 192.168.0.102:6379 2e2271a5c0144d037a7888fb0ca42362a9e7f429
node3 192.168.0.103:6379 fd78fc80e90d469cb1347db82cce5f707f095845

首先是node1的6380,将它映射到node2的6379:

root@node1:~$ redis-cli -h node1 -p 6380
node1:6380> CLUSTER REPLICATE 2e2271a5c0144d037a7888fb0ca42362a9e7f429
OK
node1:6380>exit

然后是node2的6380,将它映射到node3的6379:

root@node1:~$ redis-cli -h node2 -p 6380
node2:6380> CLUSTER REPLICATE fd78fc80e90d469cb1347db82cce5f707f095845
OK
node2:6380>exit

最后是node3的6380,将它映射到node1的6379:

root@node1:~$ redis-cli -h node3 -p 6380
node3:6380> CLUSTER REPLICATE 9d6d3de12ee1fdf1711e40d6504dd2c13e95dcc0
OK
node3:6380>exit

查看集群节点信息,

b-slaver2:6380> CLUSTER NODES
9d6d3de12ee1fdf1711e40d6504dd2c13e95dcc0 192.168.100.101:6379@16379 master - 0 1646818480000 2 connected
05a31e3aeaea4d6da847dfcd2fbae82c3d122133 192.168.100.102:6380@16380 slave fd78fc80e90d469cb1347db82cce5f707f095845 0 1646818479177 0 connected
3de43ea30f65fad909f0e5647028af2f35c360c2 192.168.100.101:6380@16380 slave 2e2271a5c0144d037a7888fb0ca42362a9e7f429 0 1646818478171 1 connected
e0867a4bca1758c7bcc9caa8f8a1c4ce4675ea51 192.168.100.103:6380@16380 myself,slave 9d6d3de12ee1fdf1711e40d6504dd2c13e95dcc0 0 1646818475000 2 connected
fd78fc80e90d469cb1347db82cce5f707f095845 192.168.100.103:6379@16379 master - 0 1646818478000 0 connected
2e2271a5c0144d037a7888fb0ca42362a9e7f429 192.168.100.102:6379@16379 master - 0 1646818480182 1 connected

分配槽位

接下来我们要开始分配槽位了,为了考虑今后的写入操作能分配均匀,槽位也要进行均匀分配。

仅在Master上进行分配,从库不进行分配,仅做主库的备份和读库使用。

槽位分配情况如下,槽位号从0开始,到16383结束,共16384个槽位,均匀分配:

节点 槽位数量
node1:6379 0 - 5461
node2:6379 5462 - 10922
node3:6379 10923 - 16383

开始分配:

$ redis-cli -h node1 -p 6379 cluster addslots {0..5461}
$ redis-cli -h node2 -p 6379 cluster addslots {5462..10922}
$ redis-cli -h node3 -p 6379 cluster addslots {10923..16383}

检查槽位是否分配正确

node1:6379> CLUSTER NODES
05a31e3aeaea4d6da847dfcd2fbae82c3d122133 192.168.100.245:6380@16380 slave fd78fc80e90d469cb1347db82cce5f707f095845 0 1646818753000 0 connected
2e2271a5c0144d037a7888fb0ca42362a9e7f429 192.168.100.245:6379@16379 master - 0 1646818751296 1 connected 5462-10922
fd78fc80e90d469cb1347db82cce5f707f095845 192.168.100.246:6379@16379 master - 0 1646818752299 0 connected 10923-16383
3de43ea30f65fad909f0e5647028af2f35c360c2 192.168.100.109:6380@16380 slave 2e2271a5c0144d037a7888fb0ca42362a9e7f429 0 1646818754302 1 connected
e0867a4bca1758c7bcc9caa8f8a1c4ce4675ea51 192.168.100.246:6380@16380 slave 9d6d3de12ee1fdf1711e40d6504dd2c13e95dcc0 0 1646818755306 2 connected
9d6d3de12ee1fdf1711e40d6504dd2c13e95dcc0 192.168.100.109:6379@16379 myself,master - 0 1646818751000 2 connected 0-5461

检查状态

使用以下命令检查集群状态是否ok,如果槽位全部分配完毕应该是ok,不然的话就检查你分配槽位时是否输错了数量:

$ redis-cli -h node1 -p 6379

node1:6379> CLUSTER info
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6
cluster_size:3
cluster_current_epoch:5
cluster_my_epoch:5
cluster_stats_messages_ping_sent:2825
cluster_stats_messages_pong_sent:2793
cluster_stats_messages_meet_sent:5
cluster_stats_messages_sent:5623
cluster_stats_messages_ping_received:2793
cluster_stats_messages_pong_received:2830
cluster_stats_messages_received:5623

读写测试

$ redis-cli -c -h node1 -p 6379

node1:6379> set k1 "v1"
-> Redirected to slot [12706] located at 192.168.0.140:6379
OK  

注意:-c参数无所谓你的Redis是否是集群模式, 如果不加-c会报(error) MOVED...

一并对主从进行验证,这条数据是写入至了node3的Master中,我们登录node2的Slaver中进行查看:

$ redis-cli -h node2 -p 6380 -c

node2:6380> keys *
1) "k1"

故障转移

模拟node1的6379下线宕机,此时应该由node3的6380接管它的工作

$ redis-cli -h node1 -p 6379 shutdown

登录集群任意节点查看目前的集群节点信息:

root@node1:~$ redis-cli -c -h node2 -p 6380
node2:6380> CLUSTER NODES
9d6d3de12ee1fdf1711e40d6504dd2c13e95dcc0 192.168.100.101:6379@16379 master,fail - 1646819034665 1646819031000 2 disconnected
3de43ea30f65fad909f0e5647028af2f35c360c2 192.168.100.101:6380@16380 slave 2e2271a5c0144d037a7888fb0ca42362a9e7f429 0 1646819090108 1 connected
fd78fc80e90d469cb1347db82cce5f707f095845 192.168.100.103:6379@16379 master - 0 1646819089100 0 connected 10923-16383
e0867a4bca1758c7bcc9caa8f8a1c4ce4675ea51 192.168.100.103:6380@16380 master - 0 1646819089000 6 connected 0-5461
2e2271a5c0144d037a7888fb0ca42362a9e7f429 192.168.100.102:6379@16379 master - 0 1646819089000 1 connected 5462-10922
05a31e3aeaea4d6da847dfcd2fbae82c3d122133 192.168.100.102:6380@16380 myself,slave fd78fc80e90d469cb1347db82cce5f707f095845 0 1646819088000 0 connected

恢复工作

重启node1的6379:

$ redis-server /opt/redis-cluster/redis_6379/conf/redis.cnf

登录node1的6379,发现他已经自动的进行上线了,并且作为node3中6380的从库:

root@b-master:~# redis-cli -c -h node2 -p 6380
node2:6380> CLUSTER NODES
9d6d3de12ee1fdf1711e40d6504dd2c13e95dcc0 192.168.100.101:6379@16379 slave e0867a4bca1758c7bcc9caa8f8a1c4ce4675ea51 0 1646819155000 6 connected
3de43ea30f65fad909f0e5647028af2f35c360c2 192.168.100.101:6380@16380 slave 2e2271a5c0144d037a7888fb0ca42362a9e7f429 0 1646819155573 1 connected
fd78fc80e90d469cb1347db82cce5f707f095845 192.168.100.103:6379@16379 master - 0 1646819155000 0 connected 10923-16383
e0867a4bca1758c7bcc9caa8f8a1c4ce4675ea51 192.168.100.103:6380@16380 master - 0 1646819156578 6 connected 0-5461
2e2271a5c0144d037a7888fb0ca42362a9e7f429 192.168.100.102:6379@16379 master - 0 1646819155000 1 connected 5462-10922
05a31e3aeaea4d6da847dfcd2fbae82c3d122133 192.168.100.102:6380@16380 myself,slave fd78fc80e90d469cb1347db82cce5f707f095845 0 1646819153000 0 connected

四、常见问题

  1. 如果一组主从宕机,集群是否可用

    • 之前说一个节点挂掉,又没有从节点,那么集群不可用(默认为yes)
    • 如果修改下边的配置属性,则宕机的1组不可用,而其他组的机器可以用
      • 往1组保存数据,失败,导致数据丢失
      • 往2组或3组保存数据,正常运行
    # cluster-require-full-coverage yes
    
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,470评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,393评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,577评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,176评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,189评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,155评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,041评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,903评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,319评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,539评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,703评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,417评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,013评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,664评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,818评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,711评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,601评论 2 353

推荐阅读更多精彩内容