当前位置: 首页 > news >正文

Redis03 - 高可用

Redis高可用

文章目录

  • Redis高可用
    • 一:主从复制 & 读写分离
      • 1:主从复制的作用
      • 2:主从复制原理
        • 2.1:全量复制
        • 2.2:增量复制(环形缓冲区)
      • 3:主从复制实际演示
        • 3.1:基本流程
          • 准备好两个redis服务器
          • 配置修改
          • 启动两个服务器
          • 查看主从状态
          • 主从配置指令
          • 测试下
        • 3.2:一些说明
      • 4:读写分离问题
    • 二:哨兵模式
      • 1:基本工作流程
        • 1.1:哨兵集群组建(消息pub/sub)
        • 1.2:下线判断(客观下线)
        • 1.3:主哨兵选举(raft半数通过)
        • 1.4:新主库的选出(健康,完整的)
        • 1.5:故障转移(易主通知复制)
      • 2:哨兵模式实际演示
        • 2.1:基本流程
          • 创建哨兵服务器
          • 修改哨兵服务器的配置文件
          • 启动哨兵服务器
          • 主节点挂掉测试
          • 要是哨兵也挂了咋办?
        • 2.2:Jedis感知
    • 一:集群
      • 1:集群的引入
      • 2:设计目标
      • 3:常用概念
        • 3.1:哈希槽 hash_slot
        • 3.2:hash_tags
        • 分片nodes属性
        • 3.3:集群总线
      • 4:搭建实例
        • 4.1:基本流程
          • 创建六个redis服务器
          • 配置修改
          • 全部启动
          • 主从集群分配
        • 4.2:其他说明
          • 节点信息
          • 让某一个主节点挂掉会怎么样?
          • 主从都挂了怎么办?
          • Jedis

一:主从复制 & 读写分离

主从复制,主从复制是指将一台redis上的服务的数据复制到另外的redis上,前者称为主节点,后者称为从节点【单向性】

1:主从复制的作用

数据冗余

主从复制实现了数据的热备份,是持久化之外的一种数据冗余的方式

故障恢复

当主节点出现问题的时候,可以由从节点提供服务,实现快速的故障恢复,实际上是一种服务的冗余。

负载均衡

在主从复制的基础上,配合读写分离,可以由主节点提供写服务,从节点提供读服务,分担服务器的负载,尤其是在写少读多的情况下,通过配置多个从节点分担读负载,可以大大的提高redis服务器的并发量。

在这里插入图片描述

高可用基石

是哨兵模式和集群可以实现的基础,因此可以说是高可用的基础。

2:主从复制原理

和MongoDB的初始同步和复制很像

2.1:全量复制

当我们启动多个redis实例的时候,就可以使用replicaof(5.0以前是slaveof)形成主库和从库的关系

会按照三个步骤完成数据的第一次同步:

确立主从关系

例如:现在有实例 1(ip:172.16.19.3)和实例 2(ip:172.16.19.5)

我们在实例 2 上执行以下这个命令后,实例 2 就变成了实例 1 的从库,并从实例 1 上复制数据

replicaof 172.16.19.3 6379

全量复制的三个阶段

在这里插入图片描述
第一步:建立连接,协商同步

  • 主要是为全量复制做准备。
  • 在这一步,从库和主库建立起连接,并告诉主库即将进行同步,主库确认回复后,主从库间就可以开始同步了。
  • 具体来说,从库给主库发送 psync 命令,表示要进行数据同步,主库根据这个命令的参数来启动复制。psync 命令包含了主库的 runID 和复制进度 offset 两个参数。runID,是每个 Redis 实例启动时都会自动生成的一个随机 ID,用来唯一标记这个实例。当从库和主库第一次复制时,因为不知道主库的 runID,所以将 runID 设为“?”。offset,此时设为 -1,表示第一次复制。主库收到 psync 命令后,会用 FULLRESYNC 响应命令带上两个参数:主库 runID 和主库目前的复制进度 offset,返回给从库。从库收到响应后,会记录下这两个参数。
  • 注意,FULLRESYNC 响应表示第一次复制采用的全量复制,也就是说,主库会把当前所有的数据都复制给从库。

第二步:将主库所有同步数据给从库

  • 从库收到数据后,在本地完成数据加载。这个过程依赖于内存快照生成的 RDB 文件
  • 具体来说,主库执行 bgsave 命令,生成 RDB 文件,接着将文件发给从库。从库接收到 RDB 文件后,会先清空当前数据库,然后加载 RDB 文件。这是因为从库在通过 replicaof 命令开始和主库同步前,可能保存了其他数据。为了避免之前数据的影响,从库需要先把当前数据库清空。在主库将数据同步给从库的过程中,主库不会被阻塞,仍然可以正常接收请求。否则,Redis 的服务就被中断了。但是,这些请求中的写操作并没有记录到刚刚生成的 RDB 文件中。为了保证主从库的数据一致性,主库会在内存中用专门的 replication buffer,记录 RDB 文件生成后收到的所有写操作。

第三步:主库发送新的写命令给从库

  • 当主库完成 RDB 文件发送后,就会把此时 replication buffer 中的修改操作发给从库,从库再重新执行这些操作。这样一来,主从库就实现同步了
2.2:增量复制(环形缓冲区)

如果主从库在命令传播时出现了网络闪断,那么,从库就会和主库重新进行一次全量复制,开销非常大。

从 Redis 2.8 开始,网络断了之后,主从库会采用增量复制的方式继续同步。
在这里插入图片描述

repl_backlog_buffer

它是为了从库断开之后,如何找到主从差异数据而设计的环形缓冲区,从而避免全量复制带来的性能开销

