首页 > 数据库 >Redis底层原理

Redis底层原理

时间:2024-08-17 15:54:49浏览次数:10  
标签:slave Redis master 原理 数据 节点 集群 底层

1.Redis主从

单节点Redis的并发能力是有上限的,要进一步提高Redis的并发能力,就需要搭建主从集群,实现读写分离。

1.1.单节点Redis的并发能力

单节点Redis的并发能力确实是有限的。主要原因包括以下几点:

  1. 单线程模型:Redis采用单线程模型来处理请求,这意味着它一次只能处理一个请求,虽然它的事件驱动机制可以快速切换上下文,但在高并发情况下,仍然会受到限制。

  2. 网络带宽:单节点的网络带宽也是一个瓶颈。在高并发情况下,网络的吞吐量可能会成为限制性能的因素。

  3. 内存限制:Redis是基于内存的数据库,内存的大小也会影响其并发处理能力。如果内存不足,可能会导致性能下降。

  4. CPU资源:虽然Redis是单线程的,但在高并发情况下,CPU的资源也会成为一个限制因素,尤其是在处理复杂命令时。

为了提高并发能力,可以考虑以下几种方案:

  • 主从复制:通过设置主从复制,将读请求分散到多个从节点上。
  • 分片:将数据分片到多个Redis实例中,以实现负载均衡。
  • 使用Redis Cluster:Redis Cluster可以自动分片和负载均衡,支持更高的并发能力。

1.2.主从集群结构

下图就是一个简单的Redis主从集群结构:

集群中有一个master节点、两个slave节点(现在叫replica)。当我们通过Redis的Java客户端访问主从集群时,应该做好路由:

  • 如果是写操作,应该访问master节点,master会自动将数据同步给两个slave节点:

    • 1.配置master节点的redis.conf文件,启用复制功能并设置密码(可选)

    • 2.启动两个slave节点,并在它们的redis.conf文件中配置连接到master节点的信息

    • 3.重启master和slave节点,使配置生效。

一旦配置完成并重启节点,master节点将会自动将数据同步给两个slave节点。您可以通过监控命令 INFO replication 来查看复制的状态和信息,确保数据同步正常进行。

  • 如果是读操作,建议访问各个slave节点,从而分担并发压力

集群有临时和永久两种模式:

  • 永久生效:在redis.conf文件中利用slaveof命令指定master节点

  • 临时生效:直接利用redis-cli控制台输入slaveof命令,指定master节点

1.3.主从集群的原理

1.3.1全量同步

在Redis中,全量同步(Full Sync)是指Slave节点在刚刚连接到Master节点时,进行一次完整的数据同步过程。这个过程确保Slave节点和Master节点的数据一致性,以便Slave节点能够开始接收增量同步数据。如下图所示:

  1. Slave节点连接到Master节点,并发送SYNC命令请求数据同步命令,申请进行全量同步。
  2. Master节点接收到SYNC请求后,会先判断是否是第一次同步,如果是第一次同步,染回master的数据版本信息,Slave会保存版本信息。
  3. 接下来Master会在后台创建一个RDB文件,将当前数据库中的数据快照存储到RDB文件中。
  4. Master节点将生成的RDB文件发送给Slave节点。
  5. Slave节点接收到RDB文件后,会先清空本地数据,再将其加载到内存中,完成全量同步。
  6. 一旦全量同步完成,Master节点会继续将增量数据发送给Slave节点,以保持数据的一致性。

这里有一个问题,Masteer如何得知Salve是否是第一次来同步呢??

