Java高级架构师-分布式Redis深度历险-Cluster

SpringMVC面试题:什么是Servlet? 一、什么是servlet? servlet是一个Java编写的程序,此程序是基于http协议的,在服务器端(如Tomcat)运行的,是按照servlet规范编写的一个Java类。 客户端发送请求至服务器端,服务器端将请求发送至servlet,servlet生成响应内容并将其传给服务器 即,我们在浏览器点击链接和按钮产生的消息不是发送给servlet的,而是发送给web容器(如Tomcat、jet... 阅读详情

集群基础实现

一个集群由多个Redis节点组成,不同的节点通过CLUSTER MEET命令进行连接:

CLUSTER MEET <ip> <port>

收到命令的节点会与命令中指定的目标节点进行握手,握手成功后目标节点会加入到集群中,看个例子,图片来自于Redis的设计与实现:

Java高级架构师-分布式Redis深度历险-Cluster

 

Java高级架构师-分布式Redis深度历险-Cluster

 

Java高级架构师-分布式Redis深度历险-Cluster

 

Java高级架构师-分布式Redis深度历险-Cluster

 

Java高级架构师-分布式Redis深度历险-Cluster

 

 

槽分配

一个集群的所有数据被分为16384个槽,可以通过CLUSTER ADDSLOTS命令将槽指派给对应的节点。当所有的槽都有节点负责时,集群处于上线状态,否则处于下线状态不对外提供服务。

clusterNode的位数组slots代表一个节点负责的槽信息。

struct clusterNode {
 unsigned char slots[16384/8]; /* slots handled by this node */
 int numslots; /* Number of slots handled by this node */
 ...
}

看个例子,下图中1、3、5、8、9、10位的值为1,代表该节点负责槽1、3、5、8、9、10。

每个Redis Server上都有一个ClusterState的对象,代表了该Server所在集群的信息,其中字段slots记录了集群中所有节点负责的槽信息。

typedef struct clusterState {
 // 负责处理各个槽的节点
 // 例如 slots[i] = clusterNode_A 表示槽 i 由节点 A 处理
 // slots[i] = null 代表该槽目前没有节点负责
 clusterNode *slots[REDIS_CLUSTER_SLOTS];
}

 

槽重分配

可以通过redis-trib工具对槽重新分配,重分配的实现步骤如下:

  1. 通知目标节点准备好接收槽
  2. 通知源节点准备好发送槽
  3. 向源节点发送命令:CLUSTER GETKEYSINSLOT <slot> <count>从源节点获取最多count个槽slot的key
  4. 对于步骤3的每个key,都向源节点发送一个MIGRATE <target_ip> <target_port> <key_name> 0 <timeout> 命令,将被选中的键原子的从源节点迁移至目标节点。
  5. 重复步骤3、4。直到槽slot的所有键值对都被迁移到目标节点
  6. 将槽slot指派给目标节点的信息发送到整个集群。

在槽重分配的过程中,槽中的一部分数据保存着源节点,另一部分保存在目标节点。这时如果要客户端向源节点发送一个命令,且相关数据在一个正在迁移槽中,源节点处理步骤如图:

Java高级架构师-分布式Redis深度历险-Cluster

 

当客户端收到一个ASK错误的时候,会根据返回的信息向目标节点重新发起一次请求。

ASK和MOVED的区别主要是ASK是一次性的,MOVED是永久性的,有点像Http协议中的301和302。

 

一次命令执行过程

我们来看cluster下一次命令的请求过程,假设执行命令 get testKey

  1. cluster client在运行前需要配置若干个server节点的ip和port。我们称这些节点为种子节点。
  2. cluster的客户端在执行命令时,会先通过计算得到key的槽信息,计算规则为:getCRC16(key) & (16384 - 1),得到槽信息后,会从一个缓存map中获得槽对应的redis server信息,如果能获取到,则调到第4步
  3. 向种子节点发送slots命令以获得整个集群的槽分布信息,然后跳转到第2步重试命令
  4. 向负责该槽的server发起调用

server处理如图:

Java高级架构师-分布式Redis深度历险-Cluster

 

5.客户端如果收到MOVED错误,则根据对应的地址跳转到第4步重新请求,

6.客户段如果收到ASK错误,则根据对应的地址跳转到第4步重新请求,并在请求前带上ASKING标识。

以上步骤大致就是redis cluster下一次命令请求的过程,但忽略了一个细节,如果要查找的数据锁所在的槽正在重分配怎么办?

 

Redis故障转移

疑似下线与已下线

集群中每个Redis节点都会定期的向集群中的其他节点发送PING消息,如果目标节点没有在有效时间内回复PONG消息,则会被标记为疑似下线。同时将该信息发送给其他节点。当一个集群中有半数负责处理槽的主节点都将某个节点A标记为疑似下线后,那么A会被标记为已下线,将A标记为已下线的节点会将该信息发送给其他节点。

比如说有A,B,C,D,E 5个主节点。E有F、G两个从节点。

当E节点发生异常后,其他节点发送给A的PING消息将不能得到正常回复。当过了最大超时时间后,假设A,B先将E标记为疑似下线;之后C也会将E标记为疑似下线,这时C发现集群中由3个节点(A、B、C)都将E标记为疑似下线,超过集群复制槽的主节点个数的一半(>2.5)则会将E标记为已下线,并向集群广播E下线的消息。

 

选取新的主节点

当F、G(E的从节点)收到E被标记已下线的消息后,会根据Raft算法选举出一个新的主节点,新的主节点会将E复制的所有槽指派给自己,然后向集群广播消息,通知其他节点新的主节点信息。

选举新的主节点算法与选举Sentinel头节点的过程很像:

  1. 集群的配置纪元是一个自增计数器,它的初始值为0.
  2. 当集群里的某个节点开始一次故障转移操作时,集群配置纪元的值会被增一。
  3. 对于每个配置纪元,集群里每个负责处理槽的主节点都有一次投票的机会,而第一个向主节点要求投票的从节点将获得主节点的投票。
  4. 档从节点发现自己正在复制的主节点进入已下线状态时,从节点会想集群广播一条CLUSTER_TYPE_FAILOVER_AUTH_REQUEST消息,要求所有接收到这条消息、并且具有投票权的主节点向这个从节点投票。
  5. 如果一个主节点具有投票权(它正在负责处理槽),并且这个主节点尚未投票给其他从节点,那么主节点将向要求投票的从节点返回一条CLUSTERMSG_TYPE_FAILOVER_AUTH_ACK消息,表示这个主节点支持从节点成为新的主节点。
  6. 每个参与选举的从节点都会接收CLUSTERMSG_TYPE_FAILOVER_AUTH_ACK消息,并根据自己收到了多少条这种消息来同济自己获得了多少主节点的支持。
  7. 如果集群里有N个具有投票权的主节点,那么当一个从节点收集到大于等于N/2+1张支持票时,这个从节点就会当选为新的主节点。
  8. 因为在每一个配置纪元里面,每个具有投票权的主节点只能投一次票,所以如果有N个主节点进行投票,那么具有大于等于N/2+1张支持票的从节点只会有一个,这确保了新的主节点只会有一个。
  9. 如果在一个配置纪元里面没有从节点能收集到足够多的支持票,那么集群进入一个新的配置纪元,并再次进行选举,知道选出新的主节点为止。

 

Redis常用分布式实现方案

最后,聊聊redis集群的其他两种实现方案。

client做分片

客户端做路由,采用一致性hash算法,将key映射到对应的redis节点上。

其优点是实现简单,没有引用其他中间件。

缺点也很明显:是一种静态分片方案,扩容性差。

Jedis中的ShardedJedis是该方案的实现。

proxy做分片

该方案在client与redis之间引入一个代理层。client的所有操作都发送给代理层,由代理层实现路由转发给不同的redis服务器。

Java高级架构师-分布式Redis深度历险-Cluster

 

其优点是: 路由规则可自定义,扩容方便。

缺点是: 代理层有单点问题,多一层转发的网络开销

 

欢迎做Java的朋友们加小编的交流群(785779447)免费获取免费的Java架构学习资料(里面有高可用、高并发、高性能及分布式、Jvm性能调优、Spring源码,MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多个知识点的架构资料)
其中覆盖了互联网的方方面面,期间碰到各种产品各种场景下的各种问题,很值得大家借鉴和学习,扩展自己的技术广度和知识面。

自动驾驶仿真(二)—— 基于PreScan与Simulink的联合仿真 自动驾驶仿真软件介绍二—— PreScan与Simulink联合仿真1. Prescan仿真软件2. Prescan与Simulink联合仿真2. 1 Prescan和matlab软件安装2. 2 联合仿真配置3. 联合仿真实例3.1 一辆不按法规行驶的小车3.2 另一辆的正常行驶的小车3.3 视觉辅助摄像机3.4 传感器检测4. 系列学习视频教程5. 参考学习的书目教材 上一篇博文简单介绍了Carsim与Simulink联合仿真,接着这篇就再继续简单介绍另一款自动驾驶仿真软件Prescan,并且简单做个P 阅读详情

相关推荐

Geant4学习——入门(基本概念、Geant4工具包的结构、强制类、可选类)

Geant4是由欧洲核子研究组织基于C++面向对象技术开发的蒙特卡罗应用软件包,用于模拟粒子在物质中输运的物理过程。由于具有良好的通用性和扩展能力,Geant4在涉及微观粒子与物质相互作用的诸多领域获得了广泛应用。 第一部分 Geant4的基本概念 HEP中的模拟是“虚拟现实”。仿真既可用于在研发阶段帮助设计探测器,又可用于物理研究中了解探测器的响应。为了创建这样的虚拟现实,我们需要对粒子间的相互作用,几何形状和材料进行建模,以便将基本粒子传播到检测器中。我们还需要描述检测器生成原始数据的灵敏度。 Gea

M_M-铭的博客 2万+

【Redis】Java操作redis集群cluster

文章目录 借助redis的java客户端jedis可以操作以上集群,引用jedis版本的maven坐标如下: <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.9.0</version> </dependency> Java编写访问redis集群的代码非常简单,如

m0_45406092的博客 1952

ADC选型实战:从参数指标到精准应用的工程指南

本文深入解析ADC(模数转换器)选型的关键参数与实战技巧,涵盖分辨率、转换误差等核心指标,并提供高精度温度测量、高速数据采集等五大应用场景的选型指南。通过实际案例和代码示例,详细讲解校准方法、功耗优化策略及常见问题排查,帮助工程师实现从参数指标到精准应用的工程实践。

weixin_29166013的博客 326

深入学习Redis(5):集群

前言 在前面的文章中,已经介绍了Redis的几种高可用技术:持久化、主从复制和哨兵,但这些方案仍有不足,其中最主要的问题是存储能力受单机限制,以及无法实现写操作的负载均衡。 Redis集群解决了上述问题,实现了较为完善的高可用方案。本文将详细介绍集群,主要内容包括:集群的作用;集群的搭建方法及设计方案;集群的基本原理;客户端访问集群的方法;以及其他实践中需要的集群知识(集群扩容、故障转移、参数...

weixin_30247781的博客 480

C# 调用halcon中visualize_object_model_3d显示点云

3.1 判断线程是否为空,如果为空,则新创建,如果不为空,则中断线程,清空窗口后再次执行创建操作3.2 创建:调用show()方法实例化显示类的对象,传入显示参数,将线程testvisual 绑定 在 类对象的action方法上(此处action方法内部,只调用了visualize_object_model_3d算子)3.3 启动线程。

weixin_42362219的博客 1403

深入解析ViT中的RoPE旋转位置编码:原理、实现与视觉应用

本文深入解析了ViT中的RoPE旋转位置编码原理、实现及其在视觉任务中的应用。RoPE通过旋转变换巧妙地将相对位置信息融入注意力计算,解决了传统绝对位置编码外推性差的问题,在图像分类、目标检测及生成任务中展现出更优的泛化能力和灵活性。

alice7model的博客 705

Java手撕面试官-面试官常问的Nginx的几个问题

1.什么是Nginx? Nginx是一个高性能的HTTP和反向代理服务器,也是一个IMAP/POP3/SMTP服务器 Nginx是一款轻量级的Web服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器 目前使用的最多的web服务器或者代理服务器,像淘宝、新浪、网易、迅雷等都在使用 2.为什么要用Nginx? 优点: 跨平台、配置简单 非阻塞、高并发连接:处理2-3万并发连接数,官方监...

JavaWildcat的博客 755

iTunes登录协议逆向与自动化实现

本文详细解析了iTunes登录协议的逆向工程与自动化实现方法,涵盖请求体构造、签名生成和会话管理等关键技术。通过XML结构解析、X-Apple-ActionSignature生成原理及完整登录流程实现,帮助开发者高效完成iTunes自动化登录,提升工作效率。

weixin_26938645的博客 939

JAVA高级架构师-浅析JavaWeb开发模式:Model1和Model2

一、前言 在学习JavaWeb的过程中,大家都会接触到Model1和Model2,历史的发展过程是Model1 → Model2。那么它们之间有何相同之处和不同之处呢? 二、Model1 Model1使用了两种技术:JSP+JavaBean。 在Model1模式下,整个Web应用几乎全部由JSP页面组成,JSP页面接受处理客户端请求,对请求处理后直接做出响应。用少量的J...

JavaWildcat的博客 667

2. Android_逆向的历史与发展

学完本节,希望你能够:了解 Android 逆向工程的发展历程,从早期 APK 破解到现代应用保护;入门先把这几类「在干啥」搞清楚,后面学脱壳、反反调试会顺很多。(反编译 APK 得到的类汇编代码,相当于程序的「菜谱」)就能绕过验证,到后来混淆、加固、反调试一起上,逆向难度越来越高。(第三节 什么是 CPU 指令集),帮你搞清楚「反汇编看到的那些指令」是从哪来的、和 Android 逆向有啥关系。有必要——先搞清「没加固时怎么玩」,再学脱壳和对抗,思路才顺。读起来费劲,但逻辑还在,耐心一点还能跟。

长沙火山 1390

【数据同化第二期】数据同化中三大理论基础之一(最小方差估计)

【数据同化第二期】深入理解数据同化及经典案例(最小方差估计)

WW、forever的博客 1596

深入理解Java虚拟机笔记---底层原理分析与性能优化

深入理解Java虚拟机笔记---底层原理分析与性能优化 文末彩蛋福利# 概念 虚拟机:指以软件的方式模拟具有完整硬件系统功能、运行在一个完全隔离环境中的完整计算机系统 ,是物理机的软件实现。常用的虚拟机有VMWare,Visual Box,Java Virtual Machine(Java虚拟机,简称JVM)。 Java虚拟机阵营:Sun HotSpot VM、BEA JRockit ...

JavaWildcat的博客 530

SAP FICO 科目余额查询表开发说明书(包括测试样例、程序代码仅作参考,不保证一定可以运行)

SAP FICO 科目余额查询表开发说明书(包括开发源代码、测试样例)

我好像病了的博客 1041

Java NIO ByteBuffer 的使用与源码研究

一、结论   ByteBuffer 是Java NIO体系中的基础类,所有与Channel进行数据交互操作的都是以ByteBuffer作为数据的载体(即缓冲区)。ByteBuffer的底层是byte数组,通过四个重要的成员变量(mark、limit、position、capacity)来实现对缓冲区的读写数据以及复用缓冲区等操作。ByteBuffer 申请缓冲区内存(数组)的方式有两种,即堆内...

JavaWildcat的博客 443

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

一个经典面试题:如何保证缓存与数据库的双写一致性?

只要用缓存,就可能会涉及到缓存与数据库双存储双写,你只要是双写,就一定会有数据一致性的问题,那么你如何解决一致性问题? 面试题剖析 一般来说,如果允许缓存可以稍微的跟数据库偶尔有不一致的情况,也就是说如果你的系统不是严格要求 “缓存+数据库” 必须保持一致性的话,最好不要做这个方案,即:读请求和写请求串行化,串到一个内存队列里去。 串行化可以保证一定不会出现不一致的情况,但是它也会导致系统的...

JavaWildcat的博客 428

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

Java高并发缓存架构,缓存雪崩、缓存穿透之谜

面试题 了解什么是 redis 的雪崩、穿透和击穿?redis 崩溃之后会怎么样?系统该如何应对这种情况?如何处理 redis 的穿透? 面试官心理分析 其实这是问到缓存必问的,因为缓存雪崩和穿透,是缓存最大的两个问题,要么不出现,一旦出现就是致命性的问题,所以面试官一定会问你。 面试题剖析 缓存雪崩 对于系统 A,假设每天高峰期每秒 5000 个请求,本来缓存在高峰期可以扛住每秒 4...

JavaWildcat的博客 414

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

Java高级架构师-Spring 注解编程之注解属性别名与覆盖

注解属性方法 在进入了解 Spring 注解属性功能之前,我们先看一个正常 Java 注解。 在注解中,属性方法与其他类/接口方法写法类似,但是存在一些区别。 注解属性方法的返回类型仅限为八种基本类型(包装类不支持),字符串,class,enum,Annotation以及前面类型的数组。 复习一下,java 八种基本类型分别为,byte(字节型)、short(短整型)、int(...

JavaWildcat的博客 378

Java-基于Spring Cloud Netflix的TCC柔性事务和EDA事件驱动示例

Solar Spring Cloud为开发者提供了快速构建分布式系统中的一些常见工具,如分布式配置中心,服务发现与注册中心,智能路由,服务熔断及降级,消息总线,分布式追踪的解决方案等。 本次实战以模拟下单流程为背景,结合Spring Cloud Netflix和分布式事务解决方案中Try Confirm Cancel模式与基于事件驱动的服务架构作为实战演示。 开发环境 Docker 1.1...

JavaWildcat的博客 351

Java高级架构师-分布式Redis深度历险-Sentinel

如何保障集群高可用 保障集群高可用,要具备如下能力: 能监测服务器的状态,当主服务器不可用时,能及时发现 当主服务器不可用时,选择一台最合适的从服务器替代原有主服务器 存储相同数据的主服务器同一时刻只有一台 要实现上述功能,最直观的做法就是,使用一台监控服务器来监视Redis 服务器的状态。 监控服务器和主从服务器间维护一个心跳连接,当超出一定时间没有收到主服务器心跳时...

JavaWildcat的博客 340

阿里p7架构师带你领略JMM

概述 JMM的全称是Java Memory Model(Java内存模型) JMM的关键技术点都是围绕着多线程的原子性、可见性和有序性来建立的,这也是Java解决多线程并行机制的环境下,定义出的一种规则,意在保证多个线程间可以有效地、正确地协同工作。 三要素 原子性(Atomicity) 原子性是指一个操作是不可中断的,即使是在多个线程一起执行的情况下,一个操作一旦开始执行,就不会受到其...

JavaWildcat的博客 278

Java高级架构师-Java集合 HashSet的原理及常用方法

目录 一. HashSet概述 二. HashSet构造 三. add方法 四. remove方法 五. 遍历 六. 合计合计 先看一下LinkedHashSet 在看一下TreeSet 七. 总结 一. HashSet概述 HashSet是Java集合Set的一个实现类,Set是一个接口,其实现类除HashSet之外,还有TreeSet,并继承了Collection,Hash...

JavaWildcat的博客 261

Java高级架构师-集合框架使用原理分析

集合是我们日常编程中可能用的很多的技术之一 使用频率极高 可能平时就会知道怎么去用 但是集合之间的关系与不同之处都不是很清楚 对它们的底层原理更甚 所以写词文章 让自己有一个更深的认识 集合是一个庞大的家族 今天先来说说这几个 ArrayList、LinkedList、Vector ArrayList由于它的底层是数组 数组我们都知道它的查询修改都是效率很高的 ArrayLi...

JavaWildcat的博客 230

Java高级架构师-分布式Redis深度历险-复制

Redis深度历险分为两个部分,单机Redis和分布式Redis。 本文为分布式Redis深度历险系列的第一篇,主要内容为Redis的复制功能。 Redis的复制功能的作用和大多数分布式存储系统一样,就是为了支持主从设计,主从设计的好处有以下几点: 读写分离,提高读写性能 数据备份,减少数据丢失的风险 高可用,避免单点故障 旧版复制实现 Redis的复制主要分为同步和命...

JavaWildcat的博客 227

Flink 学习日志 03:自定义一个SourceFunction,完成对Redis中数据的读取

本文介绍了在Flink中自定义SourceFunction读取Redis数据的完整流程:通过Jedis客户端连接WSL2中的Redis服务,编写RedisSource实现循环读取所有Key-value并逐条输出,结合Thread.sleep()实现每秒一条的流式效果。关键步骤包括环境准备、添加Jedis依赖、配置IDEA运行时加载provided依赖,并注意生产环境中应避免使用阻塞的keys *,改用scan命令。最终实现动态读取、实时打印,验证了Flink与Redis的数据集成能力。

木木的学习笔记 419

Spring Boot 工程通用能力建设:声明式事务定制与 Redis 缓存实践

本文探讨Spring Boot中声明式事务的进阶实践,通过解耦“切点”与“事务属性”,实现灵活控制。核心包括:基于方法名的只读规则(如get*、find*自动设为只读),组合事务属性源确保@Transactional注解优先于命名规则,以及自定义切点实现事务统一织入。该方案提升代码可维护性,避免误写,同时支持特殊场景覆盖,构建更健壮的事务治理体系。

BADAO_LIUMANG_QIZHI的博客 246

Docker多阶段构建实现基于Alpine的Redis的编译安装

【代码】Docker多阶段构建实现基于Alpine的Redis的编译安装。

一直在努力学习的菜鸟 319
上一篇: Java高级架构师-分布式Redis深度历险-Sentinel
下一篇: 一个经典面试题:如何保证缓存与数据库的双写一致性?
程序员杨过
博客等级 码龄7年 13粉丝 17原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值