Redis集群搭建(传统方式&Docker方式)&集群扩容&集群缩容

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
简介: Redis集群搭建(传统方式&Docker方式)&集群扩容&集群缩容

正文


一、Redis集群原理


Redis 集群没有使用一致性hash, 而是引入了 哈希槽的概念。Redis 集群有16384个哈希槽,每个key通过CRC16校验后对16384取模来决定放置哪个槽。集群的每个节点负责一部分hash槽,举个例子,比如当前集群有3个节点,那么:


节点 A 包含 0 到 5500号哈希槽。


节点 B 包含5501 到 11000 号哈希槽。


节点 C 包含11001 到 16384号哈希槽。


注意:一个键值并不是对应一个哈希槽,一个哈希槽可以有很多键值。理论上一个集群可以存放很多很多键值。


CRC16算法


static const uint16_t crc16tab[256]= {
    0x0000,0x1021,0x2042,0x3063,0x4084,0x50a5,0x60c6,0x70e7,
    0x8108,0x9129,0xa14a,0xb16b,0xc18c,0xd1ad,0xe1ce,0xf1ef,
    0x1231,0x0210,0x3273,0x2252,0x52b5,0x4294,0x72f7,0x62d6,
    0x9339,0x8318,0xb37b,0xa35a,0xd3bd,0xc39c,0xf3ff,0xe3de,
    0x2462,0x3443,0x0420,0x1401,0x64e6,0x74c7,0x44a4,0x5485,
    0xa56a,0xb54b,0x8528,0x9509,0xe5ee,0xf5cf,0xc5ac,0xd58d,
    0x3653,0x2672,0x1611,0x0630,0x76d7,0x66f6,0x5695,0x46b4,
    0xb75b,0xa77a,0x9719,0x8738,0xf7df,0xe7fe,0xd79d,0xc7bc,
    0x48c4,0x58e5,0x6886,0x78a7,0x0840,0x1861,0x2802,0x3823,
    0xc9cc,0xd9ed,0xe98e,0xf9af,0x8948,0x9969,0xa90a,0xb92b,
    0x5af5,0x4ad4,0x7ab7,0x6a96,0x1a71,0x0a50,0x3a33,0x2a12,
    0xdbfd,0xcbdc,0xfbbf,0xeb9e,0x9b79,0x8b58,0xbb3b,0xab1a,
    0x6ca6,0x7c87,0x4ce4,0x5cc5,0x2c22,0x3c03,0x0c60,0x1c41,
    0xedae,0xfd8f,0xcdec,0xddcd,0xad2a,0xbd0b,0x8d68,0x9d49,
    0x7e97,0x6eb6,0x5ed5,0x4ef4,0x3e13,0x2e32,0x1e51,0x0e70,
    0xff9f,0xefbe,0xdfdd,0xcffc,0xbf1b,0xaf3a,0x9f59,0x8f78,
    0x9188,0x81a9,0xb1ca,0xa1eb,0xd10c,0xc12d,0xf14e,0xe16f,
    0x1080,0x00a1,0x30c2,0x20e3,0x5004,0x4025,0x7046,0x6067,
    0x83b9,0x9398,0xa3fb,0xb3da,0xc33d,0xd31c,0xe37f,0xf35e,
    0x02b1,0x1290,0x22f3,0x32d2,0x4235,0x5214,0x6277,0x7256,
    0xb5ea,0xa5cb,0x95a8,0x8589,0xf56e,0xe54f,0xd52c,0xc50d,
    0x34e2,0x24c3,0x14a0,0x0481,0x7466,0x6447,0x5424,0x4405,
    0xa7db,0xb7fa,0x8799,0x97b8,0xe75f,0xf77e,0xc71d,0xd73c,
    0x26d3,0x36f2,0x0691,0x16b0,0x6657,0x7676,0x4615,0x5634,
    0xd94c,0xc96d,0xf90e,0xe92f,0x99c8,0x89e9,0xb98a,0xa9ab,
    0x5844,0x4865,0x7806,0x6827,0x18c0,0x08e1,0x3882,0x28a3,
    0xcb7d,0xdb5c,0xeb3f,0xfb1e,0x8bf9,0x9bd8,0xabbb,0xbb9a,
    0x4a75,0x5a54,0x6a37,0x7a16,0x0af1,0x1ad0,0x2ab3,0x3a92,
    0xfd2e,0xed0f,0xdd6c,0xcd4d,0xbdaa,0xad8b,0x9de8,0x8dc9,
    0x7c26,0x6c07,0x5c64,0x4c45,0x3ca2,0x2c83,0x1ce0,0x0cc1,
    0xef1f,0xff3e,0xcf5d,0xdf7c,0xaf9b,0xbfba,0x8fd9,0x9ff8,
    0x6e17,0x7e36,0x4e55,0x5e74,0x2e93,0x3eb2,0x0ed1,0x1ef0
};
uint16_t crc16(const char *buf, int len) {
    int counter;
    uint16_t crc = 0;
    for (counter = 0; counter < len; counter++)
            crc = (crc<<8) ^ crc16tab[((crc>>8) ^ *buf++)&0x00FF];
    return crc;
}