⚠️ 如果从库断开时间太久,repl_backlog_buffer环形缓冲区被主库的写命令覆盖了,那么从库连上主库后只能乖乖地进行一次全量复制

所以repl_backlog_buffer配置尽量大一些,可以降低主从断开后全量复制的概率

repl_buffer

我们每个client连上Redis后,Redis都会分配一个client buffer,所有数据交互都是通过这个buffer进行的

注意点

一个从库如果和主库断连时间过长,造成它在主库repl_backlog_buffer的slave_repl_offset位置上的数据已经被覆盖掉了,此时从库和主库间将进行全量复制。

每个从库会记录自己的slave_repl_offset,每个从库的复制进度也不一定相同。

在和主库重连进行恢复时,从库会通过psync命令把自己记录的slave_repl_offset发给主库,主库会根据从库各自的复制进度,来决定这个从库可以进行增量复制,还是全量复制

3:主从复制实际演示

3.1:基本流程
准备好两个redis服务器

在这里插入图片描述

配置修改

分别将端口号改成6001【redis-master】,6002【redis-slave】 -> 配置文件redis.windows.conf

在这里插入图片描述

启动两个服务器

在这里插入图片描述

查看主从状态

输入info replication命令来查看当前的主从状态,可以看到默认的角色为:master,也就是说所有的服务器在启动之后都是主节点的状态。
在这里插入图片描述

主从配置指令

我们希望让6002作为从节点,通过一个命令即可:输入replicaof 127.0.0.1 6001

🎉 每次都去敲个命令配置主从太麻烦了,我们可以直接在配置文件中配置这个命令

命令后,就会将6001服务器作为主节点,而当前节点作为6001的从节点,并且角色也会变成:slave

在这里插入图片描述
在这里插入图片描述
可以看到从节点信息中已经出现了6002服务器,也就是说现在我们的6001和6002就形成了主从关系

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

在这里插入图片描述

3.2:一些说明

⚠️ 从节点压根就没办法进行数据插入,节点的模式为只读模式

在这里插入图片描述
🎉 那么如果我们现在不想让6002作为6001的从节点了呢?

可以在6002执行replicaof no one【我不是别人的从服务器】即可变回到master

在这里插入图片描述

🎉 全量复制和增量复制

接着我们再次让6002变成6001的从节点【或者在创建一个6003作为6001的从节点】

可以看到,在连接之后,也会直接同步主节点的数据,因此无论是已经处于从节点状态还是刚刚启动完成的服务器,都会从主节点同步数据,实际上整个同步流程为:

  1. 从节点执行replicaof ip port命令后,从节点会保存主节点相关的地址信息。
  2. 从节点通过每秒运行的定时任务发现配置了新的主节点后,会尝试与该节点建立网络连接,专门用于接收主节点发送的复制命令。
  3. 连接成功后,第一次会将主节点的数据进行全量复制,之后采用增量复制,持续将新来的写命令同步给从节点

在这里插入图片描述
⚠️ 当我们的主节点关闭后,从节点依然可以读取数据:但是从节点会提示报错信息

在这里插入图片描述
在这里插入图片描述
再次启动后恢复正常

在这里插入图片描述
🎉 除了作为Master节点的从节点外,我们还可以将其作为从节点的从节点

在这里插入图片描述
采用这种方式,优点肯定是显而易见的,但是缺点也很明显,整个传播链路一旦中途出现问题,那么就会导致后面的从节点无法及时同步。

4:读写分离问题

延迟与不一致问题

由于主从复制的命令传播是异步的,延迟与数据的不一致不可避免。

如果应用对数据不一致的接受程度程度较低,可能的优化措施包括:

  • 优化主从节点之间的网络环境(如在同机房部署);
  • 监控主从节点延迟(通过offset)判断,如果从节点延迟过大,通知应用不再通过该从节点读取数据;
  • 使用集群同时扩展写负载和读负载等。

数据过期问题

在单机版Redis中,存在两种删除策略:

  • 惰性删除:服务器不会主动删除数据,只有当客户端查询某个数据时,服务器判断该数据是否过期,如果过期则删除。
  • 定期删除:服务器执行定时任务删除过期数据,但是考虑到内存和CPU的折中

Redis 3.2中,从节点在读取数据时,增加了对数据是否过期的判断:如果该数据已过期,则不返回给客户端;

将Redis升级到3.2+可以解决数据过期问题。

故障切换问题

在没有使用哨兵的读写分离场景下,应用针对读和写分别连接不同的Redis节点;

当主节点或从节点出现问题而发生更改时,需要及时修改应用程序读写Redis数据的连接;

连接的切换可以手动进行,或者自己写监控程序进行切换,但前者响应慢、容易出错,后者实现复杂,成本都不算低

不持久化的主服务器自动重启非常危险

  • 我们设置节点A为主服务器,关闭持久化,节点B和C从节点A复制数据。
  • 这时出现了一个崩溃,但Redis具有自动重启系统,重启了进程,因为关闭了持久化,节点重启后只有一个空的数据集。
  • 节点B和C从节点A进行复制,现在节点A是空的,所以节点B和C上的复制数据也会被删除。

二:哨兵模式

在这里插入图片描述

哨兵作用

  • 监控 -> 哨兵会不断地检查主节点和从节点是否运作正常

  • 故障自动转移 -> 当主节点不能正常工作时,哨兵会开始自动故障转移操作,它会将失效主节点的其中一个从节点升级为新的主节点,并让其他从节点改为复制新的主节点

  • 配置提供者 -> 客户端在初始化时,通过连接哨兵来获得当前Redis服务的主节点地址

  • 通知 -> 哨兵可以将故障转移的结果发送给客户端

