redis与分布式

news2024/12/28 3:00:57

主从复制

概念

主从复制,是指将一台Redis服务器的数据,复制到其他的Redis服务器。前者称为主节点(Master),后者称为从节点(Slave),数据的复制是单向的,只能由主节点到从节点。Master以写为主,Slave 以读为主(只读模式),当主节点关闭后,从节点依然可以读取数据,但是会报错

优点

  • 实现了读写分离,提高了性能

  • 在写少读多的场景下,我们甚至可以安排很多个从节点,这样就能够大幅度的分担压力,并且就算挂掉一个,其他的也能使用

实验

打开两个redis服务器,修改配置文件redis.conf的端口

一个服务器的端口设定为6001,复制一份,另一个的端口为6002,再分别指定配置文件进行启动

redis-server.exe redis.conf

输入info replication命令来查看当前的主从状态,可以看到默认的角色为:master,也就是说所有的服务器在启动之后都是主节点的状态,在6002的客户端输入slaveof/replicaof 127.0.0.1 6001命令后,就会将6001服务器作为主节点,而当前节点作为6001的从节点,并且角色也会变成:slave,而且从节点信息中已经出现了6002服务器,也就是说现在6001和6002就形成了主从关系(还包含一个偏移量,这个偏移量反应的是从节点的同步情况)

 

主服务器和从服务器都会维护一个复制偏移量,主服务器每次向从服务器中传递 N 个字节的时候,会将自己的复制偏移量加上 N。从服务器中收到主服务器的 N 个字节的数据,就会将自己额复制偏移量加上 N,通过主从服务器的偏移量对比可以很清楚的知道主从服务器的数据是否处于一致,如果不一致就需要进行增量同步了

测试:在主节点新增数据,同步到从节点

 

通过输入replicaof/slaveof no one,即可变回Master角色

新增从节点同步流程

  • 从节点执行replicaof ip port命令后,从节点会保存主节点相关的地址信息。

  • 从节点通过每秒运行的定时任务发现配置了新的主节点后,会尝试与该节点建立网络连接,专门用于接收主节点发送的复制命令。

  • 连接成功后,第一次会将主节点的数据进行全量复制,之后采用增量复制,持续将新来的写命令同步给从节点。

配置文件配置主节点

replicaof 127.0.0.1 6001    #填到从节点的配置文件中

还可以使某节点作为从节点的从节点

replicaof 127.0.0.1 6002    #填到从节点6003的配置文件中

 

从节点分布

 

第二个分布的缺点:整个传播链路一旦中途出现问题,那么就会导致后面的从节点无法及时同步

哨兵模式

这里的哨兵是是专用于Redis的。哨兵会对所有的节点进行监控,如果发现主节点出现问题,那么会立即从从节点选举一个新的主节点出来,这样就不会由于主节点的故障导致整个系统不可写

类似于服务治理模式,比如Nacos和Eureka,所有的服务都会被实时监控,那么只要出现问题,肯定是可以及时发现的,并且能够采取响应的补救措施

 

如何添加哨兵:直接删除配置文件的全部内容并添加如下内容

#第一个和第二个是固定,第三个是为监控对象名称,随意,后面就是主节点的相关信息,包括IP地址和端口
sentinel monitor lbwnb 127.0.0.1 6001 1

选举规则:

  1. 首先会根据优先级进行选择,可以在配置文件中进行配置,添加replica-priority配置项(默认是100),越小表示优先级越高

  2. 如果优先级一样,那就选择偏移量最大的

  3. 要是还选不出来,那就选择pid(启动时随机生成的)最小的

可以修改配置中的端口实现多个哨兵

与Java互动

在哨兵重新选举新的主节点之后,Java中的Redis的客户端怎么感知到呢

<dependencies>
    <dependency>
        <groupId>redis.clients</groupId>
        <artifactId>jedis</artifactId>
        <version>4.2.1</version>
    </dependency>
