redis高级篇三(分片集群)

news2024/10/5 16:27:55

一)进行测试Sentinel池:

集群的定义:所谓的集群,就是通过增加服务器的数量,提供相同的服务,从而让服务器达到一个稳定、高效的状态

之前的哨兵模式是存在着一些问题的,因为如果主节点挂了,那么sentinel集群会选举新的sentinel兵王来去进行故障修复操作,一旦此时受到了客户端的写的请求,就有可能会造成数据丢失的情况

​
@Controller
public class RestController {
    @RequestMapping("/Java100")
    @ResponseBody
    public String start(){
        //1.配置信息
        HashSet<String> set=new HashSet<>();
        // 连接信息 ip:port
        // set.add("127.0.0.1:27001");
        set.add("124.71.136.248:27001");
        //2.创建Sentinel连接池
        JedisSentinelPool pool = new JedisSentinelPool("mymaster", set, "12503487");
        //3.获取到Jedis客户端
        Jedis jedis=pool.getResource();
        //4.设置元素
        jedis.set("name","zhangsan");
        String value=jedis.get("name");
        return value;
    }
}
 public static void main(String[] args) {
        RedisURI redisURI = RedisURI.builder()
                .withHost("124.71.136.248")
                .withPort(6379)
                .withPassword("12503487")
                .build();
        RedisClient redisClient = RedisClient.create(redisURI);
//        // 创建 RedisClient
//        RedisClient redisClient = RedisClient.create("redis://124.71.136.248:7001");
        
        // 获取与 Redis 单节点的连接
        StatefulRedisConnection<String, String> connection = redisClient.connect();

        // 获取同步命令
        RedisCommands<String, String> syncCommands = connection.sync();
       
        // 执行 Redis 命令
        syncCommands.set("key", "value");
        String value = syncCommands.get("key");
        System.out.println("Value: " + value);

        // 关闭连接
        connection.close();
        redisClient.shutdown();
    }

二)Redis分片集群

主从集群可以应对高并发读的问题,我们的单节点的内存设置不要太高,如果内存占用的过高,那么在做RDB的持久化或者全量同步的时候就会导致大量的IO,性能下降

1)如果写的并发也很多怎么办呢?

2)如果需要进行存储的数据仍然是很多怎么办呢?

主从模式和哨兵模式可以解决高并发读,高可用的问题,但是仍然存在着海量数据存储的问题和高并发写的问题

3)分片集群的特征:

3.1)集群中有多个master,每一个master保存着不同的数据,这样进行存储的数据总量取决于master结点的数量;

3.2)每一个master本身都有多个slave节点

3.3)master相互之间可以做ping命令来进行检测检测彼此的健康状态

1)Redis集群支持多个Master,每一个Master又可以挂载个Slave,这样可以实现读写分离

支持数据的高可用,支持海量数据的读写存储操作;

2)由于Cluster自带的Sentinel的故障转移机制,内置了高可用的支持,这是无需再次使用哨兵模式;

3)客户端和Redis的节点相连,不再需要连接集群中的所有节点,只需要进行任意连接集群中的一个可用节点即可

4)槽位slot负责分配到各个物理服务节点,有对应的集群来负责维护节点,插槽和数据之间的关系

Redis会把每一个master节点映射到0-16383一共是16384个插槽上面,查看集群信息的时候就可以看到:

Redis中的key不是和master节点进行绑定的,而是和插槽进行绑定的,redis会根据key的有效部分来进行计算插槽的值,主要是分成两种情况:

1)key中包含{},况且大括号中至少包含一个字符,那么大括号中的部分就是有效部分

2)key中不包含大括号,整个key都是有效部分

假设如果key是num,那么key的有效部分就是num,但是假设key是{kkk}num,那么有效部分就是kkk,计算方法就是利用CRC16算法得到一个哈希值,针对这个16384取余,最后得到的结果一定是在0-16373之间,然后得到一个solt值;

3)因为redis的主节点是有可能出现宕机的情况的,或者是集群扩容增加了节点,或者是集群伸缩,删除了节点,如果一个节点宕机了,那么这个节点上面的数据也就丢失了,而数据如果是和插槽绑定的,那么当节点宕机的时候,我们可以把这个节点对应的插槽转移到正常的节点,集群扩容的时候,也可以将插槽进行转移,这样数据跟着插槽走,就永远可以找到数据的位置;

 一)Redis是如何进行判断Key在哪一个实例上面?

1)将16384个插槽分配到不同的实例节点上面

2)当存储一个key或者取出一个key的时候会,根据key的有效部分来计算哈希值,对16384进行取余操作;

