《Redis设计与实现》读书笔记(二十九) ——Redis集群执行命令与重新分片

《Redis设计与实现》读书笔记(二十九) ——Redis集群执行命令与重新分片

(原创内容,转载请注明来源,谢谢)

一、集群中执行命令

1、节点对命令的判断

当对集群的16384个槽都完成指派后,集群就上线,可以对集群进行操作。当客户端向节点发送数据库键有关的命令,接收命令的节点,会计算命令属于哪个槽,并检查槽是否指派给自己。

如果槽是该节点负责,则执行命令;如果不是,返回一个moved错误,指引客户端对正确的节点执行命令,客户端根据返回结果,会自动连接上相应的节点,再次执行命令。

2、计算键属于哪个槽

假设键名为key,计算方法如下:

crc16(key) & 16383

其中,crc16是一种算法,将key用crc16算法获取的结果,在与16383进行比较,获取一个介于0~16383的整数。

可以采用cluster keyslotkey,查看键属于哪个槽。

3、判断槽是否由当前节点处理

根据上述算法计算出键所述的槽后,节点会与clusterState的slots相应下标的指针比对:

如果指针指向自身则表示该槽由自身负责;

如果指针不是指向自身,而是指向某个节点的clusterNode结构,则从该结构获取ip和端口号,并将ip、端口号、moved错误一并返回给客户端。

4、moved错误介绍

move命令为:moved<slot> <ip> <port>

当客户端收到moved命令,就会解析里面的ip和端口号,并重新连上相应的节点,再执行命令。

不过,由于moved错误的时候,处于集群状态下的redis-cli客户端会自动重定向,显示的也是redirect,因此客户端上看不到报错信息。

但是,如果是单机模式下的redis-cli客户端,则会直接报错,因为其并不知道moved命令的含义,也不会自动连接上新的节点。

5、节点数据的实现

集群节点有个限制,只能用0号数据库。键值对的保存方式和单机一样。另外,节点的clusterState结构,还会保存槽和键的关系。

         typedef structclusterState{
         //….其他内容
         zskiplist*slots_to_keys;

}clusterState;

节点保存槽和键的关系,用的是zskiplist,其分值(score)是槽的编号,每个阶节点成员(member)是数据库的键。如下:

将键这样保存,便于批量操作。例如cluster getkeysinslot <slot> <count>命令(重新分片相关命令),可以返回最多count个,槽是slot的键。

二、重新分片

1、概述

redis集群的重新分片功能,可以将任意数量已经指派给某个节点的槽,修改为指派给另一个节点,且相关槽对应的数据库的键值对数据也迁移到另一个节点。

重新分片工作可以在线进行,集群不需要下线,并且源节点和目标节点都可以正常处理客户端的其他命令。

2、原理

redis重新分片,是由redis集群管理软件redis-trib负责执行的,redis提供了进行重新分配所需的所有命令。而redis-trib软件通过向源节点和目标节点发送命令,来完成重新分片的工作。

对单个槽进行重新分片,步骤如下:

1)redis-trib对目标节点发送命令clustersetslot <slot> importing <source_id>命令,让目标节点准备好从源节点导入编号是slot的槽的键值对。

2)redis-trib对源节点发送命令clustersetslot <slot> migrating <target_id>命令,让源节点准备好将编号是slot的槽的键值对导入到目标节点。

3)redis-trib向源节点发送命令clustergetkeysinslot <slot> <count>命令,获取最多count个属于槽slot的键值对的键。

4)对于第3步的每个键,redis-trib都向源节点发送命令migrate<target_ip> <target_port> <key_name> 0 <timeout>命令,将被选中的键迁移到目标节点。

5)重复3、4步骤,直到所有属于编号slot的槽都完成迁移。

6)redis-trib将命令clustersetsslot <slot> node <target_id>发送给集群中的任一节点,然后命令会在集群中广播,所有节点都会知道槽slot已经归目标节点负责。

如果是多个槽重新分片,则每个槽都会经历上述的步骤进行重新分片。

—written by linhxx 2017.09.15

原文发布于微信公众号 - 决胜机器学习(phpthinker)

原文发表时间:2017-09-15

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏hbbliyong

Python类、模块、包的区别

模块,在Python可理解为对应于一个文件。在创建了一个脚本文件后,定义了某些函数和变量。你在其他需要这些功能的文件中,导入这模块,就可重用这些函数和变量。一般...

952
来自专栏coding

python的多进程与多fork

1153
来自专栏肖洒的博客

【MOOC】Python网络爬虫与信息提取

Python网络爬虫与信息提取-北京理工大学-嵩天 发布大学:北京理工大学 发布课程:Python网络爬虫与信息提取 授课老师:嵩天 课程简介:“The web...

722
来自专栏云霄雨霁

并发编程包--java.util.Concurrent

1083
来自专栏极客编程

Python超级明星WEB开发框架Flask简明教程

和Django大包大揽不同,Flask建立于一系列的开源软件包之上,这其中 最主要的是WSGI应用开发库Werkzeug和模板引擎Jinja:

932
来自专栏chenssy

【死磕Java并发】—–J.U.C之Condition

在没有Lock之前,我们使用synchronized来控制同步,配合Object的wait()、notify()系列方法可以实现等待/通知模式。在Java SE...

3224
来自专栏python学习之旅

Python笔记(十三):urllib模块

(一)      URL地址 URL地址组件 URL组件 说明 scheme 网络协议或下载方案 net_loc ...

2766
来自专栏LanceToBigData

JavaWeb(一)Servlet中乱码解决与转发和重定向的区别

前言   前面其实已经把Servlet中所有的内容都介绍完了,这篇讲补充一点乱码和重定向与转发之间的区别! 一、request请求参数出现乱码问题 1.1、ge...

21910
来自专栏积累沉淀

shell脚本学习之必须了解的基础命令

命令历史 history !! 表示执行上一条命令 !n  表示执行历史中第n条命令 !字符串  表示执行命令历史中首次出现该字符串的命令 设置别名:...

1699
来自专栏锦小年的博客

python学习笔记5.3-包的创建

包,也可以称为库,是具有很多功能的一个集合体。本文主要介绍如何自己创建一个包,以及介绍一些在包的创建过程中的技巧。 1. 包的创建 本文的例子将使用最复杂的情况...

2158

扫码关注云+社区