有几个概念,可以作为判断依据:

  • Replication Id:简称replid,是数据集的标记,replid一致则是同一数据集。每个master都有唯一的replidslave则会继承master节点的replid

  • offset:偏移量,随着记录在repl_baklog中的数据增多而逐渐增大。slave完成同步时也会记录当前同步的offset。如果slaveoffset小于masteroffset,说明slave数据落后于master,需要更新。

        Slave在做数据同步,必须向master声明自己的replication id offsetmaster才可以判断到底需要同步哪些数据。

        由于我么在执行slaveof(认主)命令时,所有的redis节点都是主节点,有自己的replid和offset,所以,我们建立关系后需要对这两个数据进行主从同步。而这两条数据也就成了我们判断主从节点之间,是否是第一次数据交互的凭证。当我们进行第一次数据交互时如果主从节点之间replid和offset这两个数据不一致,就是第一次交互,就要进行全量同步。

1.3.2.增量同步

在Redis中,增量同步(Partial Sync)是指Slave节点在完成全量同步后,接收并应用Master节点的增量数据更新。这个过程确保了Slave节点和Master节点之间的数据保持一致。

增量同步就是只更新slave与master存在差异的部分数据。如图:

增量同步的流程如下:

  1. Master节点在完成全量同步后,将持续记录并保存所有的写操作命令(包括SET、DEL等)到内存中的复制缓冲区(replication buffer)中。

  2. 当有新的写操作发生时(就是不是第一次数据交互),Master节点将这些写操作命令发送给所有连接的Slave节点。

  3. Slave节点接收到增量数据更新后,会将这些命令按顺序应用到自己的数据集中,以保持与Master节点的数据一致。

通过增量同步,Slave节点能够及时地接收并应用Master节点的更新,从而保持数据的一致性。需要注意的是,增量同步是异步的,因此在极端情况下可能会有数据延迟。

2.Redis哨兵

主从结构中master节点的作用非常重要,一旦主节点故障就会导致整个集群不可用。那么有什么办法能保证主从集群的高可用性呢?

2.1.哨兵工作原理

Redis提供了哨兵Sentinel)机制来监控主从集群监控状态,确保集群的高可用性。

2.1.1.哨兵作用

哨兵集群作用原理图:

哨兵的作用如下:

  • 状态监控Sentinel 会不断检查您的masterslave是否按预期工作

  • 故障恢复(failover):如果master故障,Sentinel会将一个slave提升为master。当故障实例恢复后会成为slave

  • 状态通知Sentinel充当Redis客户端的服务发现来源,当集群发生failover时,会将最新集群信息推送给Redis的客户端

那么问题来了,Sentinel怎么知道一个Redis节点是否宕机呢?

2.1.2.状态监控

Sentinel基于心跳机制监测服务状态,每隔1秒向集群的每个节点发送ping命令,并通过实例的响应结果来做出判断:

  • 主观下线(sdown):如果某sentinel节点发现某Redis节点未在规定时间响应(就是会一直ping,节点会响应pong),则认为该节点主观下线。

  • 客观下线(odown):若超过指定数量(通过quorum设置)的sentinel都认为该节点主观下线,则该节点客观下线。quorum值最好超过Sentinel节点数量的一半,Sentinel节点数量至少3台。

如图:

一旦发现master故障,sentinel需要在salve中选择一个作为新的master,选择依据是这样的:

  • 首先会判断slave节点与master节点断开时间长短,如果超过down-after-milliseconds * 10则会排除该slave节点

  • 然后判断slave节点的slave-priority值,越小优先级越高,如果是0则永不参与选举(默认都是1)。

  • 如果slave-prority一样,则判断slave节点的offset值,越大说明数据越新,优先级越高

  • 最后是判断slave节点的run_id大小,越小优先级越高(通过info server可以查看run_id)。

对应的官方文档如下:

High availability with Redis Sentinel | Docsicon-default.png?t=N7T8https://redis.io/docs/latest/operate/oss_and_stack/management/sentinel/#replica-selection-and-priority

问题来了,当选出一个新的master后,该如何实现身份切换呢?

大概分为两步:

  • 在多个sentinel中选举一个leader

  • leader执行failover

2.1.3.选举leader

首先,Sentinel集群要选出一个执行failover的Sentinel节点,可以成为leader。要成为leader要满足两个条件:

  • 最先获得超过半数的投票

  • 获得的投票数不小于quorum

