• 深入Redis的切片


    目录

    前提场景:

    分片后,实例如何分布?

    分片原理

    首先抛出问题,如果我们是一个行的话,会出现什么样的情况?

     提问 有12个球如何均匀的放在3个桶里对应到分片中

     数据倾斜的解决

    判断插槽是否负责当前节点处理

    Moved错误

    ASK错误

    ASK 和 MOVED 的区别

    故障检测+故障转移

    故障转移的执行步骤:


     

    前提场景:

    单台redis的管理内存能力是有限的,如果保存有海量的缓存数据,则一台redis无法操作

    那么就要对redis进行扩容,

    redis分片主要目的实现redis内存扩容,对用户而言使用的就是一大台redis,但是内部每个redis中保存的数据都是不同的——>Redis集群,多个redis实例完成对16384插槽的分配

    例子:

    要用 Redis 保存 5000 万个键值对,每个键值对大约是 512B,为了能快速部署并对外提供服务,我们采用云主机来运行 Redis 实例,那么,该如何选择云主机的内存容量呢?

    通过计算,这些键值对所占的内存空间大约是 25GB(5000 万 *512B)

    方案一:进行垂直扩展,选则一个内存更加大的云主机来部署Redis,同时该redis实例采用RDB进行数据备份保证数据的持久化——>数据越多,RDB恢复越久,因为Redis的RDB备份是bgsave——>通过fork子进程异步完成数据的持久化(备份时长和数据量大小成正比)

    方案二:

    (37条消息) 分布式Redis_Fairy要carry的博客-CSDN博客

    也就是redis集群,水平扩展更多的redis实例,集群通过分片(分配插槽来提供每个节点的数据存储)

    在这里插入图片描述

    这样的话相当于每个节点保存5gb数据 ,将并发度提高之外,还减少了fork子进程异步保存数据的速度

    1.添加集群命令

    CLUSTER MEET <ip> <port>

    2.先连上一个节点

    $ redis-cli -c -p 7001

    3.然后将其他节点添加到该集群当中

    127.0.0.1:7001> CLUSTER MEET 127.0.0.1 7002

    也可以这样部署 

    (37条消息) Redis分片集群_Fairy要carry的博客-CSDN博客_redis分片和集群

    4.通过cluster nodes可以查看集群中节点信息

    分片后,实例如何分布?

    分片原理

    ShardedJedis是通过一致性哈希来实现分布式缓存的,通过一定的策略把不同的key分配到不同的redis server ,达到横向扩展的目的的

    首先抛出问题,如果我们是一个行的话,会出现什么样的情况?

    那么就不是一个环,像hash(key)%3这样,就会因为添加一个redis实例到集群中——>导致redis集群中每一个实例都会发生移动,因为节点数量变了,那么切片规则就会发生改变,每个节点的插槽就会改变,这样非常影响效率

     解决:hash一致性原理

    1.0-2^32数字组成了一个hash环

    2.根据redis的ip或者主机名计算一个hash值得到在圆环的对应位置

    3、然后根据key计算一个hash值,放在对应的圆环上,根据key位置顺时针离圆环最近的redis服务器存取;

    4、为了均衡性,通常会虚拟节点服务器;——>防止数据倾斜

     提问 有12个球如何均匀的放在3个桶里对应到分片中

    答:先对球从0开始进行编号0,1,2…11,再对桶进行编号0,1,2

    每个球的编号对三取余,得出0,1,2…0,1,2

    引伸:我们的redis集群也是这样,通过对2^32进行取模

    0到2^32-1组成了一个hash圆环,正上方是0,顺时针依次到232-1

    由这2^32个点组成的圆环,被称为hash环

    优点:这样redis节点一定在该环上,这样如果再添加一个新的节点,那么就不会出现整个redis集群所有节点都发生迁移的情况,而是只有两个节点交换的问题,所以说效率会高很多

     数据倾斜的解决

    引入虚拟节点即可,将数据合理分配,从而不会出现那种一个节点占用非常多数据,一个节点占用较少数据的情况

    通过 CLUSTER KEYSLOT 命令可以查看 key 属于哪个槽

    判断插槽是否负责当前节点处理

    当节点计算出 key 所属的 槽 i 之后,节点会判断 槽 i 是否被指派了自己。那么如何判断呢?

    每个节点会维护一个 「slots数组」,节点通过检查 slots[i] ,判断 槽 i 是否由自己负责:

    1.如果说 slots[i] 对应的节点是当前节点的话,那么说明 槽 i 由当前节点负责,节点可以执行客户端发送的命令;
    2.如果说 slots[i] 对应的不是当前节点,节点会根据 slots[i] 所指向的节点向客户端返回 MOVED 错误,指引客户端转到正确的节点
     

    Moved错误

    MOVED  <slot> <ip>:<port>
    • slot:键所在的槽
    • ip:负责处理槽 slot 节点的 ip
    • port:负责处理槽 slot 节点的 port

    比如:MOVED 10086 127.0.0.1:7002,表示,客户端请求的键值对所在的哈希槽 10086,实际是在 127.0.0.1:7002 这个实例上。

    通过返回的 MOVED 命令,就相当于把哈希槽所在的新实例的信息告诉给客户端了。

    同时,客户端还会更新本地缓存,将该槽与 Redis 实例对应关系更新正确。

    这样一来,客户端就可以直接和 7002 连接,并发送操作请求了。

    集群模式的 redis-cli 客户端在接收到 MOVED 错误时,并不会打印出 MOVED 错误,而是根据 MOVED 错误自动进行节点转向,并打印出转向信息,所以我们是看不见节点返回的 MOVED 错误的。而使用单机模式的 redis-cli 客户端可以打印MOVED 错误

    ASK错误

    如果客户端向目标节点发送一个与数据库键有关的命令,并且这个命令要处理的键正好属于被迁移的槽——>在迁移中途

    • 源节点会先在自己的数据库里查找指定的键,如果找到的话,直接执行命令;
    • 相反,如果源节点没有找到,那么这个键就有可能已经迁移到了目标节点,源节点就会向客户端发送一个 ASK 错误,指引客户端转向目标节点,并再次发送之前要执行的命令。

    在这里插入图片描述

    如上图所示,节点 7003 正在向 7004 迁移 槽 16383,这个槽包含 hello 和 world,其中键 hello 还留在节点 7003,而 world 已经迁移到 7004

    1.我们向节点 7003 发送关于 hello 的命令 这个命令会直接执行

    1. 127.0.0.1:7003> GET "hello"
    2. "you get the key 'hello'"

    2.如果我们向节点 7003 发送 world 那么客户端就会被重定向到 7004

    1. 127.0.0.1:7003> GET "world"
    2. -> (error) ASK 16383 127.0.0.1:7004

    ASK 和 MOVED 的区别

    相同点:ASK 错误和 MOVED 错误都会导致客户端重定向

    不同点:

    1.MOVED 错误代表槽的负责权已经从一个节点转移到了另一个节点(本来就不是该位置上负责):在客户端收到关于 槽 i 的 MOVED 错误之后,客户端每次遇到关于 槽 i 的命令请求时,都可以直接将命令请求发送至 MOVED 错误指向的节点,因为该节点就是目前负责 槽 i的节点。
    2.而 ASK 只是两个节点迁移槽的过程中的一种临时措施:在客户端收到关于 槽 i 的 ASK 错误之后,客户端只会在接下来的一次命令请求中将关于 槽 i 的命令请求发送到 ASK 错误指向的节点,但是 ,如果客户端再次请求 槽 i 中的数据,它还是会给原来负责 槽 i 的节点发送请求。
     

    故障检测+故障转移

    master互相png,来检测对方是否在线,如果接收消息一方没有在规定时间返回PONG,那么接收消息的一方就会被发送方标记为「疑似下线」

    节点的三种状态:

    • 在线状态
    • 疑似下线状态 PFAIL
    • 已下线状态 FAIL

     当有一半以上认为一个主节点应该挂了,那么就主从切换

    故障转移的执行步骤:

    1.在复制下线主节点的所有从节点里,选中一个从节点
    2.被选中的从节点执行 SLAVEOF no one 命令,成为主节点
    3.新的主节点会撤销所有对已下线主节点的槽指派,将这些槽全部指派给自己
    4.新的主节点向集群广播一条 PONG 消息,让集群中其他节点知道,该节点已经由从节点变为主节点,且已经接管了原主节点负责的槽
    5.新的主节点开始接收自己负责处理槽有关的命令请求,故障转移完成。

    (37条消息) Redis配置文件+发布订阅+新数据类型_Fairy要carry的博客-CSDN博客

  • 相关阅读:
    Qt+ECharts开发笔记(一):ECharts介绍、下载和Qt调用ECharts基础柱状图Demo
    小米首款汽车预计2024年量产;英伟达发布首款基于Hopper架构GPU;​Java 18正式发布|极客头条
    golang的垃圾回收算法之五GMP模型
    数据结构 线性表部分代码
    MySQL中explain的用法
    80C51单片机指令寻址方式
    java学习part06数组工具类
    在轮询系统如何将A站订单在B站自动建立,并调用B站产品
    腾讯产品经理的自动化工作流
    LeetCode_模拟_中等_2596.检查骑士巡视方案
  • 原文地址:https://blog.csdn.net/weixin_57128596/article/details/126719076