集群间通信方式


所有的集群节点都通过TCP连接和一个二进制协议(集群连接,cluster bus)建立通信。 每一个节点都通过集群连接(cluster bus)与集群上的其余每个节点连接起来。节点之间使用一个 gossip流言协议来传播集群的信息。


主节点宕机


节点的失效有两种状态PFAIL和FAIL,当集群中A节发送给B节点的一个活跃的 ping 包(active ping)(一个发送后要等待其回复的 ping 包)已经等待了超过 NODE_TIMEOUT 时间,那么A认为这个节点具有不可达性,标记为PFAIL,如果其他节点也把B节点标记为PFAIL状态(A节点通过gossip 字段收集到集群中大部分主节点标识的节点 B 的状态信息为PFAIL),那么A就会把B标记为FAIL,并告诉其他可达的节点,B节点FAIL了。


从节点选举为主节点


从节点的选举和提升都是由从节点处理的,主节点会投票要提升哪个从节点。一个从节点的选举是在主节点被至少一个具有成为主节点必备条件的从节点标记为 FAIL 的状态的时候发生的。


当以下条件满足时,一个从节点可以发起选举:


该从节点的主节点处于 FAIL 状态。

这个主节点负责的哈希槽数目不为零。

从节点和主节点之间的重复连接(replication link)断线不超过一段给定的时间,这是为了确保从节点的数据是可靠的。

一个从节点想要被推选出来,那么第一步应该是提高它的 currentEpoch(可以理解为事件版本号) 计数,并且向主节点们请求投票。

从节点通过广播一个 FAILOVER_AUTH_REQUEST 数据包给集群里的每个主节点来请求选票。然后等待回复(最多等 NODE_TIMEOUT 这么长时间)。一旦一个主节点给这个从节点投票,会回复一个 FAILOVER_AUTH_ACK,并且在 NODE_TIMEOUT * 2 这段时间内不能再给同个主节点的其他从节点投票。


一旦某个从节点收到了大多数主节点的回应,那么它就赢得了选举。否则,如果无法在 NODE_TIMEOUT 时间内访问到大多数主节点,那么当前选举会被中断并在 NODE_TIMEOUT * 4 这段时间后由另一个从节点尝试发起选举。


从节点并不是在主节点一进入 FAIL 状态就马上尝试发起选举,而是有一点点延迟。


主节点接收到来自于从节点、要求以 FAILOVER_AUTH_REQUEST 请求的形式投票的请求。 要授予一个投票,必须要满足以下条件:


在一个给定的时段(epoch)里,一个主节点只能投一次票,并且拒绝给以前时段投票:每个主节点都有一个 lastVoteEpoch 域,一旦认证请求数据包(auth request packet)里的 currentEpoch 小于 lastVoteEpoch,那么主节点就会拒绝再次投票。当一个主节点积极响应一个投票请求,那么 lastVoteEpoch 会相应地进行更新。

一个主节点投票给某个从节点当且仅当该从节点的主节点被标记为 FAIL。

如果认证请求里的 currentEpoch 小于主节点里的 currentEpoch 的话,那么该请求会被忽视掉。因此,主节点的回应总是带着和认证请求一致的 currentEpoch。如果同一个从节点在增加 currentEpoch 后再次请求投票,那么保证一个来自于主节点的、旧的延迟回复不会被新一轮选举接受。