而sentinel投票的原则有两条:

  • 优先投票给目前得票最多的

  • 如果目前没有任何节点的票,就投给自己

比如有3个sentinel节点,s1s2s3,假如s2先投票:

  • 此时发现没有任何人在投票,那就投给自己。s2得1票

  • 接着s1s3开始投票,发现目前s2票最多,于是也投给s2s2得3票

  • s2称为leader,开始故障转移

不难看出,谁先投票,谁就会称为leader,那什么时候会触发投票呢?

答案是第一个确认master客观下线的人会立刻发起投票,一定会成为leader

OK,sentinel找到leader以后,该如何完成failover呢?

2.1.4.failover

我们举个例子,有一个集群,初始状态下7001为master,7002和7003为slave

假如master发生故障,slave1当选。则故障转移的流程如下:

1)sentinel给备选的slave1节点发送slaveof no one命令,让该节点成为master

2)sentinel给所有其它slave发送slaveof 192.168.150.101 7002 命令,让这些节点成为新master,也就是7002slave节点,开始从新的master上同步数据。

3)最后,当故障节点恢复后会接收到哨兵信号,执行slaveof 192.168.150.101 7002命令,成为slave

3.Redis分片集群

主从模式可以解决高可用、高并发读的问题。但依然有两个问题没有解决:

  • 海量数据存储

  • 高并发写

要解决这两个问题就需要用到分片集群了。分片的意思,就是把数据拆分存储到不同节点,这样整个集群的存储数据量就更大了。

Redis分片集群的结构如图:

分片集群特征:

  • 集群中有多个master,每个master保存不同分片数据 ,解决海量数据存储问题

  • 每个master都可以有多个slave节点 ,确保高可用

  • master之间通过ping监测彼此健康状态 ,类似哨兵作用

  • 客户端请求可以访问集群任意节点,最终都会被转发到数据所在节点

  • 3.1.散列插槽

    数据要分片存储到不同的Redis节点,肯定需要有分片的依据,这样下次查询的时候才能知道去哪个节点查询。很多数据分片都会采用一致性hash算法。而Redis则是利用散列插槽(hash slot)的方式实现数据分片。

    详见官方文档:

  • Scale with Redis Cluster | Docsicon-default.png?t=N7T8https://redis.io/docs/latest/operate/oss_and_stack/management/scaling/#redis-cluster-101

 在Redis集群中,共有16384个hash slots,集群中的每一个master节点都会分配一定数量的hash slots

每一个数据都存储在插槽当中,而每个插槽都有属于自己的一个编号,而这个编号就是在这个集群当中的唯一标识,而集群也知道该插槽在那个master节点下面,这样就不会因为节点的增减而致使,用hash值求余时致使数据找不到。而我们也引入了以大括号里的数据求hash值,然后按照该hash值进行数据的分类,就相当于一个对象有多个属性,而我们如果是按照之前的存储方式去存储,可能致使不同的属性在不同的集群里,这样调用不同的集群也是相当的耗时,从而降低了读的效率。所以,我们才引入了得到相同的hash值的计算方法,这样我们就可以是这些属性存储在同一个集群当中。如下:

当我们读写数据时,Redis基于CRC16 算法对keyhash运算,得到的结果与16384取余,就计算出了这个keyslot值。然后到slot所在的Redis节点执行读写操作。

不过hash slot的计算也分两种情况:

  • key中包含{}时,根据{}之间的字符串计算hash slot

  • key中不包含{}时,则根据整个key字符串计算hash slot

例如:

  • key是user,则根据user来计算hash slot

  • key是user:{age},则根据age来计算hash slot

3.3.故障转移

分片集群的节点之间会互相通过ping的方式做心跳检测,超时未回应的节点会被标记为下线状态。当发现master下线时,会将这个master的某个slave提升为master。

