redis如何实现主从同步

redis实现主从同步分为两种:全量同步增量同步:第一次连入集群的slave需要进行全量同步,那些断开后重连的slave需要进行增量同步

每个redis都有自己的replid,他们是master的标识,在尚未搭建集群之前,每个redis都是master,因此大家都有各自不同的replid

repl_backlog中会写入所有操作的命令,写操作会导致offset的增大,并且主从的offset会保持一致大小

全量同步:

  如果是一个新的slave连入集群,那我们就需要进行全量同步。如何判断这个slave是断后重连还是新来的呢?我们可以通过上述replid。

  slave连入集群时,会尝试向master发送psync,其中携带自己的replid。如果replid与master不相同,那么就可以说明他是新来的。除此以外,如果offset偏移丢失,已经无法通过增量同步恢复数据,也需要进行全量同步

  这时我们由master执行bgsave,生成一份RDB,再将RDB发送给slave。

  这里又翻了翻之前的笔记,1.什么是bgsave,2.为什么不用save:这两个问题的答案是:bgsave是异步的,save是同步的。使用save会造成阻塞问题。学完MQ,再加上了解了ws,我对bgsave有了新的印象

增量同步:

  master在与slave建立连接之后会生成一个repl_backlog,其中会记录master的操作。我们在master中定义了offset(偏移值),每当写入一条命令,offset就会增加,理想情况下slave的offset也会增加。一旦连接断开,主从节点的offset就会不一致。因此如果我们的slave是断开重连,需要携带offset,来告诉master他需要从哪里开始恢复数据

repl_backlog的一些问题:repl_backlog是一个环形结构,也就是说一旦从节点长时间宕机再恢复,只能进行全量同步,因为offset已经对不齐了

主从同步优化方案:

  1.   在master上启用无磁盘复制,避免大量磁盘IO。但是会加剧网络传输的负担:repl-diskless-sync yes
  2.   redis单节点不要太大,这样才是在根本上减少磁盘IO。。黑马说不要超过8G,超了可以用类似微服务的方案多建几个redis集群分离用
  3.   适当提高repl_backlog大小,尽可能避免全量同步
  4.   适当限制slave节点数量,可以采用主从从链式结构,减少master压力(本质上从节点依旧只能读,但是他能从别的从节点同步数据)。这个方法会降低时效性

之前学过一次redis,这个主从同步的机制的问题有哪些呢?

1.主节点挂了没有选新的主节点,直接不能进行写数据了,而且这样做主机鸭梨巨大。按照我的记忆来说,这里我们需要增设哨兵sentinel,让他来和主节点定时进行心跳链接,一定主节点超时未响应,这时就会选举一个新的主节点,而这又衍生了新的问题:万一主节点其实没挂,那不就成了有两个主节点了吗。后续就推出了分片集群的设置,我记得好像是每一个节点都可以读写,并且他们都有后备小弟,主节点挂了小弟顶上,主节点恢复的时候和小弟关系反转一下就好了

 

哨兵sentinel方案:

  •   哨兵的作用:1.监控集群健康状态,2.故障转移,选新的master,3.通知
  •   如果判断master是否健康:每秒向master ping一下,一个哨兵没收到pong,那么他会认为master是主观下线,如果超过quorum都没有收到,那就是客观下线,该换master了。quorom由我们设置大小,数值最好是超过哨兵的一半
  •   故障转移:通过一系列方案抉择出新的master,让其执行slaveof no one,然后让所有slave都slaveof新的master,修复故障问题后,老的master也执行slaveof

 

redistemplate怎么连接集群:

配置的时候指定哨兵和集群名

spring:
  redis:
    sentinel:
      master: hmaster # 集群名
      nodes: # 哨兵地址列表
        - 192.168.150.101:27001
        - 192.168.150.101:27002
        - 192.168.150.101:27003

配置读写分离的bean,这里的bean用的是最优策略:先从slave里读,slave实现没有读的了才用master读

@Bean
public LettuceClientConfigurationBuilderCustomizer clientConfigurationBuilderCustomizer(){
    return clientConfigurationBuilder -> clientConfigurationBuilder.readFrom(ReadFrom.REPLICA_PREFERRED);
}

 

posted on 2024-05-16 21:56  天启A  阅读(37)  评论(0编辑  收藏  举报

导航