深入浅出Redis(八):Redis的集群模式

引言

Redis是一款优秀的键值对、内存非关系型数据库,单机节点下的Redis存在无法保证高可用、容量不足等问题

上篇文章介绍的哨兵主要能够保证主从架构下Redis的可用性,但是仍然存在容量不足、推举新的主节点时不能访问Redis的问题,集群可水平扩展的功能解决容量不足的问题并且能够保证高可用

本篇文章将围绕Redis集群深入浅出的介绍集群的原理、如何使用集群、使用集群需要注意的地方,理解集群是如何支持水平扩展的以及如何保证高可用

学习本篇文章内容之前,需要了解持久化以及主从复制的机制

集群原理

分片

Redis集群将数据空间分为16384个哈希槽slots,分布到各个主节点中,集群中的每个主节点负责一部分的哈希槽

需要注意的是使用集群后每个主节点只有一个数据库(单机节点情况下是可以设置多个数据库的)

image.png

当客户端对key进行读写时,通过CRC16校验后对16384取模来决定出Key所在槽【哈希槽 =CRC16(key) % 16384】,然后在去管理这个槽的主节点中读/写Key(各个redis节点之间通信保存这些槽编号信息)

主从--高可用

每个主节点管理部分的哈希槽,如果主节点发生宕机则这部分槽相关的数据就不可用了

为了提供可用性,需要有从节点来冗余数据保证可用性,因此可以把集群cluster理解成包含多个主从架构,每个主从架构负责管理一部分的哈希槽

主节点间互相发送消息维持心跳的同时交换信息,当节点发现某节点不响应时(可能下线),广播给其他主节点,其他主节点收到后与不响应的节点通信,当大多数主节点接收不到时(确认下线),广播信息给这个节点的所有从节点,从节点收到后根据raft算法推选新主节点

raft推举算法:

  1. 从节点收到后推举自己为新主节点广播给其他从节点
  2. 其他节点接到后,如果该节点还在自转则会投票给它,如果该节点已经推举别的节点了就不会响应
  3. 收到推举票后如果超过一定数量则成为新主节点,如果最高票相等则重复步骤1

还不熟悉的同学可以观看动画:raft算法动态展示

集群中默认情况下使用异步复制数据,即主节点处理客户端写命令时,并不等待从节点同步数据再响应,性能与强一致性不兼得

重定向

当使用命令行进入某主节点中请求写命令,该写命令可能所在的槽并不是当前主节点的,主节点会响应MOVED指令告诉该Key应该被哪个主节点处理

 127.0.0.1:6379> set name cl(error) MOVED 5798 127.0.0.1:6380

当使用redis-cli -c进入客户端时,发生这种情况则会自动将Key重定向到对应主节点进行处理

水平扩展/收缩会导致节点的槽交给其他节点管理,这就会引起所在槽的Key发生迁移(迁移到新的节点中)

水平扩容/缩容

当发生水平扩展增加主节点时,会将其他主节点负责管理的哈希槽分配给新加入的主节点,删除节点类似,总要满足管理16384个槽,且集群中最少要求三个主节点

迁移是同步阻塞的,如果要迁移大Key将会发生卡顿,因此要尽量的减少大Key

如果发生迁移时,Key已经到达了新的节点,但是还未迁移完,槽与对应节点管理关系还未发生改动,这种情况下返回MOVED指令就会发生循环重定向(A:已经迁移了你去找B,B:还未迁移,你去找A),这种情况下会返回给客户端ACKING指令

ACKING指令能在数据迁移时,防止发生循环重定向

使用集群

集群最少要求三个主节点,所以我们搭建三主三从的集群

主节点端口号:6379,6380,6381

从节点端口号:6382,6383,6384

都在本地一台机器上进行模拟

1. 编写配置文件
 #generaldaemonize yesloglevel verbose#logfile "6379.log"databases 16#bind 47.108.181.237port 6379​#密码requirepass cl192243051masterauth cl192243051​#rdbdir /usr/local/redis/redis-6.0.6/datadbfilename dump-6379.rdbrdbcompression yesrdbchecksum yessave 60 2​#aofappendonly yesappendfilename appendonly-6379.aofappendfsync everysec​#memorymaxmemory-policy noeviction​#cluster 集群配置文件主要是这里cluster-enabled yes #开启集群cluster-config-file nodes-6379.conf #该节点产生的文件cluster-node-timeout 10000 #如果该节点的master超时多少秒没反应就尝试推荐自己当master​#关闭protected-mode模式 允许外网访问protected-mode no

