redis与分布式

主从复制

概念

主从复制,是指将一台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服务器获取到锁,那么就真的获取到锁了,这样就算挂掉一部分节点,也能保证正常运行

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

MySQL----MHA高可用

文章目录 一、MHA理论1.1什么是 MHA1.2MHA 的组成1.3MHA 的特点 二、MHA的一主两从部署实验设计故障修复步骤&#xff1a; 一、MHA理论 1.1什么是 MHA MHA&#xff08;MasterHigh Availability&#xff09;是一套优秀的MySQL高可用环境下故障切换和主从复制的软件。 MHA 的出…

【Django】Django框架使用指南

Django使用指南 作者简介&#xff1a;嗨~博主目前是长安大学软件工程专硕在读&#x1f4d8;&#xff0c;喜欢钻研一些自己感兴趣的计算机技术&#xff0c;求关注&#x1f609;&#xff01; 框架简介&#xff1a;Django是一个基于Python语言的开源Web应用框架&#xff0c;采用 M…

基于STM32FFT(快速傅里叶变换)音频频谱显示功能实现

+ v hezkz17进数字音频系统研究开发交流答疑 一实验效果 二 设计过程 要用C语言实现STM32频谱显示功能,可以按照以下步骤进行操作: 1 确保已经安装好了适当的开发环境和工具链,例如Keil MDK或者GCC工具链。 2 创建一个新的STM32项目,并选择适合的MCU型号。 3 配置G…

【数据挖掘】时间序列教程【九】

第5章 状态空间模型和卡尔曼滤波 状态空间模型通常试图描述具有两个特征的现象 有一个底层系统具有时变的动态关系,因此系统在时间上的“状态”t 与系统在时间的状态t−1有关 .如果我们知道系统在时间上的状态t−1 ,那么我们就有了我们需要知道的一切,以便对当时的状态进行推…

Android Zygote 启动流程

和你一起终身学习&#xff0c;这里是程序员Android 经典好文推荐&#xff0c;通过阅读本文&#xff0c;您将收获以下知识点: Android系统包含netd、servicemanager、surfaceflinger、zygote、media、installd、bootanimation 等基本服务&#xff0c;具体作用请看下图。 Android…

更开放、更高性能、更具规模,闪马智能布局AGI时代

7月6日&#xff0c;2023世界人工智能大会&#xff08;WAIC 2023&#xff09;在上海盛大开幕。本届大会以“智联世界 生成未来”为主题&#xff0c;聚焦通用人工智能发展&#xff0c;共话产业新未来。 8日上午&#xff0c;由上海闪马智能科技有限公司&#xff08;下称“闪马智能…

el-form实现其中一个填写即可的校验

<el-formref"form":model"formData":rules"formRules"label-width"130px"><el-row :gutter"24"><el-col :span"12"><el-form-item label"司机姓名 :" prop"driverName"…

西电_矩阵论_学习笔记

文章目录 【 第一章 线性空间 】【 第二章 范数 】【 第三章 矩阵函数 】【 第四章 矩阵分解 】【 第五章 矩阵特征值估计 】【 第六章 广义逆 】【 考试重点内容总结 】 这是博主2023春季西电所学矩阵论的思维导图&#xff08;软件是幕布&#xff09;&#xff0c;供大家参考&a…

GaussDB OLTP云数据库配套工具DRS

目录 一、前言 二、DRS定义与使用场景 1、DRS定义 2、DRS场景示意图 三、DRS核心功能 1、实时迁移管理 2、实时同步管理 3、备份迁移管理 4、数据订阅管理 5、实时灾备管理 四、小结 一、前言 华为GaussDB云数据库提供了配套的生态工具数据复制服务DRS。 DRS围绕云…

漏洞深度分析 | CVE-2023-36053-Django 表达式拒绝服务

​ 项目介绍 Django 是一个高级 Python Web 框架&#xff0c;鼓励快速开发和简洁、务实的设计。它由经验丰富的开发人员构建&#xff0c;解决了 Web 开发的大部分麻烦&#xff0c;因此您可以专注于编写应用程序&#xff0c;而无需重新发明轮子。它是免费且开源的。 项目地址…

