快牵着我的袜子

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

一、主从复制

  1、命令

    PSYNC:该命令具有完整重同步和部分重同步。

      完成重同步:通过主服务器创建并发送RDB文件,以及向从服务器发送保存在缓冲区那里面的写命令来进行同步。

      部分重同步:当从服务器在断线重连主服务器之后,则主服务器将主从服务器断开期间执行的写命令发送给从服务器。从服务器接收并执行这些写命令。

      部分重同步实现:

      1)主服务器的复制偏移量和从服务器的复制偏移量

        1、主服务器每次向从服务器传播N个字节的数据时,就将自己的复制偏移量的值加上N

        2、从服务器每次接收到主服务器传播来的N个字节的数据时,就将自己的复制偏移量的值加上N

        通过对比主从服务器的偏移量可以确定主从服务器状态是否一致。

      2)主服务器的复制积压缓冲区

        主服务器维护的一个固定长度,先进先出队列,默认大小1MB。

        当主服务器进行命令传播时,它不仅将写命令发送给所有从服务器,还会讲写命令入队到复制积压缓冲区。

        当从服务器重连时,从服务器通过PSYNV命令将自己的复制偏移量offset发送给主服务器,主服务器有以下抉择:

        1、如果offset偏移量之后的数据,仍然存在于复制缓冲区,那么主服务器将对从服务器执行部分重同步操作

        2、相反,如果不存在,则执行完整的重同步操作。

      3)服务器的运行ID(run ID)

        1、每个redis服务器,无论主服务器还是从服务器,都会有自己的运行ID

        2、运行ID在服务器启动时自动生成,由40个随机的十六进制字符组成。

        主服务器根据从服务器发送过来的运行ID,决定执行部分重同步还是完整重同步。

  2、复制实现

    1)从服务器设置主服务器的地址和端口:SLAVEOF

    2)建立套接字连接:从服务器根据IP和端口,创建连接。

    3)发送ping命令:检查读写状态;检查主服务器能否正常处理命令请求

    4)身份验证

    5)发送端口信息:REPLCONF listening-port <port-number> 向主服务器发送从服务器的监听端口。

    6)同步:从服务器向主服务器发送PSYNC命令,执行同步操作。

    7)命令传播

二、哨兵(Sentinel)

  1、概念

    有一个或多个Sentinel实例组成的Sentinel系统,可以监视任意多个主服务器,以及这些主服务器属下的所有从服务器,并在主服务器

  进入下线状态时,自动通过投票方法,将主服务器属下的某个从服务器升级为新的主服务器。

  2、启动并初始化Sentinel

    $ redis-sentinel /path/to/you/sentinel.conf  或者通过命令 $ redis-server /path/to/your/sentinel.conf --sentinel

    1)初始化服务器

      Sentinel本质是一个运行在特殊模式下的Redis服务器,但是初始化是与普通的服务器不同,不载入RDB文件或者AOF文件。

    2)将普通redis服务器使用的代码替换成Sentinel专用代码

    3)初始化Sentinel状态

      初始化Sentinel状态中的masters字典,里面记录了所有呗Sentinel监视的主服务器相关信息。

    4)根据给定的配置文件,初始化Sentinel的监视主服务器列表

      初始化上面提到的字典。

    5)创建连向主服务器的网络连接

      Sentinel会创建两个连向主服务器的异步网络连接

      1、命令连接:向主服务器发送命令,并接收命令回复

      2、订阅连接,订阅主服务器的_sentinel_:hello频道

      当Sentinel发现有新的从服务器出现时,会创建连接到从服务器的命令连接和订阅连接。

  3、选举领头Sentinel

    当一个主服务器被判断客观下线时,监视这个下线主服务器的各个Sentinel会进行协商,选举出一个领头Sentinel,并由领头Sentinel对下线主服务器

  执行故障转移操作:

    1、设置规则:

      1)所有sentinel(源)都向另一个sentinel(目的)发送命令,要求目的将自己设置为局部sentinel(源)

      2)先到先得,最先向目标Sentinel发送设置要求的源Sentinel将成为Sentinel的局部Sentinel,

      3)如果某个sentine被半数以上的sentinel设置为局部领头,则这个sentinel成为领头sentinel。

      4)如果规定时间没有选举出,则再次选举。

  4、故障转移

    领头sentinel在已下线主服务器属下的所有从服务器中,挑选出一个状态良好、数据完整的从服务器,将其转换为主服务器。

    所有从服务器都保存在一个列表里面,将通过以下规则进行过滤:

    1)删除下线或者断线的从服务器

    2)删除类表中5秒内没有回复过领头sentinel的INFO命令的从服务器

    3)删除与已下线主服务器连接断开超多规定时间的从服务器。

    4)选举优先级高的从服务器

    5)如果有多个相同优先级的从服务器,则按照从服务器的复制偏移量,挑选出偏移量最大的从服务器

    6)如果还有多个,则挑选运行ID最小的从服务器。

