背景介绍

我们先来看一下为什么要做集群,如果我们要部署一个单节点Redis,很明显会遇到单点故障的问题。

首先能想到解决单点故障的方法,就是做主从,但是当有海量存储需求时,单一的主从结构就会出问题,说问题之前要先了解一下主从之间是如何复制的。

我们把Redis分为三个部分,分别是客户端、主节点以及从节点,如果从节点要同步主节点的数据,它首先会发Sync指令给主节点,主节点收到指令之后会执行BGSAVE命令生成RDB文件,这个RDB文件指的是快照文件,它是Redis两种备份方式的其中一种,另一种叫AOF,它的原理是将所有的写入指令存入文件,mysql的binlog原理是一样的。

如果主节点在生成RDB的过程当中,客户端发来了写入指令,这个时候主节点会把指令全部写入缓冲区,等RDB生成完了,会把RDB文件发送给从节点,最后再把缓冲区的指令发送给从节点。这样就完成了整个的复制。

我们刚才说单纯地做主从是有缺陷的,这个缺陷就是如果我们要存储海量的数据,那么BGSAVE指令生成的RDB文件会非常巨大,这个文件传送给从节点也会非常慢,如果缓冲区命令很多的话,从节点同步数据时也会执行很久,所以,要解决单点问题和海量存储问题,还是要考虑做集群。

Redis常见集群方案

Redis集群方案目前主流的有三种,分别是Twemproxy、Codis和Redis Cluster。

Twemproxy,是推特开源的,它最大的缺点就是无法平滑的扩缩容,而Codis解决了Twemproxy扩缩容的问题,而且兼容了Twemproxy,它是由豌豆荚开源的,和Twemproxy都是代理模式。其实Codis能发展起来的一个主要原因是它是在Redis官方集群方案漏洞百出的时候率先成熟稳定的。以现在的Redis官方集群方案,这两个好像没有太大差别了,不过我也没有去做性能测试,不清楚哪个最好。

Redis Cluster是由官方出品的,用去中心化的方式实现,不属于代理模式,今天主要讲codis,redis cluster后面也会过一下。下面,来看一下Codis的实现原理。

Codis原理

我们换一种方式去讲,就按照Codis的架构演进一下,这样理解会比较清晰一点,假如现在只有一个Redis Server,怎么让它变得高可用?

开篇的时候也有讲,首先,能想到的就是做主从,这样就算主宕机了,从节点也能马上接替主节点的位置。

我们现在已经做成主从结构了,那到底是谁来负责主从之间的切换?

就是它,Sentinel,中文名叫哨兵,它呢,在Redis里面主要负责监控主从节点,如果主节点挂了,就会把从拉起来。但是哨兵本身也存在单点问题,所以它也需要做集群。

那么问题来了,哨兵是如何做主从切换呢?来看下哨兵的运行机制。

假如有三个哨兵和一主两从的节点,下面是一主多从,哨兵之间会互相监测运行状态,并且会交换一下节点监测的状态,同时哨兵也会监测主从节点的状态。

如果检测到某一个节点没有正常回复,并且距离上次正常回复的时间超过了某个阈值,那么就认为该节点为主观下线。

这个时候其他哨兵也会来监测该节点是不是真的主观下线,如果有足够多数量的哨兵都认为它确实主观下线了,那么它就会被标记为客观下线,这个时候哨兵会找下线节点的从节点,然后与其他哨兵协商出一个从节点做主节点,并将剩余的从节点指向新的主节点。

关于主从节点的切换有两个环节,第一个是哨兵要选举出领头人来负责下线机器的故障转移,第二是从Slave中选出主节点,领头人的选举规则是谁发现客观下线谁就可以马上要求其他哨兵认自己做老大,其他哨兵会无条件接受第一个发过来的人,并告知老大,如果超过一半人都同意了,那他老大的位置就坐实了。

关于从节点选举,一共有四个因素影响选举的结果,分别是断开连接时长、优先级排序、复制数量、进程id,如果连接断开的比较久,超过了某个阈值,就直接失去了选举权,如果拥有选举权,那就看谁的优先级高,这个在配置文件里可以设置,数值越小优先级越高,如果优先级相同,就看谁从master中复制的数据最多,选最多的那个,如果复制数量也相同,就选择进程id最小的那个。

现在继续回过来,刚才讲痛点的时候说了,如果有存储海量数据的需求,同步会非常缓慢,所以我们应该把一个主从结构变成多个,把存储的key分摊到各个主从结构中来分担压力。