监控和自动故障转移功能,使得哨兵可以及时发现主节点故障并完成转移;

而配置提供者和通知功能,则需要在与客户端的交互中才能体现

1:基本工作流程

1.1:哨兵集群组建(消息pub/sub)

哨兵实例之间可以相互发现,要归功于 Redis 提供的 pub/sub 机制,也就是发布 / 订阅机制【消息传递】

🌰 举一个简单的栗子

在主从集群中,主库上有一个名为__sentinel__:hello的频道,不同哨兵就是通过它来相互发现,实现互相通信的。

哨兵 1 把自己的 IP(172.16.19.3)和端口(26579)发布到__sentinel__:hello频道上

哨兵 2 和 3 订阅了该频道。

那么此时,哨兵 2 和 3 就可以从这个频道直接获取哨兵 1 的 IP 地址和端口号。

然后,哨兵 2、3 可以和哨兵 1 建立网络连接。

在这里插入图片描述
通过这个方式,哨兵 2 和 3 也可以建立网络连接,这样一来,哨兵集群就形成了。

它们相互间可以通过网络连接进行通信,比如说对主库有没有下线这件事儿进行判断和协商。

1.2:下线判断(客观下线)

首先要理解两个概念:主观下线和客观下线

  • 主观下线:任何一个哨兵都是可以监控探测,并作出Redis节点下线的判断;
  • 客观下线:有哨兵集群共同决定Redis节点是否下线;

当某个哨兵(如下图中的哨兵2)判断主库“主观下线”后,就会给其他哨兵发送 is-master-down-by-addr 命令。

接着,其他哨兵会根据自己和主库的连接情况,做出 Y 或 N 的响应,Y 相当于赞成票,N 相当于反对票

在这里插入图片描述
如果赞成票数是大于等于哨兵配置文件中的 quorum 配置项(比如这里如果是quorum=2), 则可以判定主库客观下线了

1.3:主哨兵选举(raft半数通过)

判断完主库下线后,由哪个哨兵节点来执行主从切换呢?

为什么需要哨兵的选举

为了避免单节点哨兵的存在,就需要哨兵集群,而集群的出现表示必然要面临共识问题【选举问题】

故障转移和通知都由主哨兵节点进行负责即可。

哨兵的选举是怎样的

哨兵的选举,遵循的是著名的raft算法:

当投票数 r >= num / 2 + 1 就进行当选

如何成为leader哨兵节点

  • 第一,拿到半数以上的赞成票
  • 第二,拿到的票数同时还需要大于等于哨兵配置文件中的 quorum 值

以 3 个哨兵为例,假设此时的 quorum 设置为 2,那么,任何一个想成为 Leader 的哨兵只要拿到 2 张赞成票,就可以了。

1.4:新主库的选出(健康,完整的)
  • 过滤掉不健康的(下线或断线),没有回复过哨兵ping响应的从节点
  • 选择salve-priority从节点优先级最高(redis.conf)的
  • 选择复制偏移量最大,指复制最完整的从节点

在这里插入图片描述

1.5:故障转移(易主通知复制)

假设现在有这样的情况:主库节点已经客观下线了,哨兵节点3被选为了哨兵leader,并且决定新的主库为从节点slave_1

在这里插入图片描述

故障转移的流程

  1. 将slave-1脱离原从节点(5.0 中应该是replicaof no one),升级主节点,
  2. 将从节点slave-2指向新的主节点
  3. 通知客户端主节点已更换
  4. 将原主节点(oldMaster)变成从节点,指向新的主节点

在这里插入图片描述

转移之后

在这里插入图片描述

2:哨兵模式实际演示

2.1:基本流程

在这里插入图片描述

创建哨兵服务器

在这里插入图片描述

修改哨兵服务器的配置文件
# 其他的全部都删除掉,只写这一行
# 	其中第一个和第二个参数是固定的
# 	第三个参数是为监控对象名称,随意
# 第四个,第五个参数就是主节点的相关信息,包括IP地址和端口
# 最后一个参数是哨兵支持数大于等于多少sentinel monitor cuihaida-sentinel 127.0.0.1 6001 1
启动哨兵服务器

在这里插入图片描述
可以看到以哨兵模式启动后,会自动监控主节点,然后还会显示那些节点是作为从节点存在的。

主节点挂掉测试

一开始从节点还在常规报错,因为会认为主节点只是网络卡顿了,没必要急着切换主节点

在这里插入图片描述
但是一段时间之后,哨兵发现还是连接不上主节点,便开始重新选主

在这里插入图片描述
6003已经成为新的主节点

在这里插入图片描述
再次启动6001之后,发现他已经变成了6003的从节点

在这里插入图片描述
那么,这个选举规则是怎样的呢?是在所有的从节点中随机选取还是遵循某种规则呢?

  1. 首先会根据优先级进行选择,可以在配置文件中进行配置,添加replica-priority配置项(默认是100),越小表示优先级越高。
  2. 如果优先级一样,那就选择偏移量最大的
  3. 要是还选不出来,那就选择runid(启动时随机生成的)最小的。
要是哨兵也挂了咋办?

咱们可以多安排几个哨兵,只需要把哨兵的配置复制一下,然后修改端口,这样就可以同时启动多个哨兵了,我们启动3个哨兵(一主二从三哨兵),这里我们吧最后一个值改为2

sentinel monitor cuihaida 192.168.0.8 6001 2

这个值实际上代表的是当有几个哨兵认为主节点挂掉时,就判断主节点真的挂掉了

2.2:Jedis感知