三、集群

  1、节点

    1)一个redis集群通常由多个节点(每个节点就是一个redis服务器)组成,在刚开始的时候,每个节点都是相互独立的,

     都处于只包含自己的集群里,需要将各个独立的节点连接起来,才能构成一个包含多个节点的集群

    2)连接命令:CLUSTER MEET <ip> <port>  发送命令后节点进行握手,握手成功时,节点就会将ip和port所指定的节点添加到自己的集群中。

    3)启动节点:根据配置:cluster-enabled是否为yes来决定是否开启服务器的集群模式。

    4)握手过程(A->B):

      1、节点A为B创建一个clusterNode结构,并将该结构添加到自己的clusterStater.nodes字典里

      2、A根据CLUSTER MEET命令给定的IP和port,向B发送一条MEET消息

      3、B接收到A的MEET消息,为A创建一个clusterNode结构,并添加到自己的字典里

      4、B向A发送一条PONG消息

      5、A接收到B的PONG消息,发送一条PING消息。

      至此握手完成,之后A会将节点B的信息通过Gossip协议传播给集群的其他节点,让其他节点和B进行握手,

      经过一段时间之后,节点B会被集群中的所有节点认识。

  2、槽指派

      redis集群通过分片的方式来保存数据库中的键值对:集群的整个数据库被分为16384个槽(slot),数据库中的每个键都属于这16384个slot的其中一个,集群中的每个

    节点可以处理0个或最多16384个slot。

    1)指派命令:CLUSTER ADDSLOTS <slot> [slot]  命令可以指派一个或多个slot给节点负责。

    2)slots属性:每个节点都包含一个slots属性,其是一个二进制数组,包含16384个字节,以0为起始索引,16383为终止索引。节点根据索引上的二进制位的值

      来判断是否负责处理槽i,如果二进制位上的值为1,则负责处理该槽,为0则不负责处理该槽。

      节点之间通过传播节点的槽指派信息,获知其他节点的槽指派信息,并将其保存在为其创建的slusterNode节点里。

  3、集群中执行命令:

    1)执行过程:客户端向某个节点发起命令请求,如果该节点保存,则回复;否则返回一个MOVED错误,并直营客户端转向正确节点,并再次发送之前想要执行的命令。

        MOVED错误格式:MOVED <slot> <ip>:<port>

    2)计算键属于哪个槽:

      

def slot_number(key)
    return CRC16(key) & 16383

    先计算CRC-16校验和,之后&16383,确定键key的槽号。

    3)节点数据库的实现

      集群节点数据库保存键值对以及键值对过期时间的方式,和单机服务器相同。区别在于,节点只能使用0号数据库,单机数据库没有限制。

  4、重新分片

    redis集群重新发片操作由redis的集群管理软件redis-trib负责执行,redis-trib通过向源节点和目标节点发送命令来进行重新分片

    1)命令:

      1、redis-trib对目标节点发送 CLUSTER SETLOT  <slot> IMPORTING <source_id>:让目标节点准备好从源节点导入(import)属于槽slot的键值对。

      2、redis-trib对源节点发送 CLUSTER SETLOT  <slot> MIGRATING <target_id>:让源节点准备好将属于槽slot的键值对迁移至目标节点。

      3、redis-trib对源节点发送 CLUSTER GETKEYSINSLOT <slot> <count>:获得最多count哥属于槽slot的键值对的键名

      4、对于步骤三获得的每个键名,redis-trib对源节点发送MIGRATE <target_ip> <target_port> <key_name> 0 <timeout>:将被选中的键原子地从源节点迁移至目标节点。

      5、重复步骤三和步骤四,将所有属于槽的键值对进行迁移。

      6、向任意一个节点发送CLUSTER SETSLOT <slot> NODE <target_id>:将槽slot指派给目标节点这个信息,告知这个节点,这一指派信息会通过消息传播至整个集群,集群的其他节点就会获知这一消息。

  5、复制和故障转移

    redis集群中的节点分为主节点和从节点,主节点负责处理槽,从节点用于复制某个主节点,并在主节点下线时,代替主节点继续处理命令。

    1)设置从节点命令:CLUSTER REPLICATE <node_id>:可以让接收命令的节点成为node_id的所指定的从节点,并开始对主节点进行复制

    2)故障检测:集群中的每个节点都会定期向集群中的其他节点发送ping消息,如果目标没有在规定时间返回pong消息,则被标记为疑似下线。如果半数以上节点将该节点标记为疑似下线,则目标主节点表标记为已下线。

      例如:有四个主节点7000,7001,7002,7003。如果7001收到主节点7002、主节点7003发送的主节点7000疑似下线消息,并且自己也认为该节点下线。

      那么主节点7001将在集群中广播一条主节点7000的FAILL消息,所有收到的消息的节点将主节点7000标记为已下线。

    3、故障转移

      1)复制下线主节点的所有从节点里面,会有一个从节点被选中

      2)被选中的节点执行SLAVEOF no one命令,成为新的主节点

      3)新的主节点会侧小所有对已下线主节点的槽指派,并将槽全部派给自己

      4)新的主节点广播一条pong消息,告知自己接管工作。

      5)新主节点开始工作

    4、选举新的主节点

      1)集群里每个负责处理槽的主节点都有一次投票机会

      2)从节点发现自己正在复制的主节点进入下线状态,会向集群中广播,要求接收到消息的并且具有投票权的主节点向这个从节点投票

      3)具有投票权的主节点向第一个发送给他的消息的从节点投票

      4)当一个从节点收到N/2+1张支持票时,则该从节点会当选为新的主节点。

      5)如果一个配置纪元(一轮投票)里没有收集到足够多的选票,则再次进行。

      

      选举新节点的方法和选举领头sentinel的方法相似,两者都给予RAFT算法的领头选举方法实现。

 

四、常见问题

  5.1 消息队列是什么?作用是什么?

  5.2 redis 是怎么实现消息队列的?缺点是什么?缺点有什么解决方式?

  5.3 redis 消息队列如何保证消息不丢失

  5.3 如何保证缓存与数据库一致性?

     

 

posted on 2022-04-01 17:41  快牵着我的袜子  阅读(154)  评论(0编辑  收藏  举报