就像这样,代理通过一种算法把要操作的key经过计算后分配到各个组中,这个过程叫做分片,我们来看一下分片的实现原理。

分片算法

在Codis里面,它把所有的key分为1024个槽,每一个槽位都对应了一个分组,具体槽位的分配,可以进行自定义,现在如果有一个key进来,首先要根据CRC32算法,针对key算出32位的哈希值,然后除以1024取余,然后就能算出这个KEY属于哪个槽,然后根据槽与分组的映射关系,就能去对应的分组当中处理数据了。

CRC全称是循环冗余校验,主要在数据存储和通信领域保证数据正确性的校验手段,我去看了这个算法的原理,还没理解透彻,这里就先不讲了,省得误导大家。

我们继续回过来,刚才所讲的槽位和分组的映射关系就保存在codis proxy当中,但是codis proxy它本身也存在单点问题,所以需要对proxy做一个集群。

部署好集群之后,有一个问题,就是槽位的映射关系是保存在proxy里面的,不同proxy之间怎么同步映射关系?

在Codis中使用的是Zookeeper来保存映射关系,由proxy上来同步配置信息,其实它支持的不止zookeeper,还有etcd和本地文件。在zookeeper中保存的数据格式就是这个样子。除了这个还会存储一些其他的信息,比如分组信息、代理信息等,感兴趣可以自己去了解一下。

现在还有一个问题,就是codis proxy如果出现异常怎么处理,这个可能要利用一下k8s中pod的特性,在k8s里面可以设置pod冗余的数量,k8s会严格保证启动的数量与设置一致,所以只需要一个进程监测Proxy的异常,并且把它干掉就可以了,k8s会自动拉起来一个新的proxy。

codis给这个进程起名叫codis-ha,codis-ha实时监测proxy的运行状态,如果有异常就会干掉,它包含了哨兵的功能,所以豌豆荚直接把哨兵去掉了。

但是codis-ha在Codis整个架构中是没有办法直接操作代理和服务,因为所有的代理和服务的操作都要经过dashboard处理。所以部署的时候会利用k8s的亲和性将codis-ha与dashboard部署在同一个节点上。

除了这些,codis自己开发了集群管理界面,集群管理可以通过界面化的方式更方便的管理集群,这个模块叫codis-fe,我们可以看一下这个界面。

最后就是redis客户端了,这个没什么好讲的,客户端是直接通过代理来访问后端服务的。

Redis Cluster原理

下面来看一下redis cluster的原理,它和codis不太一样,Codis它是通过代理分片的,但是Redis Cluster是去中心化的没有代理,所以只能通过客户端分片,它分片的槽数跟Codis不太一样,Codis是1024个,而Redis cluster有16384个,槽跟节点的映射关系保存在每个节点上,每个节点每秒钟会ping十次其他几个最久没通信的节点,其他节点也是一样的原理互相PING ,PING的时候一个是判断其他节点有没有问题,另一个是顺便交换一下当前集群的节点信息、包括槽与节点映射的关系等。客户端操作key的时候先通过分片算法算出所属的槽,然后随机找一个服务端请求。

但是可能这个槽并不归随机找的这个节点管,节点如果发现不归自己管,就会返回一个MOVED ERROR通知,引导客户端去正确的节点访问,这个时候客户端就会去正确的节点操作数据。

这是RedisCluster大概的原理,下面看一下Codis跟RedisCluster简要的区别。