3)将余数作为插槽,寻找到插槽所在的实例节点即可

二)如何将同一类数据固定的保存到同一个Redis实例中呢

假设我现在有不同的商品,空调洗衣机手机,各种类型不同的产品,就是将相同的商品放到同一个节点上面,因为将来用户搜索手机的时候,我就可以去同一个节点查询,避免出现请求重定向,因为重定向还要重新建立连接,性能上会有一定的损耗,

所以说这一类数据使用相同的有效部分,例如说key都是以{typeID}为前缀

三)redis集群的分片

3.1)分片的定义:在使用redis集群的时候,我们会将存储的数据分散到多台Redis机器上面,这就称之为是分片,简而言之集群中的每一个Redis实例都被认为是整个数据的一个分片

3.2)如何找到给定的key的分片:为了找到给定的key的分片,我们对key进行CRC16(key)算法处理并通过对总分片数量进行取模,然后使用确定性哈希函数,这就意味着给定的key将多次始终映射到一个分片,我们可以进行推断并且读到key的位置

四)slot槽位映射:

1)不一致哈希取余分区:2亿条记录就是2亿个K,V,我们单机是存储不下这些数据的,必须要使用分布式机器,假设有三台机器构成一个集群,用户每一次的读写操作都是根据公式:

hash(key)%机器数,来进行计算出哈希值,用来决定数据映射到哪一个机器上面

1.1)优点:简单粗暴,直接有效,只需要预估好数据,规划好节点,使用哈希算法让固定的一部分请求落在同一台服务器上面,这样每一台服务器来固定处理一部分请求,并且维护这些请求的信息,起到负载均衡和分而治之的作用;

1.2)缺点:原来规划好的节点,进行扩容和缩招就比较麻烦,因为映射关系要重新进行计算除非服务器永远不会变化,在服务器固定个数不变的时候没有问题,但是如果需要进行弹性扩容或者故障停机的情况下,原来的取模公式就会发生变化,Hash(Key)/3就会变成Hash(Key)/2,甚至于说如果某一台Redis直接宕机了,由于台数发生变化,就会导致哈希取余全部数据重新洗牌;

二)一致性哈希算法分区:设计目标是为了解决分布式缓存数据变动和映射问题,如果某一台机器宕机了,分母数量改变了,自然取余数就不OK了,就是为了当服务器的个数发生变动的时候,要尽量减少客户端到服务器的映射关系

2.1)哈希取余分区:一致性哈希是将整个哈希值空间组织成一个虚拟的圆环,比如说假设某一个哈希值的值空间是0-2^32-1,那么他的整个哈希环空间如下,也就是说所有的输入值都被映射到0-2^32之间,组成了一个圆环,前面介绍的算法是针对服务器的数量进行取余,而一致性哈希算法是针对2^32进行取余;

2.2)下一步将各个服务器使用Hash函数进行一个哈希, 具体可以选择服务器的ip或主机名或者其他业务属性作为关键字进行哈希,这样每台机器就能确定其在哈希环上的位置,这里假设将上文中四台服务器使用ip地址哈希后在环空间的位置如下:

2.3)将数据key使用相同的函数Hash计算出哈希值,并确定此数据在环上的位置,从此位置沿环顺时针“行走”,第一台遇到的服务器就是其应该定位到的服务器,并且将该键值对存储到该节点上面

 

 

 

 

 

 

 

五)搭建分片集群 

1)在/myredis目录下面创建9001 9002 9003 9004 9005 9006 9007目录,并分别写入redis.conf文件

2)在redis.conf文件中配置下面的信息

port 9001
# 开启集群功能
cluster-enabled yes
# 集群的配置文件名称,不需要我们创建,只需要程序员指定位置即可这个文件将来由redis自己维护
cluster-config-file /myredis/9001/nodes.conf
# 节点心跳失败的超时时间,如果集群之间相互做心跳的时候超过5s没有心跳,就认为是疑似宕机了
cluster-node-timeout 5000
# 持久化文件存放目录
dir /myredis/9001
# 绑定地址,任何地址都可以访问
bind 0.0.0.0
# 让redis后台运行
daemonize yes
# 注册的实例ip
replica-announce-ip 127.0.0.1
# 保护模式
protected-mode no
# 数据库数量
databases 1
# 日志
logfile /myredis/9001.log

3)启动各个目录下面的redis,虽然此时6个redis实例,全部启动起来了,但是它们彼此之间并没有相互联系起来,因为并没有进行指定谁和谁之间是有联系的

创建集群:

1)redis-cli --cluster create 127.0.0.1:9001 127.0.0.1:9002 127.0.0.1:9003 127.0.0.1:9004 127.0.0.1:9005 127.0.0.1:9006
2)redis-cli -p 9001 cluster nodes

1.1)这里面的redis-cli --cluster代表的是集群操作命令

1.2)create代表的是创建集群

1.3)--cluster-replicas 1代表指定集群中每一个master得副本是1,此时节点总数/(replicas+1)得到的就是master得数量,因此上面的节点列表的前n个就是master,其他节点的都是slave节点,被随机分配到不同的master节点

3)​​​​在我们进行连接集群中的某一个节点的时候,直接输入命令

redis -c -p 具体的端口号

port 9001
# 开启集群功能
cluster-enabled yes
cluster-node-timeout 5000
cluster-announce-ip 127.0.0.1
cluster-announce-port 9001
# 集群的配置文件名称,不需要我们创建,由redis自己维护
cluster-config-file /myredis/9001/nodes.conf
# 节点心跳失败的超时时间
cluster-node-timeout 5000
# 持久化文件存放目录
dir /myredis/9001
# 绑定地址
bind 0.0.0.0
# 让redis后台运行
daemonize yes
# 注册的实例ip
replica-announce-ip 127.0.0.1
# 保护模式
protected-mode no
# 数据库数量
databases 1
# 日志
logfile /myredis/9001.log 
~                                 

所以当你进行操作任意一个key的时候,会先进行计算插槽值,再进行判断你在哪一个节点,在完成一个请求的路由,所以你进行访问任意一个数据,都可以重定向到具体的节点;

集群伸缩

redis-cli --cluster提供了很多可以进行操作集群的命令,可以通过以下方式来进行查看:

1)如果想要进行新增节点,需要指明新的IP地址和新的端口号,还要进行指明集群中已经存在的IP和端口号(为了新增节点的时候通知每一个集群中每一个角色,从而联系上这个集群)

2)下面的--cluster-slave和--cluster--master-ip默认是没有进行添加的,如果没有添加这两个节点,那么这个节点默认就是一个主节点,如果你添加了这两个信息,那么默认就成为了指定节点的从节点了

需求:向集群中添加一个新的master节点,并向其中存储num=10

1)启动一个新的redis实例,端口号是1000

2)添加1000到之前的集群,并作为一个master节点

3)给7004节点分配插槽,使得num这个key可以存储到7004这个主节点上面

1.1)添加新节点到集群中

redis-cli --cluster add-node 127.0.0.1:1000 127.0.0.1:9001

1.2)通过命令查看集群状态

redis-cli -p 1000 cluster nodes

1.3)查看集群状态可知,1000的插槽数量是0,因此没有任何节点可以成功存储到1000这个主节点

1.4)先进行查看num的插槽值是多少,可以看到num的插槽值是2765,也就是说只要2765这个插槽能够成功分配到1000,那么1000这个主节点就可以成功的存储到num值了

1.5)先查看以下分配插槽的命令:

1.6)建立连接: redis-cli --cluster reshard 127.0.0.1:9001

1.7)当你输入命令成功之后,redis会想你进行询问你想要那一部分的插槽,我们需要转移3000个插槽就足够了

1.8)接下来redis有会向你进行询问,你需要将插槽转移到哪里去?所以我们需要直接输入插槽对应的ID即可

1.9)然后redis还是会向你进行询问,你这些插槽,从哪一个主节点开始进行拷贝,请输入主节点的ID,当然是从9001开始呀,于是输入9001对应的ID即可,然后输入done即可

 2.0)再次进行查看redis-cli -p 1000 cluster nodes节点信息

故障转移:

1)先实现将节点断开连接redis -p 对应节点的端口号 shutdown

2)将这个节点重启,发现这个节点已经变成了从节点

当一个集群中有一个master宕机会发生什么呢?

1)首先是该实例会和其他实例断开连接

2)然后是疑似宕机

3)最后是确认下线,自动提升一个该节点的slave节点为新的master节点

从上面的日志信息我们可以看出,当我们把9001这个进程给干掉之后,9005就成为了主节点,如果我们再次启动9001,那么它会变成分片集群中的从节点 

手动故障转移:

1)利用cluster master命令可以让集群中的某一个master宕机,切换到cluster master命令的这个slave节点,实现无感知的数据迁移

2)具体的替换流程如下:现在我想让这个slave节点替换master节点

2.1)当我们去执行命令的这一刻,slave节点回向master节点发送一个消息,和master说我要替换你了,这个时候主节点为了避免消息的丢失,这个master节点就会拒绝客户端的一切请求,所有进来的命令都会进行阻塞;