当编写好模板配置文件后,其他配置文件也是一致的只需要改变端口号

使用命令将redis-6379.conf文件中6379替换为6380生成新文件redis-6380.conf

 sed "s/6379/6380/g" redis-6379.conf > redis-6380.conf
2. 启动所有节点

redis-server redis-6379.conf

image.png

3.搭建集群命令
 #如果有密码使用参数-a#--cluster-replicas 1 表示每个主节点携带一个从节点#后面跟所有节点的 IP:端口号(先主节点后从节点)#本地访问版redis-cli --cluster create --cluster-replicas 1 127.0.0.1:6379 127.0.0.1:6380 127.0.0.1:6381 127.0.0.1:6382 127.0.0.1:6383 127.0.0.1:6384​#外网访问版redis-cli --cluster create --cluster-replicas 1 -a 密码 47.108.181.237:6379 47.108.181.237:6380 47.108.181.237:6381 47.108.181.237:6382 47.108.181.237:6383 47.108.181.237:6384

image-20211204165816656.png

4. 客户端测试

客户端使用redis-cli 操作不在当前节点管理槽的key会响应moved信息

当集群模式时,进入客户端使用redis-cli -c 这样它会重定向到对应的节点中

写操作

 127.0.0.1:6379> set name cl(error) MOVED 5798 127.0.0.1:6380​[root@Tcl ~]# redis-cli -c127.0.0.1:6379> set name cl-> Redirected to slot [5798] located at 127.0.0.1:6380OK127.0.0.1:6380> 

读操作

故意不去6380端口

 [root@Tcl ~]# redis-cli -c -p 6381127.0.0.1:6381> get name-> Redirected to slot [5798] located at 127.0.0.1:6380"cl"127.0.0.1:6380> 

查看节点信息

在客户端使用命令cluster nodes可以查看节点信息

 127.0.0.1:6380> cluster nodes3c0b7cbc00846b8cca43dd94c55a0005d4d3113b 127.0.0.1:6380@16380 myself,master - 0 1638608629000 2 connected 5461-10922207460275205f58d47dbf3528bc3c1dedd3ce59d 127.0.0.1:6379@16379 master - 0 1638608631377 1 connected 0-5460d0eeaf81fcdcbaeee2f99c6598e00b239d796bea 127.0.0.1:6384@16384 slave 3c0b7cbc00846b8cca43dd94c55a0005d4d3113b 0 1638608630375 2 connected86fcc49d8090bfcfea7a40241c6a78c4bcbc617a 127.0.0.1:6381@16381 master - 0 1638608629375 3 connected 10923-16383449bceec97e103eafdfebade77decd92081a798b 127.0.0.1:6383@16383 slave 207460275205f58d47dbf3528bc3c1dedd3ce59d 0 1638608628372 1 connected28f122d37e1bce60749326761a6ec7adc92e834b 127.0.0.1:6382@16382 slave 86fcc49d8090bfcfea7a40241c6a78c4bcbc617a 0 1638608631000 3 connected

image-20211204170553227.png

6379主节点的从节点是6383

6380主节点的从节点是6364

6381主节点的从节点是6382

5. 模拟主从切换

现在模拟6379主机宕机,超时10s后它的从节点6383检测到主节点没响应,会发生主从切换

 127.0.0.1:6380> cluster nodes3c0b7cbc00846b8cca43dd94c55a0005d4d3113b 127.0.0.1:6380@16380 myself,master - 0 1638609049000 2 connected 5461-10922207460275205f58d47dbf3528bc3c1dedd3ce59d 127.0.0.1:6379@16379 master,fail - 1638608946026 1638608941010 1 disconnectedd0eeaf81fcdcbaeee2f99c6598e00b239d796bea 127.0.0.1:6384@16384 slave 3c0b7cbc00846b8cca43dd94c55a0005d4d3113b 0 1638609052351 2 connected86fcc49d8090bfcfea7a40241c6a78c4bcbc617a 127.0.0.1:6381@16381 master - 0 1638609051000 3 connected 10923-16383449bceec97e103eafdfebade77decd92081a798b 127.0.0.1:6383@16383 master - 0 1638609051347 7 connected 0-546028f122d37e1bce60749326761a6ec7adc92e834b 127.0.0.1:6382@16382 slave 86fcc49d8090bfcfea7a40241c6a78c4bcbc617a 0 1638609049343 3 connected