Codis与RedisCluster的原理详解的更多相关文章

  1. I2C 基础原理详解

    今天来学习下I2C通信~ I2C(Inter-Intergrated Circuit)指的是 IC(Intergrated Circuit)之间的(Inter) 通信方式.如上图所以有很多的周边设备都 ...

  2. Zigbee组网原理详解

    Zigbee组网原理详解 来源:互联网 作者:佚名2015年08月13日 15:57   [导读] 组建一个完整的zigbee网状网络包括两个步骤:网络初始化.节点加入网络.其中节点加入网络又包括两个 ...

  3. 块级格式化上下文(block formatting context)、浮动和绝对定位的工作原理详解

    CSS的可视化格式模型中具有一个非常重要地位的概念——定位方案.定位方案用以控制元素的布局,在CSS2.1中,有三种定位方案——普通流.浮动和绝对定位: 普通流:元素按照先后位置自上而下布局,inli ...

  4. SSL/TLS 原理详解

    本文大部分整理自网络,相关文章请见文后参考. SSL/TLS作为一种互联网安全加密技术,原理较为复杂,枯燥而无味,我也是试图理解之后重新整理,尽量做到层次清晰.正文开始. 1. SSL/TLS概览 1 ...

  5. 锁之“轻量级锁”原理详解(Lightweight Locking)

    大家知道,Java的多线程安全是基于Lock机制实现的,而Lock的性能往往不如人意. 原因是,monitorenter与monitorexit这两个控制多线程同步的bytecode原语,是JVM依赖 ...

  6. [转]js中几种实用的跨域方法原理详解

    转自:js中几种实用的跨域方法原理详解 - 无双 - 博客园 // // 这里说的js跨域是指通过js在不同的域之间进行数据传输或通信,比如用ajax向一个不同的域请求数据,或者通过js获取页面中不同 ...

  7. 节点地址的函数list_entry()原理详解

    本节中,我们继续讲解,在linux2.4内核下,如果通过一些列函数从路径名找到目标节点. 3.3.1)接下来查看chached_lookup()的代码(namei.c) [path_walk()> ...

  8. WebActivator的实现原理详解

    WebActivator的实现原理详解 文章内容 上篇文章,我们分析如何动态注册HttpModule的实现,本篇我们来分析一下通过上篇代码原理实现的WebActivator类库,WebActivato ...

  9. Influxdb原理详解

    本文属于<InfluxDB系列教程>文章系列,该系列共包括以下 15 部分: InfluxDB学习之InfluxDB的安装和简介 InfluxDB学习之InfluxDB的基本概念 Infl ...

随机推荐

  1. C# RESTful API 访问辅助类

    REST 全称是 Representational State Transfer,有人说它是一种风格,并非一种标准,个人觉得挺有道理.它本身并没有创造新的技术.组件与服务,更像是告诉大家如何更好地使用 ...

  2. 【JDK基础】java基础的一些资料

    工具:https://blog.csdn.net/javazejian/article/details/72828483 类加载器:https://blog.csdn.net/X5fnncxzq4/a ...

  3. Gradle +HanLP +SpringBoot 构建关键词提取,摘要提取 。入门篇

    前段时间,领导要求出一个关键字提取的微服务,要求轻量级. 对于没写过微服务的一个小白来讲.有点赶鸭子上架,但是没办法,硬着头皮上也不能说不会啊. 首先了解下公司目前的架构体系,发现并不是分布式开发,只 ...

  4. 多语言应用性能监控系统:Elastic APM

    ▶ 概述 Elastic APM 是基于 Elastic Stack 构建的应用性能监控系统.通过 Elastic APM 可以监控应用程序,收集有关请求的响应时间.数据库查询.高速缓存调用.外部 H ...

  5. Android 蓝牙开发(2)——低功耗蓝牙

    低功耗蓝牙官方文档 本文章是参考官网,然后加入自己实践中的理解完成!没有看上一篇的读者,可以先阅读一下前一篇,这是一个系列. 官网地址:https://developer.android.com/gu ...

  6. Jenkins+GitLab+Docker+SpringCloud+Kubernetes实现可持续自动化微服务

    现有混合云平台的场景下,即有线下和线上的环境,又有测试与正式的场景,而且结合了Docker,导致打包内容有所区分,且服务的发布流程复杂起来,手工打包需要在编译阶段就要根据环境到处更改配置,因此纯手工发 ...

  7. WordPress教程之如何入门WordPress

    这篇文章将介绍如何设置 WordPress,并自定义其基本功能.WordPress 的安装包相对较小(低于 10 MB),非常易于安装和管理.为了托管自己的网站,你可以获得几个不同的选项. 你可以通过 ...

  8. 从无到有构建vue实战项目(五)

    八.错误总结(一) webpack打包项目识别子组件路径问题 之所以出现了这样的问题是因为在webpack打包项目时,未将此处的子组件路径正确识别: 将此处的carousel改为carousel.vu ...

  9. 【模拟】CF409C 【Magnum Opus】-C++

    题目背景 愚人节题目,题面似乎是一位名叫Nicolas Flamel的炼金术士用拉丁文写的某种物质的配方,结合谷歌尝试翻译了一下: 吾友: 哲人石所言不虚,人不可貌相,海不可斗量,唯努力得胜万象,亦无 ...

  10. CF39D Cubical Planet-C++

    银河系中没有你找不到的东西!有一颗形状为立方体的的行星正在绕着一颗形状为二十面体的恒星运转.现在我们让这颗行星的两个在同一条体对角线上的顶点置于(0,0,0)和(1,1,1)上.有两只苍蝇住在行星上. ...