在哨兵重新选举新的主节点之后,我们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) {try {//这里我们直接使用JedisSentinelPool来获取Master节点//需要把三个哨兵的地址都填入JedisSentinelPool pool = new JedisSentinelPool("cuihaida", new HashSet<>(Arrays.asList("192.168.0.8:26741", "192.168.0.8:26740", "192.168.0.8: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();}}
}

一:集群

1:集群的引入

如果我们服务器的内存不够用了,但是现在我们的Redis又需要继续存储内容,那么这个时候就可以利用集群来实现扩容。

因为单机的内存容量最大就那么多,已经没办法再继续扩展了,但是现在又需要存储更多的内容

这时我们就可以让N台机器上的Redis来分别存储各个部分的数据(每个Redis可以存储1/N的数据量),这样就实现了容量的横向扩展。

同时每台Redis还可以配一个从节点,这样就可以更好地保证数据的安全性。

在这里插入图片描述
那么问题来,现在用户来了一个写入的请求,数据该写到哪个节点上呢?

首先,一个Redis集群包含16384个插槽,集群中的每个Redis 实例负责维护一部分插槽以及插槽所映射的键值数据,那么这个插槽是什么意思呢?

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

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

结果的值是多少,就应该存放到对应维护的Redis下

比如Redis节点1负责0-25565的插槽,而这时客户端插入了一个新的数据a=10,a在Hash计算后结果为666,那么a就应该存放到1号Redis节点中。

简而言之,本质上就是通过哈希算法将插入的数据分摊到各个节点的,所以说哈希算法真的是处处都有用啊。

主从复制和哨兵机制保障了高可用,就读写分离而言虽然slave节点扩展了主从的读并发能力,但是写能力和存储能力是无法进行扩展,就只能是master节点能够承载的上限。

如果面对海量数据那么必然需要构建master(主节点分片)之间的集群,同时必然需要吸收高可用(主从复制和哨兵机制)能力,即每个master分片节点还需要有slave节点,这是分布式系统中典型的纵向扩展(集群的分片技术)的体现

所以在Redis 3.0版本中对应的设计就是Redis Cluster

在这里插入图片描述

2:设计目标

高性能可线性扩展至最多1000节点。集群中没有代理,(集群节点间)使用异步复制,没有归并操作

3:常用概念

3.1:哈希槽 hash_slot

redis分片没有使用一致性hash,而是采用了hash槽的概念,redis分片中有16284(214)个hash槽

每一个key通过校验之后对16284 mod决定放到那个槽里。分片中的每一个节点负责一部分槽。

比如集群中存在三个节点,则可能存在的一种分配如下:

  • 节点A包含0到5500号哈希槽;
  • 节点B包含5501到11000号哈希槽;
  • 节点C包含11001到16384号哈希槽。
3.2:hash_tags

hash_tags提供了一种策略,用来将多个(相关的)key分配到相同的hash槽中,这是实现muitl_key的基础。

hash_tags规则如下,如果满足如下规则,{和}之间的字符将用来计算hash槽,以保证这样的key保存在同一个slot中

  • key包含一个{字符
  • 并且 如果在这个{的右面有一个}字符
  • 并且 如果在{和}之间存在至少一个字符
--------- 举几个例子 ----------
{user1000}.following和{user1000}.followers这两个key会被hash到相同的hash slot中,因为只有user1000会被用来计算hash slot值。 foo{}{bar}这个key不会启用hash tag因为第一个{和}之间没有字符。 foozap这个key中的{bar部分会被用来计算hash slot foo{bar}{zap}这个key中的bar会被用来计算计算hash slot,而zap不会
分片nodes属性

每一个节点在分片中有唯一的名字

节点在配置文件中保存它的id,并且永久的使用这个id,直到被管理员使用CLUSTER RESET HARD命令重置节点。

节点id被用来在整个分集群中标识每个节点。一个节点可以修改自己的IP地址而不需要修改自己的id

节点ID不是唯一与节点绑定的信息,但是他是唯一的一个总是保持全局一致的字段。

3.3:集群总线

每个集群节点有一个额外的TCP端口用来接受其他节点的连接。

这个端口与用来接收client命令的普通TCP端口有一个固定的offset。该端口等于普通命令端口加上10000。

例如,一个Redis在端口6379和客户端连接,那么它的集群总线端口16379也会被打开。

节点到节点的通讯只使用集群总线,同时使用集群总线协议:有不同的类型和大小的帧组成的二进制协议。

在这里插入图片描述

集群拓扑

redis集群是一张全网拓扑,节点与其他每个节点之间都保持着TCP连接。

在一个拥有N个节点的集群中,每个节点由N-1个TCP传出连接,和N-1个TCP传入连接。 这些TCP连接总是保持活性。

当一个节点在集群总线上发送了ping请求并期待对方回复pong,(如果没有得到回复)在等待足够成时间以便将对方标记为不可达之前,它将先尝试重新连接对方以刷新与对方的连接。

而在全网拓扑中的redis集群节点,节点使用gossip协议和配置更新机制来避免在正常情况下节点之间交换过多的消息,因此集群内交换的消息数目(相对节点数目)不是指数级的。

节点握手

节点总是接受集群总线端口的链接,并且总是会回复ping请求,即使ping来自一个不可信节点。

然而,如果发送节点被认为不是当前集群的一部分,所有其他包将被抛弃

节点认定其他节点是当前集群的一部分有两种方式:

  • 如果一个节点出现在了一条MEET消息中。一条MEET消息非常像一个ping消息,但是它会强制接收者接受一个节点作为集群的一部分。节点只有在接收到系统管理员的如下命令后,才会向其他节点发送MEET消息
cluster meet ip port
  • 如果一个被信任的节点gossip了某个节点,那么接收到gossip消息的节点也会那个节点标记为集群的一部分。也就是说,如果在集群中,A知道B,而B知道C,最终B会发送gossip消息到A,告诉A节点C是集群的一部分。这时,A会把C注册未网络的一部分,并尝试与C建立连接。

🔉一旦我们把某个节点加入了连接图,它们最终会自动形成一张全连接图。这意味着只要系统管理员强制加入了一条信任关系(在某个节点上通过meet命令加入了一个新节点),集群可以自动发现其他节点

4:搭建实例

4.1:基本流程
创建六个redis服务器

在这里插入图片描述

配置修改

修改三个节点的配置【主节点端口:6001, 6002, 6003】【从节点端口:7001,7002,7003】

  • bind 127.0.0.1注释掉【56行】
  • 保护模式关闭protected-mode no【75行】
  • 设置端口【79行】
  • cluster-enabled yes解开注释 【707行】

🎉 改好一份复制redis.windows.conf到其他的服务器,然后其他的服务器只需要改端口就可以了

全部启动

⚠️ 要是起不来了,把所有的持久化文件全部删除,所有的节点内容必须是空的。

在这里插入图片描述

主从集群分配

然后输入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即可:

在这里插入图片描述
分配成功,可以看到插槽的分配情况

在这里插入图片描述

5:测试

随便连接一个节点,尝试插入一个值:

在这里插入图片描述
在插入时,出现了一个错误,实际上这就是因为a计算出来的哈希值(插槽),不归当前节点管,我们得去管这个插槽的节点执行

通过上面的分配情况,我们可以得到15495号插槽属于节点6003管理:

在这里插入图片描述

6:集群方式连接

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

在这里插入图片描述
可以看到,在6001节点成功对a的值进行了更新,只不过还是被重定向到了6003节点进行插入

4.2:其他说明
节点信息

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

在这里插入图片描述

让某一个主节点挂掉会怎么样?

现在我们把6001挂掉,可以看到原本的6001从节点7001,晋升为了新的主节点,而之前的6001已经挂了

在这里插入图片描述
现在我们将6001重启,可以看到6001变成了7001的从节点

在这里插入图片描述

主从都挂了怎么办?

要是6001和7001都挂了

在这里插入图片描述
我们尝试插入新的数据,可以看到,当存在节点不可用时,会无法插入新的数据

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

相关文章:

Redis03 - 高可用

Redis高可用 文章目录 Redis高可用一&#xff1a;主从复制 & 读写分离1&#xff1a;主从复制的作用2&#xff1a;主从复制原理2.1&#xff1a;全量复制2.2&#xff1a;增量复制&#xff08;环形缓冲区&#xff09; 3&#xff1a;主从复制实际演示3.1&#xff1a;基本流程准…...

日常知识点之面试后反思遗留问题汇总

梳理一下最近接触到的几个知识点&#xff1a; 1&#xff1a;突然问到端口复用 &#xff08;SO_REUSEADDR&#xff09; 端口复用一般用在服务端重启时&#xff0c;套接字处于time_wait状态时&#xff0c;无法绑定该端口&#xff0c;导致无法启动问题。 设置端口复用&#xff…...

软考教材重点内容 信息安全工程师 第15章 网络安全主动防御技术与应用

目录 15.1.1 人侵阻断技术原理 15.1.2 人侵阻断技术应用 15.3 网络流量清洗技术与应用 15.3.1 网络流量清洗技术原理 15.3.2 网络流量清洗技术应用 15.4 可信计算技术与应用 15.4.1 可信计算技术原理 15.5 数字水印技术与应用 15.5.1 数字水印技术原理 15.5.2 数字水…...

大模型的底层逻辑及Transformer架构

一、大模型的底层逻辑 1.数据驱动 大模型依赖海量的数据进行训练,数据的质量和数量直接影响模型的性能。通过大量的数据,模型能够学习到丰富的模式和规律,从而更好地处理各种任务。 2.深度学习架构 大模型基于深度学习技术,通常采用多层神经网络进行特征学习与抽象。其中…...

PostgreSQL-字符串函数

字符串连接 SELECT A||B; 字符串连接&#xff0c;适用于字符串与数字连接 SELECT CONCAT(10,a,hello,20.0); 连接所有参数&#xff0c;个数不限&#xff0c;类型不限 字母转换 SELECT LOWER(ABCD); 将字符转换成小写 SELECT UPPER(ABCD); 将字符转换成大写 SELECT IN…...

Qt修仙之路2-1 炼丹初成

widget.cpp #include "widget.h" #include<QDebug> //实现槽函数 void Widget::login1() {QString userusername_input->text();QString passpassword_input->text();//如果不勾选无法登入if(!check->isChecked()){qDebug()<<"xxx"&…...

华为的IPD模式VS敏捷项目管理模式

本文介绍了华为的IPD模式与敏捷项目管理模式的对比。文章详细阐述了两种模式的特点、适用范围及实施要点&#xff0c;为读者提供了全面的理解。 重点内容&#xff1a; 1. IPD模式强调跨部门协同&#xff0c;注重产品全生命周期管理&#xff0c;适用于复杂产品领域。 2. 敏捷…...

Ollama python交互:chat+embedding实践

Ollama简介 Ollama 是一个开源的大型语言模型&#xff08;LLM&#xff09;平台&#xff0c;旨在让用户能够轻松地在本地运行、管理和与大型语言模型进行交互。 Ollama 提供了一个简单的方式来加载和使用各种预训练的语言模型&#xff0c;支持文本生成、翻译、代码编写、问答等…...

Redis进阶

Redis持久化&#xff1a; 前面我们讲到mysql事务有四个比较核心的特性&#xff1a; 原子性&#xff1a;保证多个操作打包成一个。一致性&#xff1a;A给B100&#xff0c;A少一百&#xff0c;B必须多一百。持久性&#xff1a;针对事务操作必须要持久生效&#xff0c;不管是重启…...

【蓝桥杯嵌入式】6_定时器输入捕获

全部代码网盘自取 链接&#xff1a;https://pan.baidu.com/s/1PX2NCQxnADxYBQx5CsOgPA?pwd3ii2 提取码&#xff1a;3ii2 这是两个信号发生器&#xff0c;可以通过调节板上的两个电位器R39和R40调节输出频率。 将PB4、PA15选择ch1&#xff0c;两个信号发生器只能选择TIM3和TIM…...

C#常用集合优缺点对比

先上结论&#xff1a; 在C#中&#xff0c;链表、一维数组、字典、List<T>和ArrayList是常见的数据集合类型&#xff0c;它们各有优缺点&#xff0c;适用于不同的场景。以下是它们的比较&#xff1a; 1. 一维数组 (T[]) 优点&#xff1a; 性能高&#xff1a;数组在内存中…...

Python调取本地MongoDB招投标数据库,并结合Ollama部署的DeepSeek-R1-8B模型来制作招投标垂直领域模型

根据你的需求&#xff0c;以下是使用Python调取本地MongoDB招投标数据库&#xff0c;并结合Ollama部署的DeepSeek-R1-8B模型来制作招投标垂直领域模型的步骤&#xff1a; 安装PyMongo 首先&#xff0c;确保你已经安装了PyMongo库&#xff0c;用于Python与MongoDB的交互。如果未…...

【MySQL】深入了解索引背后的内部结构

目录 索引的认识&#xff1a; 作用&#xff1a; 索引的使用&#xff1a; 索引底层的数据结构&#xff1a; 哈希表 AVL树 红黑树 B树&#xff1a; B树&#xff1a; B树搜索&#xff1a; 索引的认识&#xff1a; 索引是数据库中的一个数据结构&#xff0c;用于加速查询…...

pytest-xdist 进行多进程并发测试

在自动化测试中&#xff0c;运行时间过长往往是令人头疼的问题。你是否遇到过执行 Pytest 测试用例时&#xff0c;整个测试流程缓慢得让人抓狂&#xff1f;别担心&#xff0c;pytest-xdist 正是解决这一问题的利器&#xff01;它支持多进程并发执行&#xff0c;能够显著加快测试…...

蓝桥杯准备 【入门3】循环结构

素数小算法&#xff08;埃氏筛&&欧拉筛&#xff09; 以下四段代码都是求20以内的所有素数 1.0版求素数 #include<iostream> using namespace std;int main() {int n 20;for(int i2;i<n;i){int j0;for(j2;j<i;j)//遍历i{if(i%j0){break;}}if(ij){cout&l…...

PHP填表统计预约打卡表单系统小程序

&#x1f4cb; 填表统计预约打卡表单系统——专属定制&#xff0c;信息互动新纪元 &#x1f4ca; 填表统计预约打卡表单系统&#xff0c;一款专为现代快节奏生活量身打造的多元化自定义表单统计小程序&#xff0c;集信息填表、预约报名、签到打卡、活动通知、报名投票、班级统…...

自定义数据集,使用scikit-learn 中K均值包 进行聚类

1. 引言 K均值聚类是一种无监督学习方法&#xff0c;用于将数据集分为多个簇。通过计算数据点之间的距离并将它们分配到最近的簇中心&#xff0c;K均值算法可以帮助我们发现数据中的自然结构。 2. 数据集创建 首先&#xff0c;我们使用numpy创建一个自定义的二维数据集&…...

Lua中文语言编程源码-第十一节,其它小改动汉化过程

__tostring 汉化过程 liolib.c metameth[] {"__转换为字符串", f_tostring}, lauxlib.c luaL_callmeta(L, idx, "__转换为字符串") lua.c luaL_callmeta(L, 1, "__转换为字符串") __len 汉化过程 ltm.c luaT_eventname[] ltablib.c c…...

Android studio 创建aar包给Unity使用

1、aar 是什么&#xff1f; 和 Jar有什么区别 aar 和 jar包 都是压缩包&#xff0c;可以使用压缩软件打开 jar包 用于封装 Java 类及其相关资源 aar 文件是专门为 Android 平台设计的 &#xff0c;可以包含Android的专有内容&#xff0c;比如AndroidManifest.xml 文件 &#…...

4. 【.NET 8 实战--孢子记账--从单体到微服务--转向微服务】--什么是微服务--微服务设计原则与最佳实践

相比传统的单体应用&#xff0c;微服务架构通过将大型系统拆分成多个独立的小服务&#xff0c;不仅提升了系统的灵活性和扩展性&#xff0c;也带来了许多设计和运维上的挑战。如何在设计和实现微服务的过程中遵循一系列原则和最佳实践&#xff0c;从而构建一个稳定、高效、易维…...

大语言模型遇上自动驾驶:AsyncDriver如何巧妙解决推理瓶颈?

导读 这篇论文提出了AsyncDriver框架&#xff0c;致力于解决大语言模型在自动驾驶领域应用中的关键挑战。论文的主要创新点在于提出了大语言模型和实时规划器的异步推理机制&#xff0c;实现了在保持性能的同时显著降低计算开销。通过设计场景关联指令特征提取模块和自适应注入…...

第17章 读写锁分离设计模式(Java高并发编程详解:多线程与系统设计)

1.场景描述 对资源的访问一般包括两种类型的动作——读和写(更新、删除、增加等资源会发生变化的动作)&#xff0c;如果多个线程在某个时刻都在进行资源的读操作&#xff0c;虽然有资源的竞争&#xff0c;但是这种竞争不足以引起数据不一致的情况发生&#xff0c;那么这个时候…...

硬盘修复后,文件隐身之谜

在数字时代&#xff0c;硬盘作为数据存储的重要载体&#xff0c;承载着无数珍贵的信息与回忆。然而&#xff0c;当硬盘遭遇故障并经过修复后&#xff0c;有时我们会遇到这样一个棘手问题&#xff1a;硬盘修复后&#xff0c;文件却神秘地“隐身”&#xff0c;无法正常显示。这一…...

Ollama+ page Assist或Ollama+AnythingLLM 搭建本地知识库

参考&#xff1a;【AI】10分钟学会如何用RAG投喂数据给你的deepseek本地模型&#xff1f;_哔哩哔哩_bilibili 方法一&#xff1a;Ollama page Assist 本地知识库 ***下方操作比较精简&#xff0c;详情参考&#xff1a;Ollama 部署本地大语言模型-CSDN博客 1.下载Ollama 2.O…...

树莓派5添加摄像头 在C++下调用opencv

由于树莓派5 os系统升级,正常libcamera创建对象每次失败。 改如下方法成功。 1 创建管道 rpicam-vid -t 0 --codec mjpeg -o udp://127.0.0.1:8554 > /dev/null 2>&1 2 opencv从管道里读取 #include <opencv2/opencv.hpp> #include <iostream>int mai…...

redis之RDB持久化过程

redis的rdb持久化过程 流程图就想表达两点&#xff1a; 1.主进程会fork一个子进程&#xff0c;子进程共享主进程内存数据(fork其实是复制页表)&#xff0c;子进程读取数据并写到新的rdb文件&#xff0c;最后替换旧的rdb文件。 2.在持久化过程中主进程接收到用户写操作&#x…...

Linux后台运行进程

linux 后台运行进程&#xff1a;& , nohup-腾讯云开发者社区-腾讯云 进程 &&#xff0c;后台运行&#xff0c;结束终端退出时结束进程。 nohup 进程 &&#xff0c;后台运行&#xff0c;结束终端后依然保持运行。...

webpack配置方式

1. 基本配置文件 (webpack.config.js)&#xff08;导出一个对象&#xff09; 最常见的方式是通过 webpack.config.js 文件来配置 Webpack&#xff0c;导出一个对象。你可以在这个文件中导出一个配置对象&#xff0c;指定入口、输出、加载器、插件等。 // webpack.config.js m…...

123,【7】 buuctf web [极客大挑战 2019]Secret File

进入靶场 太熟悉了&#xff0c;有种回家的感觉 查看源代码&#xff0c;发现一个紫色文件 点下看看 点secret 信息被隐藏了 要么源代码&#xff0c;要么抓包 源代码没有&#xff0c;抓包 自己点击时只能看到1和3处的文件&#xff0c;点击1后直接跳转3&#xff0c;根本不出…...

OSPF基础(2):数据包详解

OSPF数据包(可抓包) OSPF报文直接封装在IP报文中&#xff0c;协议号89 头部数据包内容&#xff1a; 版本(Version):对于OSPFv2&#xff0c;该字段值恒为2(使用在IPV4中)&#xff1b;对于OSPFv3&#xff0c;该字段值恒为3(使用在IPV6中)。类型(Message Type):该OSPF报文的类型。…...

Vue 入门到实战 八

第8章 组合API与响应性 目录 8.1 响应性 8.1.1 什么是响应性 8.1.2 响应性原理 8.2 为什么使用组合API 8.3 setup组件选项 8.3.1 setup函数的参数 8.3.2 setup函数的返回值 8.3.3 使用ref创建响应式引用 8.3.4 setup内部调用生命周期钩子函数 8.4 提供/注入 8.4.1 …...

【学习总结|DAY036】Vue工程化+ElementPlus

引言 在前端开发领域&#xff0c;Vue 作为一款流行的 JavaScript 框架&#xff0c;结合 ElementPlus 组件库&#xff0c;为开发者提供了强大的构建用户界面的能力。本文将结合学习内容&#xff0c;详细介绍 Vue 工程化开发流程以及 ElementPlus 的使用&#xff0c;助力开发者快…...

HTML之CSS三大选择器

HTML之CSS三大选择器 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title><st…...

理解链接:加载二进制动态库

理解链接&#xff1a;加载二进制动态库 文章目录 理解链接&#xff1a;加载二进制动态库前情提要基本方式1 - 显式连接 dlopen基本方式 2 - 隐式链接 compile link ld衍生方式 3 - 弱链接 weak linking衍生方式 4 - dlmopen 加载到独立命名空间调试所有符号 补充知识1. 动态库…...

ASP.NET Core中Filter与Middleware的区别

中间件是ASP.NET Core这个基础提供的功能&#xff0c;而Filter是ASP.NET Core MVC中提供的功能。ASP.NET Core MVC是由MVC中间件提供的框架&#xff0c;而Filter属于MVC中间件提供的功能。 区别 中间件可以处理所有的请求&#xff0c;而Filter只能处理对控制器的请求&#x…...

《语义捕捉全解析:从“我爱自然语言处理”到嵌入向量的全过程》

首先讲在前面&#xff0c;介绍一些背景 RAG&#xff08;Retrieval-Augmented Generation&#xff0c;检索增强生成&#xff09; 是一种结合了信息检索与语言生成模型的技术&#xff0c;通过从外部知识库中检索相关信息&#xff0c;并将其作为提示输入给大型语言模型&#xff…...

大规模多准则决策模型构建详细方案

第二阶段&#xff1a;大规模多准则决策模型构建详细方案 目标 基于消费者群体偏好和个体交互数据&#xff0c;构建动态、可扩展的多准则决策模型&#xff0c;实现实时个性化产品排序。 一、技术架构设计 1. 系统架构图 [用户交互层] → (React前端) ↓ [API服务层] → (…...

Rust 语言:变革关键任务软件的新力量

软件无处不在&#xff0c;从手表、烤箱、汽车&#xff0c;甚至可能是牙刷中都有它的身影。更重要的是&#xff0c;软件控制着关乎生死的系统&#xff0c;如飞机、医疗设备、电网系统和银行基础设施等。如果软件工程师稍有疏忽&#xff0c;软件缺陷和漏洞可能导致数十亿美元的损…...

Linux特权组全解析:识别GID带来的权限提升风险

组ID&#xff08;Group ID&#xff0c;简称 GID&#xff09;是Linux系统中用来标识不同用户组的唯一数字标识符。每个用户组都有一个对应的 GID&#xff0c;通过 GID&#xff0c;系统能够区分并管理不同的用户组。 在Linux系统中&#xff0c;系统用户和组的配置文件通常包括以…...

安卓/ios脚本开发按键精灵经验小分享

1. 程序的切换 我们经常碰到这样的需求&#xff1a;打开最近的应用列表&#xff0c;选取我们想要的程序。但是每个手机为了自己的风格&#xff0c;样式都有区别&#xff0c;甚至连列表的滑动方向都不一样&#xff0c;我们很难通过模拟操作来识别点击&#xff0c;那么我们做的只…...

机器学习在癌症分子亚型分类中的应用

学习笔记&#xff1a;机器学习在癌症分子亚型分类中的应用——Cancer Cell 研究解析 1. 文章基本信息 标题&#xff1a;Classification of non-TCGA cancer samples to TCGA molecular subtypes using machine learning发表期刊&#xff1a;Cancer Cell发表时间&#xff1a;20…...

DeepSeek本地部署保姆级教程

由于DeepSeek近期遭受攻击&#xff0c;又加上用户访问量较大&#xff0c;导致总是服务不可用&#xff0c;让人十分窝火。有没有好的解决办法呢&#xff1f;答案是自己在电脑端部署一套&#xff0c;这样就不用和别人抢着用了。另外本地部署的好处还有保护隐私与减少延迟。 如果…...

无惧户外复杂环境,安科瑞 AKH-0.66/K-HW 开口式互感器准确测流

​安科瑞 吕梦怡 18706162527 1.产品特点 AKH-0.66/K-HW 系列互感器具有防水功能&#xff0c;可在户外使用&#xff0c;切面端口采用橡胶垫环绕可有效阻止雨水进入。互感器采用注塑技术&#xff0c;将互感器线圈直接在模具中进行注塑&#xff0c;同时二次侧引线采用防水端子…...

玩转Docker | 使用Docker部署httpd服务

玩转Docker | 使用Docker部署httpd服务 前言一、准备工作环境确认检查操作系统准备网站目录和配置文件二、拉取httpd镜像三、运行httpd容器运行容器命令检查容器状态四、验证httpd服务浏览器访问测试错误排查五、容器管理与维护查看容器状态停止和启动容器更新网站内容和配置六…...

MacOS 安装NVM

MacOS 安装NVM 方法一&#xff1a;使用Homebrew安装nvm 打开终端&#xff08;Terminal&#xff09;&#xff0c;输入以下命令安装Homebrew&#xff1a; /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"安装nvm…...

Qt 数据库SQLite 使用【01】基本功能

1.开发背景 Qt 开发过程中难免需要存储数据&#xff0c;可以选择保存到本地文件&#xff0c;但是查找比较麻烦&#xff0c;所以就有了数据库&#xff0c;主要是方便查找数据&#xff0c;增删改查等操作&#xff0c;而 SqLite 属于数据库中轻量级的存在&#xff0c;适合本地数据…...

http状态码:请说说 503 Service Unavailable(服务不可用)的原因以及排查问题的思路

503 Service Unavailable&#xff08;服务不可用&#xff09; 是一种HTTP状态码&#xff0c;表示服务器当前无法处理请求&#xff0c;通常是由于临时性原因导致服务中断。以下是它的常见原因和排查思路&#xff1a; 一、503错误的常见原因 1. 服务器过载 场景&#xff1a;服务…...

58页PPT学习华为面向业务价值的数据治理实践

目录 1. 正文解读... 1 2. 华为数据质量管控的质量度量框架是怎样的?... 2 3. 如何在企业中实施类似华为的数据质量管控...

电脑开机提示按f1原因分析及终极解决方法来了

经常有网友问到一个问题&#xff0c;我电脑开机后提示按f1怎么解决&#xff1f;不管理是台式电脑&#xff0c;还是笔记本&#xff0c;都有可能会遇到开机需要按F1&#xff0c;才能进入系统的问题&#xff0c;引起这个问题的原因比较多&#xff0c;今天小编在这里给大家列举了比…...

DeepSeek模型构建与训练

在完成数据预处理之后,下一步就是构建和训练深度学习模型。DeepSeek提供了简洁而强大的API,使得模型构建和训练变得非常直观。无论是简单的全连接网络,还是复杂的卷积神经网络(CNN)或循环神经网络(RNN),DeepSeek都能轻松应对。本文将带你一步步构建一个深度学习模型,并…...