二、RedisCluster安装


传统方式


1、创建文件


[root@localhost local]# mkdir redis-cluster
[root@localhost redis-cluster]# mkdir 7000
[root@localhost redis-cluster]# mkdir 7001
[root@localhost redis-cluster]# mkdir 7002
[root@localhost redis-cluster]# mkdir 7003
[root@localhost redis-cluster]# mkdir 7004
[root@localhost redis-cluster]# mkdir 7005
#降配置文件复制到相应的目录下
[root@localhost redis-cluster]# cp /usr/local/redis-6.2.4/redis.conf /usr/local/redis-cluster/7000/ -r
[root@localhost redis-cluster]# cp /usr/local/redis-6.2.4/redis.conf /usr/local/redis-cluster/7001/ -r
[root@localhost redis-cluster]# cp /usr/local/redis-6.2.4/redis.conf /usr/local/redis-cluster/7002/ -r
[root@localhost redis-cluster]# cp /usr/local/redis-6.2.4/redis.conf /usr/local/redis-cluster/7003/ -r
[root@localhost redis-cluster]# cp /usr/local/redis-6.2.4/redis.conf /usr/local/redis-cluster/7004/ -r
[root@localhost redis-cluster]# cp /usr/local/redis-6.2.4/redis.conf /usr/local/redis-cluster/7005/ -r


2、修改配置文件


#注释掉
bind 127.0.0.1 -::1
#后台启动
daemonize yes 
# 允许外部访问
protected-mode no 
#修改端口号,从7000到7005
port 7000
#指定启动的pid文件 7000-7005
pidfile /var/run/redis_7000.pid
#日志路径 引号不要丢 7000-7005
logfile  "usr/local/redis-cluster/7000/redis.log"
#修改rdb文件,为后面的扩容使用,因为是同一台虚拟机,不在同一个虚拟机可以不用改 7000-7005
dbfilename dump_7000.rdb
#修改密码
requirepass xiaojie
#集群的密码,不然节点切换的时候需要输入密码
masterauth xiaojie
#开启集群
cluster-enabled yes 
#自动生成文件 7000-7005
cluster-config-file nodes-7000.conf


3、启动集群


启动脚本 授权 chmod +x startall.sh


/usr/local/redis/bin/redis-server /usr/local/redis-cluster/7000/redis.conf
/usr/local/redis/bin/redis-server /usr/local/redis-cluster/7001/redis.conf
/usr/local/redis/bin/redis-server /usr/local/redis-cluster/7002/redis.conf
/usr/local/redis/bin/redis-server /usr/local/redis-cluster/7003/redis.conf
/usr/local/redis/bin/redis-server /usr/local/redis-cluster/7004/redis.conf
/usr/local/redis/bin/redis-server /usr/local/redis-cluster/7005/redis.conf


4、创建集群


#无密码 cluster-replicas 1 主从节点1:1分配
./redis-cli --cluster create  192.168.139.154:7000  192.168.139.154:7001  192.168.139.154:7002  192.168.139.154:7003  192.168.139.154:7004  192.168.139.154:7005  --cluster-replicas 1
#有密码
./redis-cli --cluster create  192.168.139.154:7000  192.168.139.154:7001  192.168.139.154:7002  192.168.139.154:7003  192.168.139.154:7004  192.168.139.154:7005  --cluster-replicas 1 -a xiaojie


111.png


输入yes接收卡槽分配。


222.png


看到这个图说明 集群安装成功了。


cluster nodes 指令查看集群节点


测试


[root@localhost bin]# ./redis-cli -p 7000 -c -a 'xiaojie'


111.png


OK搭建完成。


Docker方式


1、拉取镜像


[root@localhost bin]# docker pull redis


2、创建文件


[root@localhost local]# mkdir docker-redis-cluster 


3、创建redis-cluster.tmpl文件


#端口
port ${PORT}
#集群密码
masterauth xiaojie
#redis密码
requirepass xiaojie
#开启集群
cluster-enabled yes
#配置文件
cluster-config-file nodes.conf
cluster-node-timeout 5000
#集群通讯的ip如果在外网访问,需要填写服务器的公网ip
cluster-announce-ip 192.168.6.137
##集群节点的汇报port,防止nat
cluster-announce-port ${PORT}
#集群节点的汇报bus-port,防止nat
cluster-announce-bus-port 1${PORT}
#开启aof
appendonly yes