标签:slave,Redis,master,原理,数据,节点,集群,底层
From: https://blog.csdn.net/kwb18293575696/article/details/141267710

相关文章

  • Redis5多实例安装-Redis
    本文是按照Redis5二进制安装的后续1、创建6380、6381目录,分别将安装目录下的redis.conf拷贝到这两个目录下cd/usr/local/redis6/bin/mkdirredis6380mkdirredis6381cpredis.confredis6380/cpredis.confredis6381/2、修改配置文件redis6380viredis6380/redis.con......
  • 面试题:在Java中,线程之间的通信主要通过哪几种方式实现?并简述其中一种方式的基本工作原
    面试题:在Java中,线程之间的通信主要通过哪几种方式实现?并简述其中一种方式的基本工作原理。请注意,除了直接回答此问题外,我们还为您准备了更多深入的学习资源和面试技巧。想要了解更多关于Java线程通信、优化简历、模拟面试、企业项目源码、大厂高并发面试题、项目场景题、算法......
  • 面试题:在Java中,volatile 关键字的作用是什么?它与 synchronized 关键字在实现线程同步
    面试题:在Java中,volatile 关键字的作用是什么?它与 synchronized 关键字在实现线程同步方面有何不同?请深入探讨其背后的原理和应用场景。更多答案在这里,手机或电脑浏览器就可以打开, 面霸宝典【全 拼音】.com 这里可以优化简历,模拟面试,企业项目源码,最新最全大厂高并......
  • 容斥原理
    二项式系数  二项式定理证明过程 (x+y)^n=(x+y)(x+y)(x+y)........(x+y)我们先展开式子,得出以上等式。为了方便,我们以n=3举例(x+y)^3=(x+y)(x+y)(x+y)对于每一个因式(即每一个(x+y)),都可以选择x或者y和其他的因式(即其他的(x+y))也选出x或者y相乘,然......
  • 操作系统--精髓与设计原理(第八版)复习题答案
    操作系统-精髓与设计原理(第八版)复习题-随笔分类-浩楠honer-博客园(cnblogs.com)  转至此操作系统--精髓与设计原理(第八版)第一章复习题答案1.1列出并简要定义计算机的四个组成部分。处理器:控制计算机的操作,执行数据处理功能。内存:也叫主存储器,存储数据和程序。输......
  • Redisson
    packageorg.example.myoracle.config;importorg.redisson.Redisson;importorg.redisson.config.Config;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importorg.springframework.data.redis.co......
  • esp-toothbrush 硬件原理图介绍
    前言个人邮箱:[email protected]项目视频链接硬件介绍电池管理(1)我们项目采用TP4056电源芯片给锂电池充电。因为我们采用的是3.7V锂电池,通过插上USB接口5V供电。通过查看TP4056芯片手册的典型应用可知,该芯片是满足要求的。(2)通过典型应用,我们基本可以知道......
  • Eureka原理实践
    1.简介1.1.概述Eureka是Netflix开源的一个服务注册与发现框架,它在微服务架构中扮演着至关重要的角色。Eureka由两个核心组件组成:EurekaServer(服务注册中心):负责存储、管理和提供服务实例信息,如服务名、IP地址、端口号等。EurekaServer通常采用集群部署以保证高可用......
  • Redux 中间件的实现原理
    Redux中间件的实现原理主要基于函数式编程思想和高阶函数。中间件用于在Redux的dispatch过程之间插入自定义逻辑,如日志记录、异步操作、调试工具等。1.什么是Redux中间件?简要介绍Redux中间件的概念和用途。解释中间件如何在dispatch动作和到达reducer之间插入逻......
  • session概念和底层原理——生命周期
    session–(会话)一、概念session在网络应用中称为“会话控制”,是服务器为了保存用户状态而创建的一个特殊的对象。简而言之,session就是一个对象,用于存储信息。二、使用和注意事项session是以键值对的形式存放数据,类型为**<String,Object>**,通过getAttribute()和setAttri......