image-20211204171229115.png

6379主机失败,而6383成为新的master

再启动6379主机,6379变成了6383的从机

同时也会更新其他节点中,这俩个节点关系变更的信息

image-20211204171326196.png

6. spring boot整合jedis cluster
 <dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId><version>3.7.0</version></dependency>
 @Configurationpublic class JedisClusterConfig {​@Value("${spring.redis.cluster.nodes}")private String clusterNodes;@Value("${spring.redis.timeout}")private int timeout;@Value("${spring.redis.jedis.pool.max-idle}")private int maxIdle;@Value("${spring.redis.jedis.pool.max-wait}")private long maxWaitMillis;@Value("${spring.redis.maxAttempts}")private int maxAttempts;@Value("${spring.redis.password}")private String password;​@Beanpublic JedisCluster getJedisCluster() {String[] cNodes = clusterNodes.split(",");Set<HostAndPort> nodes = new HashSet<HostAndPort>();// 分割出集群节点for (String node : cNodes) {String[] hp = node.split(":");nodes.add(new HostAndPort(hp[0], Integer.parseInt(hp[1])));}JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();jedisPoolConfig.setMaxIdle(maxIdle);jedisPoolConfig.setMaxWaitMillis(maxWaitMillis);// 创建集群对象JedisCluster jedisCluster = new JedisCluster(nodes, timeout, timeout, maxAttempts, password, jedisPoolConfig);return jedisCluster;}}

接下来可以使用jediscluster调用api操作redis集群

集群注意事项

  • 当有业务需要使用Set对象操作交集、并集时,要求key需要在相同的主节点中,使用{}规范命名前缀,计算槽时只有括号中的内容才会被哈希({}前缀相同,它们就会被分配到相同的槽中,由相同主节点处理)
  • mset、mget、事务等操作只有槽都被相同节点管理时才能使用,可以使用{}相同前缀解决
  • 集群下每个节点只有一个数据库

总结

本篇文章围绕Redis集群深入浅出的解析集群原理、使用集群以及注意事项

集群通过分片的策略,由多个节点管理集群中的16384个哈希槽,查询时先CRC16(key)% 16384计算key所在哈希槽,再去管理该哈希槽的主节点处理

为了保证集群的可用性,使用从节点冗余备份主节点数据,当发生确认下线时根据raft算法推举从节点发生主从切换,主从之间数据同步默认是异步的,性能和一致性不可兼得

由于Key不一定由当前服务端节点管理,服务端会使用MOVED指令重定向到管理key所在槽的节点

当发生水平扩容/缩容时,需要其他节点迁出/迁入部分管理的哈希槽,迁移是同步阻塞的,如果有大Key要迁移则会发生卡顿,使用ACKING指令防止迁移时发生循环重定向

最后(一键三连求求拉~)

本篇文章笔记以及案例被收入 gitee-StudyJava、 github-StudyJava 感兴趣的同学可以stat下持续关注喔~

有什么问题可以在评论区交流,如果觉得菜菜写的不错,可以点赞、关注、收藏支持一下~

关注菜菜,分享更多干货,公众号:菜菜的后端私房菜

本文由博客一文多发平台 OpenWrite 发布!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/522018.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

开发Chrome扩展插件

1.首先开发谷歌chrome扩展插件&#xff0c;没有严格的项目结构目录&#xff0c;但是需要保证里面有一个mainfest.json文件 (必不可少的文件)。在这个文件里有三个属性必不可少&#xff1a;name、version、mainfest_version&#xff1b; // 清单文件的版本&#xff0c;这个必须写…

jmap-各种option参数说明

基本情况 jmap&#xff08;JVM Memory Map&#xff09;&#xff1a;作用一方面是获取dump文件&#xff08;堆转储快照文件&#xff0c;二进制文件&#xff09;&#xff0c;它还可以获取目标Java进程的内存相关信息&#xff0c;包括Java堆各区域的使用情况、堆中对象的统计信息…

sheng的学习笔记-AI-多分类学习:ECOC,softmax

目录&#xff1a;sheng的学习笔记-AI目录-CSDN博客 基本术语&#xff1a; 若我们欲预测的是离散值&#xff0c;例如“好瓜”“坏瓜”&#xff0c;此类学习任务称为“分类”(classification)&#xff1b; 若欲预测的是连续值&#xff0c;例如西瓜成熟度0.95、0.37&#xff0c;…

蓝桥杯:矩形总面积(Java)

目录 问题描述输入格式输出格式代码实现 问题描述 平面上有个两个矩形R1和R2&#xff0c;它们各边都与坐标轴平行。设(x1, y1)和(x2 ,y2)依次是R1的左下角和右上角坐标&#xff0c;(x3, y3)和(x4, y4)依次是R2的左下角和右上角坐标&#xff0c;请你计算R1和R2的总面积是多少? …

Jmeter(GUI模式)详细教程

前些天&#xff0c;领导让我做接口的压力测试。What&#xff1f;&#xff1f;我从未接触过这方面&#xff0c;什么都不知道&#xff0c;一脸蒙。于是我从学习jmeter开始入手。 现在记录下来jmeter的使用步骤&#xff0c;希望能对大家有所帮助。 一、安装Jmeter 1、电脑安装J…

1910_野火FreeRTOS教程阅读笔记_prvStartFirstTask函数

1910_野火FreeRTOS教程阅读笔记_prvStartFirstTask函数 全部学习汇总&#xff1a; g_FreeRTOS: FreeRTOS学习笔记 这是教程中的一个函数&#xff0c;通过汇编来实现的。注释部分以及结合后面的讲解部分&#xff0c;可能还是有一点点细节的地方让初学者疑惑。我结合我自己的理解…

SAP金江、阎韶华、雷凡将出席“第四届ISIG-RPA、低代码、流程挖掘三大峰会

3月16日&#xff0c;第四届「ISIG中国产业智能大会」将在上海中庚聚龙酒店拉开序幕。本届大会由苏州市金融科技协会指导&#xff0c;企智未来科技&#xff08;RPA中国、AIGC开放社区、LowCode低码时代&#xff09;主办。大会旨在聚合每一位产业成员的力量&#xff0c;深入探索R…

vue router 解决路由带参数跳转时出现404问题

我的页面是从一个vue页面router跳转到另一个vue页面,并且利用windows.open() 浏览器重新创建一个页签。但是不知道为什么有时候可以有时候又不行,经过反复测试与分析,最终发现是因为有一个参数的值里包含了小数点., 小数点是浏览器合法字符,不能通过encode编码转义,于是乎…

【JavaEE初阶】 关于JVM垃圾回收

文章目录 &#x1f343;前言&#x1f38b;死亡对象的判断算法&#x1f6a9;引用计数算法&#x1f6a9;可达性分析算法 &#x1f333;垃圾回收算法&#x1f6a9;标记-清除算法&#x1f6a9;复制算法&#x1f6a9;标记-整理算法&#x1f6a9;分代算法&#x1f388;哪些对象会进入…

【Neo4j系列】Neo4j之CQL语句和函数介绍

本文将对Neo4j中的CQL语句和CQL函数进行详细介绍。 作者&#xff1a;后端小肥肠 目录 1. 前言 2. CQL语句 2.1. CQL简介 2.2. CREATE命令 2.3. MATCH命令 2.4. RETURN命令 2.5. MATCH和RETURN 2.6. CREATEMATCHRETURN命令 2.7. 关系基础 2.8. CREATE创建标签 2.9. WH…

C/C++的内存管理与初阶模板

引言 我们在学习C的时候&#xff0c;会经常在堆上申请空间&#xff0c;所以这个时候就体现了内存管理遍历。 图下是我们常见的计算机的内存划分&#xff1a; 我也在图下对部分变量存在的位置&#xff0c;及时标注。(如果有任何问题可以联系博主修改&#xff0c;感谢大家。) 那…

VSCode搭建ARM开发环境

为了构建Cortex M系列单片机免费开源的开发环境&#xff0c;网络上了解来看VSCODEGCCJLINK是一套比较高效的组合方式&#xff0c;下面记录环境搭建的流程。 我这边的PC环境为 WIN7专业版64bit。 需要用到的工具 Visual Studio CodeSTM32CubemxARM GCC 交叉编译工具链&#x…