4、创建data和conf文件


[root@localhost docker-redis-cluster]# for port in `seq 9000 9005`; do mkdir -p ./${port}/conf && PORT=${port} envsubst < ./redis-cluster.tmpl > ./${port}/conf/redis.conf && mkdir -p ./${port}/data; done


5、创建Redis容器


[root@localhost docker-redis-cluster]# for port in `seq 9000 9005`; do docker run -d --net=host -v /usr/local/docker-redis-cluster/${port}/conf/redis.conf:/etc/redis/redis.conf -v /usr/local/docker-redis-cluster/${port}/data:/data --restart always --name=redis-${port}  redis redis-server /etc/redis/redis.conf; done


6、进入任一容器创建集群


#进入容器
[root@localhost docker-redis-cluster]# docker exec -it 9e36f2ab4ae7 bash
#创建集群
root@localhost:/data# redis-cli --cluster create  192.168.6.137:9000  192.168.6.137:9001  192.168.6.137:9002  192.168.6.137:9003  192.168.6.137:9004  192.168.6.137:9005  --cluster-replicas 1 -a xiaojie


7、测试


root@localhost:/data# redis-cli -p 9000 -c -a 'xiaojie'  
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
192.168.6.137:9002> set docker docker 
-> Redirected to slot [9730] located at 192.168.6.137:9001
OK
192.168.6.137:9001> get docker
"docker"
192.168.6.137:9001> 


三、集群扩容


集群扩容就是在原来的基础上新增集群节点,而不需要重新启动服务器。简单明白的说,就是新增一个服务器,然后从其他节点上分给它一些卡槽和数据(如果卡槽上有数据则连带数据一起分给新增的节点)。


添加两个配置文件,在下面源码地址上有


新增主节点


#启动新增的连个节点
[root@localhost bin]# ./redis-server /usr/local/redis-cluster/7006/redis.conf 
[root@localhost bin]# ./redis-server /usr/local/redis-cluster/7007/redis.conf
#新增主节点
[root@localhost bin]# /usr/local/redis/bin/redis-cli --cluster add-node 192.168.139.154:7006   192.168.139.154:7000 -a xiaojie  #没有密码则不用-a xiaojie


444.png


可以看到新增的节点是没有卡槽的。


下面我们为新增的主节点分配从节点


[root@localhost bin]# ./redis-cli --cluster add-node   192.168.139.154:7007  192.168.139.154:7000  --cluster-slave   --cluster-master-id  9493cb0e7ee7b35da0c9078e9a99e5b577de9f1a -a xiaojie 
#master-id 为7006节点对应的id可以看到我们为7006新增从节点


333.png


输入cluster nodes 检查集群状态,如上图,还没有分配卡槽


下面分配卡槽


#这个客户端可以连接任何一个节点,不限于7000
[root@localhost bin]# ./redis-cli --cluster reshard  192.168.139.154:7000 -a xiaojie


333.png


你想移动多少卡槽? 16384/4=4096 所以我们想要移动4096个卡槽到7006节点上,然后就会从其他的三个主节(从节点上是没有卡槽的)点上分给7006。所以输入4096


222.png


输入对应的id,这里我们选择all 再接着选择yes等待分配完卡槽就好啦。


111.png


右上图可见,已经给我们分配完卡槽了。


四、集群缩容


集群缩容,正好和扩容相反,就是在不重启服务器的情况 下移除服务节点。


111.png


我们选择将7006卡槽全部给7001,注意:移除节点时,一定要确保,所有的卡槽已经移除到别的主节点上。


[root@localhost bin]# ./redis-cli --cluster  reshard  192.168.139.154:7000  --cluster-from   9493cb0e7ee7b35da0c9078e9a99e5b577de9f1a -a xiaojie  --cluster-to d5ac3163a51a0b7e70e777d8ff137a4ba901d611  --cluster-slots -a xiaojie

五、SpringBoot整合Redis Cluster