</dependencies>
public class Main {
    public static void main(String[] args) {
        //直接使用JedisSentinelPool来获取Master节点
        //需要把三个哨兵的地址都填入
        try (JedisSentinelPool pool = new JedisSentinelPool("lbwnb",
                new HashSet<>(Arrays.asList("127.0.0.1:26741", "127.0.0.1:26740", "127.0.0.1:26739")))) {
            Jedis jedis = pool.getResource();   //直接询问并得到Jedis对象,这就是连接的Master节点
            jedis.set("test", "114514");    //直接写入即可,实际上就是向Master节点写入
​
            Jedis jedis2 = pool.getResource();   //再次获取
            System.out.println(jedis2.get("test"));   //读取操作
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

集群搭建

因为单机的内存容量有限,已经没办法再继续扩展时,但又需要存储更多的内容,这时就可以让N台机器上的Redis来分别存储各个部分的数据(每个Redis可以存储1/N的数据量),实现了容量的横向扩展。同时每台Redis还可以配一个从节点,这样就可以更好地保证数据的安全性

 

集群的机制

插槽就是键的Hash计算后的一个结果,采用CRC16,能得到16个bit位的数据,也就是说算出来之后结果是0-65535之间,再进行取模

Redis key的路由计算公式:s = CRC16(key) % 16384

一个Redis集群包含16384个插槽,集群中的每个Redis 实例负责维护一部分插槽以及插槽所映射的键值数据

哈希结果的值是多少,就应该存放到对应维护的Redis下,比如Redis节点1负责0-25565的插槽,而这时客户端插入了一个新的数据a=10,a在Hash计算后结果为666,那么a就应该存放到1号Redis节点中。本质上就是通过哈希算法将插入的数据分摊到各个节点的

集群搭建

配置中开启集群模式

# cluster node enable the cluster support uncommenting the following:
#
cluster-enabled yes

接着把所有的持久化文件全部删除,所有的节点内容必须是空的

输入

redis-cli.exe --cluster create --cluster-replicas 1 127.0.0.1:6001 127.0.0.1:6002 127.0.0.1:6003 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003
#--cluster-replicas 1指的是每个节点配一个从节点
​

 

默认分配的方案是6001/6002/6003都被选为主节点,其他的为从节点,直接输入yes同意方案即可

插入数据时,键计算出来的哈希值(插槽),若不归当前节点管,则无法插入,需要去管这个插槽的节点执行

也可以使用集群方式连接,这样无论在哪个节点都可以插入,只需要添加-c表示以集群模式访问

 

输入cluster nodes命令来查看当前所有节点的信息

当一个主节点挂了,其从节点就可以晋升为主节点,再次启用原主节点,发现其变为现主节点的从节点,当两个节点都挂了,也就是说集群存在不可用的节点,会无法插入新的数据

Java连接到集群模式下的Redis

使用JedisCluster对象即可

public class Main {
    public static void main(String[] args) {
        //和客户端一样,随便连一个就行,也可以多写几个,构造方法有很多种可以选择
        try(JedisCluster cluster = new JedisCluster(new HostAndPort("127.0.0.1", 6003))){
            System.out.println("集群实例数量:"+cluster.getClusterNodes().size());
            cluster.set("a", "yyds");
            System.out.println(cluster.get("a"));
        }
    }
}

分布式锁

setnx key value #只有当指定的key不存在的时候,才能进行插入
#当客户端1设定a之后,客户端2使用setnx会直接失败,但使用set可以成功
#当客户端1删除a之后,客户端2使用setnx就会成功

某个服务加了锁但服务本身卡顿了或是直接崩溃了,那这把锁将无法释放了,因此还可以考虑加个过期时间

set a 666 EX 5 NX   #最后加一个NX表示是使用setnx的模式

问题1:一个服务放了一个键值对,由于资源紧张服务时间过长,键值对的过期时间先到了,而在第一个服务未结束时,第二个服务开启并存放了与第一个服务键值相同的数据,然后第一个服务完事了,就把第二个服务存放的键值对删了

只是添加过期时间,会出现这种把别人加的锁谁卸了的情况

解决方案:现在想保证任务只能删除自己加的锁,如果是别人加的锁是没有资格删的,所以可以吧a的值指定为任务专属的值,如果在主动删除锁的时候发现值不是当前任务指定的,那么说明可能是因为超时,其他任务已经加锁了

问题2:如果在超时之前那一刹那进入到释放锁的阶段,获取到值还是自己,但是在即将执行删除之前,由于超时机制导致被删除并且其他任务也加锁了,那么这时再进行删除,仍然会导致删除其他任务加的锁

本质还是因为锁的超时时间不太好衡量,如果超时时间能够设定地比较恰当,就可以避免这种问题了

解决方案:可以使用Redisson框架,它是Redis官方推荐的Java版的Redis客户端。Redisson内部提供了一个监控锁的看门狗,作用是在Redisson实例被关闭前,不断的延长锁的有效期,它提供了很多种分布式锁的实现

<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson</artifactId>
    <version>3.17.0</version>
</dependency>
<dependency>
    <groupId>io.netty</groupId>
    <artifactId>netty-all</artifactId>
    <version>4.1.75.Final</version>
</dependency>
// 注:这个锁是基于Redis的,不仅仅只可以用于当前应用,是能够垮系统的
public static void main(String[] args) {
    Config config = new Config();
    config.useSingleServer().setAddress("redis://127.0.0.1:6379");   //配置连接的Redis服务器,也可以指定集群
    RedissonClient client =  Redisson.create(config);   //创建RedissonClient客户端
    for (int i = 0; i < 10; i++) {
        new Thread(() -> {
            try(Jedis jedis = new Jedis("127.0.0.1", 6379)){
                RLock lock = client.getLock("testLock");    //指定锁的名称,拿到锁对象
                for (int j = 0; j < 100; j++) {
                    lock.lock();    //加锁
                    int a = Integer.parseInt(jedis.get("a")) + 1;
                    jedis.set("a", a+"");
                    lock.unlock();   //解锁
                }
            }
            System.out.println("结束!");
        }).start();
    }
}

如果用于存放锁的Redis服务器挂了,还是是会出问题的,这个时就可以使用RedLock,它的思路是,在多个Redis服务器上保存锁,只需要超过半数的Redis服务器获取到锁,那么就真的获取到锁了,这样就算挂掉一部分节点,也能保证正常运行

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

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

相关文章

kong-dashboard安装

简介 kong-dashboard提供了UI界面操作和查看kong&#xff0c;可以进行api、consumers、plugins操作 官网&#xff1a;https://hub.docker.com/r/pgbi/kong-dashboard/ 安装 联网安装 [slviewDEMO:~]$ docker search kong-dashboard INDEX NAME …

终端安全管理系统(软件)能干什么?

随着企业网络化的进程&#xff0c;大多数企业已经开始通过终端安全管理系统来改善企业的网络环境&#xff0c;管控员工的上网行为&#xff0c;但同时还有很多企业不了解其具体的用处&#xff0c;那终端安全管理系统究竟可以干什么呢&#xff1f; 一、加密重要文档&#xff0c;保…

概率DP求期望

[NOIP2016 提高组] 换教室 链接&#xff1a;https://www.luogu.com.cn/problem/P1850 题目描述 对于刚上大学的牛牛来说&#xff0c;他面临的第一个问题是如何根据实际情况申请合适的课程。 在可以选择的课程中&#xff0c;有 2 n 2n 2n 节课程安排在 n n n 个时间段上。…

D352周赛复盘:重点是双指针滑动窗口+质数判断

文章目录 6909.最长奇偶子数组&#xff08;双指针&#xff09;思路完整版 6916.和等于目标的质数对&#xff08;质数判断&#xff0c;重要&#xff09;思路质数判断&#xff1a;埃拉托斯特尼筛法获取所有小于等于n的质数质数定义 完整版为什么只遍历到n/2&#xff1f; 时间复杂…

python 深度学习 解决遇到的报错问题2

目录 一、解决报错UnicodeDecodeError: utf-8 codec cant decode byte 0xe3 in position 15: invalid continuation byte 二、解决ERROR: Could not build wheels for pycocotools, which is required to install pyproject.toml-based pro 三、解决OSError: [WinError 1314…

flutter 中实现动态表单 form generator

flutter 中实现动态表单 form generator 前言 最近有人问我 flutter 前端如何处理动态表单。 这种是企业开发中的常见问题&#xff0c;特别是问卷和工作流审核表单。 今天我们就来实现下这个功能&#xff0c;主要是处理这个业务功能的思路。 原文 https://ducafecat.com/blog/…

通用分页(下)

一.理解分页思想 1.分页的实质 1.1&#xff08;自我概述&#xff09; 用最简单的话来说&#xff0c;就是在一个界面展示不了那么多数据时&#xff0c;通过一点手段将数据一部分一部分的加载出来&#xff0c;从而减少服务器的压力。并且使能够让服务器利用率提高&#xff01; …

把yum源配置为ftp服务

配置yum源为ftp服务 一、在node1部署ftp服务器1.1 挂载镜像1.2 配置ftp的根目录 二、配置node2的yum源为node1的ftp服务器2.1 移除node2中默认的yum源文件2.2 创建新的yum源文件2.3 更新yum软件列表 环境介绍&#xff1a;有node1和node2两台Centos7虚拟机 环境准备&#xff1a;…

C++ 图的遍历

1. 图的遍历 给定一个图 G 和其中任意一个顶点 v0 &#xff0c;从 v0 出发&#xff0c;沿着图中各边访问图中的所有顶点&#xff0c;且每个顶 点仅被遍历一次 。 " 遍历 " 即对结点进行某种操作的意思 。 请思考树以前是怎么遍历的&#xff0c;此处可以直接用来遍…

手搓GPT系列之 - 通过理解LSTM的反向传播过程,理解LSTM解决梯度消失的原理 - 逐条解释LSTM创始论文全部推导公式,配超多图帮助理解(下篇)

本文承接上篇上篇在此和中篇中篇在此&#xff0c;继续就Sepp Hochreiter 1997年的开山大作 Long Short-term Memory 中APPENDIX A.1和A.2所载的数学推导过程进行详细解读。希望可以帮助大家理解了这个推导过程&#xff0c;进而能顺利理解为什么那几个门的设置可以解决RNN里的梯…

Spring中@NotEmpty、@NotBlank、@NotNull 的区别和使用

1、引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><version>2.0.5.RELEASE</version> </dependency>NotEmpty、NotBlank、NotNull 包的位置&#xff1…

i春秋,春秋云镜系列

目录 先提神CVE-2022-32991靶标介绍&#xff1a;复现&#xff1a; CVE-2022-30887靶标介绍&#xff1a;复现 先提神 CVE-2022-32991 靶标介绍&#xff1a; 该CMS的welcome.php中存在SQL注入攻击。 复现&#xff1a; 打开靶场地址&#xff0c;三个随便选一个进去&#xff0c…

Gof23设计模式之适配器模式

1.定义 将一个类的接口转换成客户希望的另外一个接口&#xff0c;使得原本由于接口不兼容而不能一起工作的那些类能一起工作。 适配器模式分为类适配器模式和对象适配器模式&#xff0c;前者类之间的耦合度比后者高&#xff0c;且要求程序员了解现有组件库中的相关组件的内部结…

国产划片机开创了半导体芯片切割的新工艺时代

国产划片机确实开创了半导体芯片切割的新工艺时代。划片机是一种用于切割和划分半导体芯片的设备&#xff0c;它是半导体制造过程中非常重要的一环。在过去&#xff0c;划片机技术一直被国外厂商所垄断&#xff0c;国内半导体制造企业不得不依赖进口设备。 然而&#xff0c;随着…

QT学习笔记6--信号之间的连接

连接 仍然使用connect函数&#xff0c;但是和函数重载类似&#xff0c;需要用到函数指针。如下所示 void (teacher:: *teachersignals)(void) &teacher::hungery;void (student:: *studentslots)(void) &student::treat;connect(zt,teachersignals,st,studentslots)…

水利三类人员专职安全生产管理人员c证安全生产法律法规考试题库

​本题库是根据最新考试大纲要求&#xff0c;结合近年来考试真题的重难点进行汇编整理组成的全真模拟试题&#xff0c;考生们可以进行专项训练&#xff0c;查漏补缺巩固知识点。本题库对热点考题和重难点题目都进行了仔细的整理和编辑&#xff0c;相信考生在经过了针对性的刷题…

浏览器使用Notification桌面通知消息推送

什么是 Notification&#xff1f; Notification 是浏览器最小化后在桌面显示消息的一种方法类似于 360 等流氓软件在桌面右下角的弹窗广告它与浏览器是脱离的&#xff0c;消息是置顶的 一、弹窗授权 授权当前页面允许通知可以通过检查只读属性 Notification.permission 的值来…

基于Springboot+Html的健身房管理系统

✌全网粉丝20W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取项目下载方式&#x1f345; 一、项目背景介绍&#xff1a; 随着现代生活方式的改…

基于改进莱维飞行和混沌映射的金鹰优化算法(10种混沌映射随意切换),附matlab代码

“ 本篇文章对金鹰优化算法进行改进&#xff0c;首先通过引入混沌映射机制&#xff0c;对其群体进行初始化&#xff0c;增加金鹰个体的多样性&#xff1b;然后在金鹰个体的位置更新公式上引入改进的莱维飞行机制&#xff0c;提高搜索精度&#xff0c;帮助金鹰个体跳出局部最优。…

谈谈NLP中 大语言模型LLM的 思维链 Chain-of-Thought(CoT)

Chain-of-Thought(CoT) 1.介绍 在过去几年的探索中&#xff0c;业界发现了一个现象&#xff0c;在增大模型参数量和训练数据的同时&#xff0c;在多数任务上&#xff0c;模型的表现会越来越好。因而&#xff0c;现有的大模型LLM&#xff0c;最大参数量已经超过了千亿。 然而…