2.2)master会返回一个offset给slave

2.3)slave也会等地啊当前的数据和master一致,如果不一致赶紧做主从同步

2.4)开始做故障迁移

2.5)让slave充当master,master来充当slave

2.6)这个新的master结点开始做一个广播,通知自己是新的节点

3)这种Failover支持三种不同版本的参数

3.1)不加任何参数,按照默认的流程来进行节点替换

3.2)fource,省略了对offset的一致性校验

3.3)takeover:直接执行2.6,忽略数据一致性,忽略master状态和其他master的意见

 需求:将9001这个slave节点手动进行故障转移,重新夺回master地位

1)需要使用redis-cli连接这个7002节点

2)执行cluster failover命令

StringRedisTemplate访问分片集群: 

1)引入redis的依赖

2)配置分片集群的地址

3)配置读写分离

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

一些题目__

好耶&#xff0c;第一次div2做出来3道题&#xff0c;虽然中间看了个题解&#xff0c;但是思路差不多&#xff0c;被复杂度困住了&#xff0c;nnd 首先是第一个题&#xff0c;emm 第一题 那么这个题的要求是&#xff0c;构造一个数组&#xff0c;满足这些条件&#xff1a; 注意…

Java学习路线(6)——方法

概念&#xff1a; 方法是一种语法结构&#xff0c;可以将一段代码封装成一个功能&#xff0c;方便复用。 特点&#xff1a; 提高代码复用性提高逻辑清晰性 一、基本方法定义和调用 1、有反有参方法 修饰符 返回类型 方法名( 形参列表 ){ 方法体代码; return 返回值; } public…

printf串口重定向标准方法

一&#xff0c;简介 在程序调试的过程中&#xff0c;需要用到串口打印信息来判断单片机程序运行是否正确。需要使用串口对printf进行重定向&#xff0c;本文就介绍一下ARM官方推荐的一种重定向的方法&#xff0c;供参考使用。 二&#xff0c;具体步骤 主要分为两步&#xff…

leetcode 138.复制带随机指针的链表

题目链接&#xff1a;leetcode 138 1.题目 给你一个长度为 n 的链表&#xff0c;每个节点包含一个额外增加的随机指针 random &#xff0c;该指针可以指向链表中的任何节点或空节点。 构造这个链表的 深拷贝。 深拷贝应该正好由 n 个 全新 节点组成&#xff0c;其中每个新节…

如何用Nginx实现对城市以及指定IP的访问限制?

1.前言 在【如何用Nginx代理MySQL连接&#xff0c;并限制可访问IP】一文中&#xff0c;我们实现了通过Nginx代理MySQL连接&#xff0c;并限制了指定IP才能通过Nginx进行连接&#xff0c;以提高数据安全性。 该场景适用于根据具体的IP地址来进行访问限制&#xff0c;假如我们要…

C++控制台打飞机小游戏

我终于决定还是把这个放出来。 视频在这&#xff1a;https://v.youku.com/v_show/id_XNDQxMTQwNDA3Mg.html 具体信息主界面上都有写。 按空格暂停&#xff0c;建议暂停后再升级属性。 记录最高分的文件进行了加密。 有boss&#xff08;上面视频2分47秒&#xff09;。 挺好…

LeetCode 不同路径1\2