Squid 缓存服务器

Squid 缓存服务器 作为应用层的代理服务软件&#xff0c;Squid 主要提供缓存加速和应用层过滤控制的功能 ☆什么是缓存代理 当客户机通过代理来请求 Web 页面时 指定的代理服务器会先检查自己的缓存&#xff0c;如果缓存中已经有客户机需要访问的页面&#xff0c;则直接将缓…

【考研思维题】【哈希表 || 什么时候用哈希表呢?快速查询的时候】【我们一起60天准备考研算法面试(大全)-第九天 9/60】

专注 效率 记忆 预习 笔记 复习 做题 欢迎观看我的博客&#xff0c;如有问题交流&#xff0c;欢迎评论区留言&#xff0c;一定尽快回复&#xff01;&#xff08;大家可以去看我的专栏&#xff0c;是所有文章的目录&#xff09;   文章字体风格&#xff1a; 红色文字表示&#…

ModaHub魔搭社区:向量数据库Zilliz Cloud删除 Entity和删除 Collection教程

目录 删除单个 Entity 批量删除 Entity 开始前 操作步骤 使用限制 Entity 是指存储在 Zilliz Cloud 集群中的数据实体,包含用于处理、搜索和查询的数据。如果您不再需要某个 Entity,可以执行相关操作将其删除。 本文介绍如何从 Collection 中删除单个或多个 Entity。 …

网络数据包的监听与分析——IP数据报文分析

1. 抓包工具下载 x下面是一个IP数据报的抓包软件——IPtool的蓝奏云下载链接 https://wwix.lanzoue.com/iaGpy11klpnc 2. iptool使用 下载解压之后&#xff0c;右击以管理员身份运行&#xff0c;打开该exe文件即可 然后点击绿色运行就开始捕包了 随便点一个包进去进行分析就可…

JAVA-MAVEN初学者教程(配置、pom.xml、依赖管理等)

目录 认识MAVEN安装&配置MAVENwindows安装MAVENMAVEN的配置本地仓库 localRepository镜像 mirrors代理仓库 respositories代理 proxies IDEA配置MAVEN&#xff08;一个module&#xff09; MAVEN生命周期install下载包 模块的pom.xml坐标gav打包方式 package属性值 properti…

web 前端 Day 4

盒子模型 <style>div {width: 300px;height: 300px;background-color: pink;padding-left: 4px; 左侧内边距border: 3px solid red;margin: 50px;}</style> padding 内边距 </head> ​ <body> ​<div>cfdaffshydghjgdjdnjjjjjjjjjjjjjjj&l…

Spark学习--3、WordCount案例、RDD序列化、RDD依赖关系、RDD持久化

1、WordCount案例实操 导入项目依赖 <dependencies><dependency><groupId>org.apache.spark</groupId><artifactId>spark-core_2.12</artifactId><version>3.3.0</version></dependency> </dependencies>1.1 本…

2023年java还是golang还是c#?

前言 我们可以先来看一下这三门语言各自的优劣 学习曲线&#xff1a;如果你是初学者或对编程相对陌生&#xff0c;Java可能是一个较好的选择。它有广泛的学习资源和社区支持&#xff0c;易于上手。Go也有简单易学的特点&#xff0c;但由于相对较年轻&#xff0c;相关的学习资…

Linux驱动进阶(一)——设备驱动中的并发控制

文章目录 前言并发与竞争原子变量操作原子变量操作原子整型操作原子位操作 自旋锁自旋锁概述自旋锁的使用自旋锁的使用注意事项 信号量信号量概述信号量的实现信号量的使用自旋锁与信号量的对比 完成量完成量概述完成量的实现完成量的使用 小结 前言 现代操作系统有三大特征&a…

frp内网穿透

frp内网穿透 一.frp的作用和原理图 1.首先frp分客户端和服务端&#xff0c;frp客户端和服务端在同一个局域网。 2.frp服务端拥有公网ip与互联网连通。 frp的作用&#xff1a; 通过一台公司拥有外网ip的服务器做为frp服务端&#xff0c;通过请求转发的形式&#xff0c;转发到公…