spring:
  jackson:
    time-zone: GMT+8
    date-format: yyyy-MM-dd HH:mm:ss
  datasource:
    name: my-test
    url: jdbc:mysql://127.0.0.1:3306/my_test?useUnicode=true&characterEncoding=UTF-8&rewriteBatchedStatements=true&allowMultiQueries=true&serverTimezone=Asia/Shanghai
    username: root
    password: root
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
  redis:
    cluster:
      nodes: #我连接的是Docker安装的集群
      - 192.168.6.137:9000
      - 192.168.6.137:9001
      - 192.168.6.137:9002
      - 192.168.6.137:9003
      - 192.168.6.137:9004
      - 192.168.6.137:9005
    password: xiaojie
    connect-timeout: 5000
#    password: xiaojie #这个密码一定要加,然后才能保证能连接到redis服务器,如果没有配置密码则不需要
#    connect-timeout: 5000
#    database: 0
#    sentinel:
#      master: mymaster
#      nodes: 192.168.6.137:26379,192.168.6.137:26380,192.168.6.137:26381
#      password: xiaojie #这个密码是哨兵的密码,如果在sentinel.conf中没有配置requirepass则不需要


完整代码和集群配置文件:spring-boot: Springboot整合redis、消息中间件等相关代码 


参考:


REDIS cluster-spec -- Redis中文资料站 -- Redis中国用户组(CRUG)


docker部署redis集群 - 桥头堡洗脚城 - 博客园

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
3月前
|
网络安全 Docker 容器
|
3月前
|
安全 Docker 容器
|
22天前
|
NoSQL 关系型数据库 Redis
《docker高级篇(大厂进阶):1.Docker复杂安装详说》包括:安装mysql主从复制、安装redis集群
《docker高级篇(大厂进阶):1.Docker复杂安装详说》包括:安装mysql主从复制、安装redis集群
88 14
|
19天前
|
关系型数据库 MySQL 应用服务中间件
《docker基础篇:8.Docker常规安装简介》包括:docker常规安装总体步骤、安装tomcat、安装mysql、安装redis
《docker基础篇:8.Docker常规安装简介》包括:docker常规安装总体步骤、安装tomcat、安装mysql、安装redis
72 7
|
1月前
|
NoSQL 算法 Redis
docker高级篇(大厂进阶):安装redis集群
docker高级篇(大厂进阶):安装redis集群
117 24
|
1月前
|
Prometheus 监控 Cloud Native
如何使用Prometheus监控Docker Swarm集群的资源使用情况?
还可以根据实际需求进行进一步的配置和优化,如设置告警规则,当资源使用超出阈值时及时发出警报。通过这些步骤,能够有效地使用 Prometheus 对 Docker Swarm 集群的资源进行监控和管理。
74 8
|
1月前
|
Prometheus 监控 Cloud Native
如何监控Docker Swarm集群的性能?
如何监控Docker Swarm集群的性能?
131 8
|
1月前
|
监控 Docker 容器
Docker Swarm集群的扩展与缩容策略,涵盖其意义、方法、步骤及注意事项
本文深入探讨了Docker Swarm集群的扩展与缩容策略,涵盖其意义、方法、步骤及注意事项,旨在帮助用户高效管理集群资源,适应业务变化,确保服务稳定性和资源优化。
63 6
|
2月前
|
API Docker 容器
【赵渝强老师】构建Docker Swarm集群
本文介绍了如何使用三台虚拟主机构建Docker Swarm集群。首先在master节点上初始化集群,然后通过特定命令将node1和node2作为worker节点加入集群。最后,在master节点上查看集群的节点信息,确认集群构建成功。文中还提供了相关图片和视频教程,帮助读者更好地理解和操作。
|
2月前
|
调度 Docker 容器
【赵渝强老师】Docker Swarm集群的体系架构
Docker Swarm自1.12.0版本起集成至Docker引擎,无需单独安装。它内置服务发现功能,支持跨多服务器或宿主机创建容器,形成集群提供服务。相比之下,Docker Compose仅限于单个宿主机。Docker Swarm采用主从架构,Swarm Manager负责管理和调度集群中的容器资源,用户通过其接口发送指令,Swarm Node根据指令创建容器运行应用。