Redis集群(一)

集群篇

主从同步

CAP的原理

  • 原理:C(一致)、A(可用性)、P(分区容忍性)

    分布式的节点在不同的机器上,如果网络不可达,那么就会出现网络分区。

    如果发生分区,两个节点就不会通信,一致性无法满足。

    CAP:在网络发生分区的是时候,一致性和可用性的两难全。

    如果发生网络分区,那么我们只能将系统设为不可用,停止系统的修改操作,直到服务恢复。

最终一致

Redis的主从并不是同步的,所以并不满足一致性,但是可以立即的响应,满足了可用。从节点会努力的弥补差距,主从网络恢复之后就会立即的进行同步。

增加同步

Redis的同步是指令流,主节点会将那些自己的状态修改性影响的指令记录在本地的内存buffer中,然后将buffer的数据同步到从节点中,并会向主节点反馈执行的位置。

假如网络状态不好,那么就会造成数据积压,数据并不会无限制的增加,buffer是一个环形的数组,如果积压太多就会造成后面的将覆盖,这个使用需要使用同步机制-----快照同步。

快照同步

快照同步是一个耗费资源的操作,他先将数据全部的存储到磁盘上,从节点将快照得到,然后清空内存,将其加载,加载结束通知主节点继续快照同步。

问题:如果buffer太小,或者是快照时间太长,就会造成数据会被覆盖,也会造成同步的问题。所以buffer的大小很重要。【他会进入死循环,这个不是很理解】

增加从节点

一个节点加入之后,需要一次快照同步,同步完成之后,在继续进行增加同步。

无盘复制

快照是一个IO操作,在SSD磁盘上,快照会很慢,系统在进行AOF的fsync时候,快照同步,fsync会推迟,影响主节点的效率。

所以Redis2.8之后是一个无盘复制,主服务器将数据直接的通过套接字将内容发送出去(从节点),它会一边的扫描内存,一边倒继续序列化,将数据传输出去,从节点将输几局存储磁盘中,在进行一次性加载。

Wait指令

Redis的复制是异步的,wait可以使得异步变为同步,确保系统强一致性,(Redis 3.0之后)

wait指令的操作需要两个参数,一个是从节点的个数,第二个是时间,等待n个节点的所有写操作同步之后,最多等t,如果t=0,那么就无限制的等待。

 


无论如何,如果只做缓存,那么就不关心,那么多,死掉了,重新启动就可以了。

 

Sentinel

如果深夜宕机,人工运维太操劳,高可用的设计。在发生故障自己主从切换。Redis官方提供Redis sentinel(哨兵)。它是由多个节点组成的,个别死了,还可以继续。

作用:监控主从节点健康,主节点挂掉,自动选择一个最优节点作为主节点,请求的步骤,先请求sentinel,sentinel告诉谁是主,然后在与主节点进行通信。主有故障,就会再次的请求sentinel,sentinel返回最新的主节点。

如果挂掉,主从复制会断开,客户端的连接也会断开,从新选择主节点,建立新的主从复制关系,待主节点活过来。

 

消息丢失

异步复制,不会达到100%无丢失,主从延迟越大,数据丢失就越严重,那么可以通过设置主从延迟的范围

min-slaves-to-write 1
min-slaves-max-lag 10

第一个参数设置,必须有一个从节点活着,否则就会停止外写服务。

第二个参数,也就是在10m内没有收到主从复制,那么主代表网络断开了。

 

sentinel的基本使用方法

客户端发现主节点的位置,sentinel的默认端口是26379,可以发现主节点只有一个,但是从节点可以有多个。

问题:如果主节点发生改变,从节点怎样知道节点发生了改变。

答案:在建立连接的时候,会进行主节点地址变更判断。

建立连接的时候,会去判断主节点的地址,然后和内存主节点进行比对,如果不一致,就会断开所有的连接,重新的选出新的节点,然后重新建立连接。

问题:如果主节点死不了,那么怎样主从切换呢?

答案:在处理命令的时候会捕获一个ReadOnlyError异常,这个异常就将所有的连接都关闭了。主从切换之后,将所有的主变为从,所有修改操作,都会抛出异常,如果没有修改操作,那么不排除异常也不会有什么影响。

 

Codis(分而治之)

大数据场景下,数据存储在内存中,那么又可以存储多少呢,内存太大导致rdb变大,导致同步时间变长。重新也会导致加载时间太长。单个的内存大小会受到限制,cpu的使用率。

大数据的情况下,可以使用redis集群进行操作,将总多的小redis结合起来使用,分布在总多的CPU上。

Codis是Redis集群的解决方案之一,它是一个中间件,客户端发送请求给codis,codis将其转发到后面的redis集群中,将数据返回给客户端。

codis挂载所有的redis节点,实现一个Redis集群,如果内存不足,就可以通过该增加redis来实现一个扩容需求。

它是无状态的,可以启动多个执行服务。

 

codis分片原理

codis负责将特定的key转发到Redis实例,如何管理这种关系?

默认是将其划分为1024个槽,对客户端的key先进行crc32运算hash,再将hsh值对1024这个整数进行取模得到一个余数,这个余数就是槽的位置。每个槽都会映射到后面的多个实例,codis会维护一个映射关系。,通过key对应槽,就对应了Redis实例。

槽的数量可以进行设置,默认是1024.

不同的codis之间槽位关系如何同步

如果将映射关系放在内存中,就无法在多个codis之间进行得到同步,所以需要一个专门的槽位来进行持久化槽位关系。槽位关系可以存储在zookeeper中。通过Dashboad进行监听,如果发生改变,监听到变化,会进行更新槽位之间的关系。

扩容

开始只有一个redis实例,1024个槽就会指向一个,然后一个redis就撑死了,所以需要多个。那么就加一个,对槽位进行调整,将一半槽位划分到新的redis上,

如何划分?????

Codis对redis进行了改造。增加SLOTSSCAN指令,可以变量槽下所有的key,扫描出带迁移的key,让将其迁移到新的Redis上。

问题:在迁移过程中,有请求??

那么就将其打在正在迁移的槽位上,因为它存在于新旧两个槽位上。【不是很理解,P133页】

自动均衡

新增实例,手动均衡太麻烦,codis可以自动均衡,在空闲的时候,观察每个redis实例对应槽的数量,自动进行迁移。

posted @ 2019-05-20 19:08  kwdeep  阅读(316)  评论(0编辑  收藏  举报