不同路径1和2 题目在上面 这两个题目都是简单的动态规划问题 对不同路径最初始的问题举个例子 因为我们的机器人只能向右或者向下走一步 因此这个矩形的第一行和第一列都可以初始化为1 然后我们就可以得到动态规划的方程 f i , j f i − 1 , j f i , j − 1 f_{i,j} f_{i…

【C++模板】

目录 一、什么是泛型编程二、函数模板2.1函数模板概念2.2函数模板格式2.3函数模板的原理2.4函数模板的实例化 三、类模板3.1类模板的定义格式3.2类模板的成员函数的声明与定义分开的写法 一、什么是泛型编程 问题&#xff1a;如何实现一个加法函数呢&#xff1f;假设加法函数的…

LeetCode94. 二叉树的中序遍历(递归与非递归)

写在前面&#xff1a; 题目链接&#xff1a;添加链接描述 编程语言&#xff1a;c 题目难度&#xff1a;简单 一、题目描述 给定一个二叉树的根节点 root &#xff0c;返回 它的 中序 遍历 。 输入&#xff1a;root [1,null,2,3] 输出&#xff1a;[1,3,2] 示例 2&#xff1a;…

chatgpt赋能Python-python3_6怎么保存

Python3.6的保存方式简介 Python3.6是一种高级编程语言&#xff0c;由于其易读性和清晰性&#xff0c;成为了广泛使用的编程语言之一。Python3.6提供了丰富的特性和功能&#xff0c;使其成为了开发各种网站和Web应用程序的完美选择。在这篇文章中&#xff0c;我们将介绍Python…

8.2 综合案例2.0-远程遥控智能锁

综合案例2.0-远程遥控智能锁 案例说明1.硬件2.连线图3.dvr8833电机驱动使用说明 搭建云平台环境1.添加设备2.创建设备类型3.功能定义&#xff08;创建物模型&#xff09;4.ThingsX App 配置5.生成用户应用 App 代码1.更改MQTT信息2.测试 案例说明 生活中很多场景需要用到锁&am…

一、预约挂号微服务模块搭建

文章目录 一、预约挂号微服务模块搭建1、项目模块构建2、sql资源3、构建父工程&#xff08;yygh-parent&#xff09;3.1、添加配置pom.xml 4、搭建common父模块4.1、搭建common4.2、修改配置pom.xml 5、搭建common-util模块5.1、搭建common-util5.2、修改配置pom.xml5.3、添加公…

运筹优化求解迭代过程案例:图解法、单纯形法、单纯形表

运筹优化求解迭代过程案例:图解法、单纯形法、单纯形表 题目来自于清华大学出版的《运筹学》第四版。 一、问题描述 二、图解法 三、单纯形法 第一次迭代&#xff1a; 第二次迭代&#xff1a; 第三次迭代&#xff1a; 下面描述一下第三次迭代的详细过程&#xff1a; 从表达式…

【进阶】MySQL索引介绍

半个月没写mysql了&#xff0c;今天记录一下。。 了解到的索引有Btree&#xff0c;Hash表&#xff08;Memory存储引擎中&#xff09;&#xff0c;R-tree&#xff0c;Full-text等 MySql用的索引结构是Btree&#xff0c;B树所有节点都会出现在叶子节点中 目录 索引介绍&#…

容器目录挂载原理

前言 就我目前的对容器的了解, 使用namespace技术实现隔离, 使用cgroups技术实现资源限制. 但是具体是如何实现却从未深究过. 闲来无事, 挑其中的Mount Namespace来康康, 容器是如何实现目录隔离的. 目录隔离 在耗子叔的这篇文章中对此技术进行了介绍. 在c函数库中, 可通过…

Linux Audio (4) ASOC代码分析-基于kernel3.4.2

ASOC代码分析-基于kernel3.4.2 OverviewPlatformCPU DAICPU DMA CodecMechine Linux kernel版本&#xff1a;3.4.2 Overview linux ASoC音频设备驱动 ASoC是ALSA在SoC方面的发展和演变&#xff0c;它的本质仍然属于ALSA&#xff0c;但是在ALSA架构基础上对CPU相关的代码和Cod…

【python之django1.11框架一】django环境搭建及基本操作

1. 环境准备 开发环境&#xff1a;windows 11先安装好miniconda3。镜像地址&#xff1a;https://mirrors.tuna.tsinghua.edu.cn/anaconda/miniconda/ 选择windows 64位下载。 下载地址&#xff1a; https://mirrors.tuna.tsinghua.edu.cn/anaconda/miniconda/Miniconda3-lates…

JIRA的数据备份与恢复教程

目录 一、简介 二、数据备份&#xff08;默认系统会自动备份&#xff0c;不需要手动&#xff09; 1、使用管理员账号登录JIRA。 2、点击左上角的设置按钮&#xff0c;选择“系统”选项。 3、选择“备份系统”选项 4、开始手动备份 5、查看备份进度 三、数据恢复 1、使用…

MyBatisPlus入门案例

文章目录 1 入门案例步骤1:创建数据库及表步骤2:创建SpringBoot工程步骤3:勾选配置使用技术步骤4:pom.xml补全依赖步骤5:添加MP的相关配置信息步骤6:根据数据库表创建实体类步骤7:创建Dao接口步骤8:编写引导类步骤9:编写测试类 2 MybatisPlus简介 MyBatisPlus主要是对MyBatis的…

SQL注入 - Part 1

前置知识&#xff1a;sql前置的软件环境&#xff1a;预装了phpstudy_prodvwa&#xff0c;花了好长时间……时间主要浪费在听从chatgpt的建议装xampp上&#xff0c;卸载了mysql&#xff0c;重置了密码。其实使用xampp搭建环境也成功了&#xff0c;但是由于phpstudy教程比较多&am…