关于redis:redis-主从复制常见问题

一、读写拆散的问题

1.数据复制的提早  

读写拆散时,master会异步的将数据复制到slave,如果这是slave产生阻塞,则会提早master数据的写命令,造成数据不统一的状况  

解决办法:能够对slave的偏移量值进行监控,如果发现某台slave的偏移量有问题,则将数据读取操作切换到master,但自身这个监控开销比拟高,所以对于这个问题,大部分的状况是能够间接应用而不去思考的。

  2.读到过期的数据 

产生起因:  

redis的从库是无奈被动的删除曾经过期的key的,所以如果做了读写拆散,就很有可能在从库读到脏数据

例子重现

主Redis

setex test 20 1
+OK
get test
$1
1
ttl test
:18

从Redis

get test
$1
1
ttl test
:7

以上都没问题,然而过几秒再看从Redis

ttl test
:-1
get test
$1
1

test这个key曾经过期了,然而还是能够获取到test的值。

在应用Redis做锁的时候,如果间接取读从库的值,这就有大问题了。 

二、为什么从库不删除数据?

redis删除过期数据有以下几个策略:  

  1. 惰性删除:当读/写一个曾经过期的key时,会触发惰性删除策略,间接删除掉这个过期key,很显著,这是被动的!  
  2. 定期删除:因为惰性删除策略无奈保障冷数据被及时删掉,所以 redis 会定期被动淘汰一批已过期的key。(在第二节中会具体阐明)  
  3. 被动删除:以后已用内存超过maxMemory限定时,触发被动清理策略。被动设置的前提是设置了maxMemory的值

    int expireIfNeeded(redisDb *db, robj *key) { 
     time_t when = getExpire(db,key); 
     
     if (when < 0) return 0; /* No expire for this key */ 
     
     /* Don't expire anything while loading. It will be done later. */ 
     if (server.loading) return 0; 
     
     /* If we are running in the context of a slave, return ASAP: 
     * the slave key expiration is controlled by the master that will 
     * send us synthesized DEL operations for expired keys. 
     * 
     * Still we try to return the right information to the caller, 
     * that is, 0 if we think the key should be still valid, 1 if 
     * we think the key is expired at this time. */ 
     if (server.masterhost != NULL) { 
     return time(NULL) > when; 
     } 
     
     /* Return when this key has not expired */ 
     if (time(NULL) <= when) return 0; 
     
     /* Delete the key */ 
     server.stat_expiredkeys++; 
     propagateExpire(db,key); 
     return dbDelete(db,key); 
    }

通过以上源码发现,4行:没有设置超时工夫,则不删;7行:在”loading”时不删;16行:非主库不删;21行未到期不删。25行同步从库和文件。

所以说,在从库执行被动删除操作,或者通过惰性删除的形式触发删除key的操作,最终都不会执行胜利。起因就在下面的第16行代码。 

解决办法:  
1)通过一个程序循环便当所有的key,例如scan  
2)通过ttl判断  
3)降级到reidis3.2 

主从配置不统一

这个问题个别很少见,但如果有,就会产生很多诡异的问题

例如:

1.maxmemory配置不统一:这个会导致数据的失落  

起因:例如master配置4G,slave配置2G,这个时候主从复制能够胜利,但,如果在进行某一次全量复制的时候,slave拿到master的RDB加载数据时发现本身的2G内存不够用,这时就会触发slave的maxmemory策略,将数据进行淘汰。更可怕的是,在高可用的集群环境下,如果咱们将这台slave升级成master的时候,就会发现数据曾经失落了。 

2.数据结构优化参数不统一(例如hash-max-ziplist-entries):这个就会导致内存不统一  

起因:例如在master上对这个参数进行了优化,而在slave没有配置,就会造成主从节点内存不统一的诡异问题。

三、躲避全量复制

redis复制有全量复制和局部复制两种,而全量复制的开销是很大的。那么咱们如何尽量去躲避全量复制。

1.第一次全量复制

某一台slave第一次去挂到master上时,是不可避免要进行一次全量复制的,那么,咱们如何去想方法升高开销呢?  
计划1:小主节点,例如咱们把redis分成2G一个节点,这样一来,会减速RDB的生成和同步,同时还能够升高咱们fork子过程的开销(master会fork一个子过程来生成同步须要的RDB文件,而fork是要拷贝内存快的,如果主节点内存太大,fork的开销就大)。  

计划2:既然第一次不能够防止,那咱们能够选在集群低峰的工夫(凌晨)进行slave的挂载。

2.节点RunID不匹配

例如咱们主节点重启(RunID发生变化),对于slave来说,它会保留之前master节点的RunID,如果它发现了此时master的RunID发生变化,那它会认为这是master过去的数据可能是不平安的,就会采取一次全量复制  

解决办法:对于这类问题,咱们只有是做一些故障转移的伎俩,例如master产生故障宕掉,咱们选举一台slave晋升为master(哨兵或集群) 

3.复制积压缓冲区有余  

master生成RDB同步到slave,slave加载RDB这段时间里,master的所有写命令都会保留到一个复制缓冲队列里(如果主从间接网络抖动,进行局部复制也是走这个逻辑),待slave加载完RDB后,拿offset的值到这个队列里判断,如果在这个队列中,则把这个队列从offset到开端全副同步过去,这个队列的默认值为1M。而如果发现offset不在这个队列,就会产生全量复制。  

解决办法:增大复制缓冲区的配置 rel_backlog_size 默认1M,咱们能够设置大一些,从而来加大咱们offset的命中率。这个值,咱们能够假如,个别咱们网络故障工夫个别是分钟级别,那咱们能够依据咱们以后的QPS来算一下每分钟能够写入多少字节,再乘以咱们可能产生故障的分钟就能够失去咱们这个现实的值。 

四、躲避复制风暴

什么是复制风暴?举例:咱们master重启,其master下的所有slave检测到RunID发生变化,导致所有从节点向主节点做全量复制。只管redis对这个问题做了优化,即只生成一份RDB文件,但须要屡次传输,依然开销很大。  

1.单主节点复制风暴:主节点重启,多从节点全量复制

解决:更换复制拓扑如下图:

  1.咱们将原来master与slave两头加一个或多个slave,再在slave上加若干个slave,这样能够分担所有slave对master复制的压力。(这种架构还是有问题:读写拆散的时候,slave1也产生了故障,怎么去解决?) 

 2.如果只是实现高可用,而不做读写拆散,那当master宕机,间接降职一台slave即可。 

2.单机器复制风暴:机器宕机后的大量全量复制,

如下图:

当machine-A这个机器宕机重启,会导致该机器所有master下的所有slave同时产生复制。(劫难)

解决:  

1.主节点扩散多机器(将master扩散到不同机器上部署)  

2.还有咱们能够采纳高可用伎俩(slave降职master)就不会有相似问题了。 
 

常见的数据库集群架构如何?

答: 一主多从,主从同步,读写拆散。

 如上图:  
(1)一个主库提供写服务  
(2)多个从库提供读服务,能够减少从库晋升读性能  
(3)主从之间同步数据

画外音:任何计划不要忘了本心,加从库的本心,是晋升读性能。 

为什么会呈现不统一?

答:主从同步有时延,这个时延期间读从库,可能读到不统一的数据。

 如上图:  
(1)服务发动了一个写申请  
(2)服务又发动了一个读申请,此时同步未实现,读到一个不统一的脏数据  (3)数据库主从同步最初才实现

画外音:任何数据冗余,必将引发一致性问题。

如何防止这种主从延时导致的不统一

?答:常见的办法有这么几种。
计划一:疏忽任何脱离业务的架构设计都是耍流氓,绝大部分业务,例如:百度搜寻,淘宝订单,QQ音讯,58帖子都容许短时间不统一。
画外音:如果业务能承受,最推崇此法。 如果业务可能承受,别把零碎架构搞得太简单。 

计划二:强制读主

 如上图:  
(1)应用一个高可用主库提供数据库服务 
 
(2)读和写都落到主库上 

(3)采纳缓存来晋升零碎读性能

这是很常见的微服务架构,能够防止数据库主从一致性问题。 

计划三:选择性读主
强制读主过于粗犷,毕竟只有大量写申请,很短时间,可能读取到脏数据。 

有没有可能实现,只有这一段时间,可能读到从库脏数据的读申请读主,平时读从呢?

 能够利用一个缓存记录必须读主的数据。

 如上图,当写申请产生时:

(1)写主库

(2)将哪个库,哪个表,哪个主键三个信息拼装一个key设置到cache里,这条记录的超时工夫,设置为“主从同步时延”

画外音:key的格局为“db:table:PK”,假如主从延时为1s,这个key的cache超时工夫也为1s。 
 

如上图,当读申请产生时:

这是要读哪个库,哪个表,哪个主键的数据呢,也将这三个信息拼装一个key,到cache里去查问,如果, 
 
(1)cache里有这个key,阐明1s内刚产生过写申请,数据库主从同步可能还没有实现,此时就应该去主库查问  

(2)cache里没有这个key,阐明最近没有产生过写申请,此时就能够去从库查问以此,保障读到的肯定不是不统一的脏数据。

 总结数据库主库和从库不统一,常见有这么几种优化计划:
(1)业务能够承受,零碎不优化
(2)强制读主,高可用主库,用缓存进步读性能
(3)在cache里记录哪些记录产生过写申请,来路由读主还是读从

哨兵是什么?

哨兵是Redis高可用(HA)的解决方案.它是一种非凡的模式.只不过它不对外提供服务.

组成:
Sentinel是一个零碎(或者说是集群)它是由一个(多个实例)组成,采纳哨兵集群的起因是避免哨兵的误判.(单个哨兵的话会因为主节点过大或者因为网络起因造成误判)

为什么须要Redis哨兵?

Redis有主从模式(客户端写操作发送到主节点,读操作发送到从节点),如果这时候主节点呈现故障,不能对外提供服务了.这个时候咱们须要做哪几个操作能力失常的对外提供不间断服务.

1.咱们不知什么主节点挂了(最次要的问题)

2.手工把从库设置为主库

3.客户端还须要批改新的主库地址

Redis如何提供无间断对外提供服务?

首先咱们理解下Redis哨兵三个定时工作

1.监控(主节点是否下线)

2.选主(抉择一个新的主节点)

3.告诉(告诉客户端和其余从节点,哨兵)

监控(三个定时工作)

INFO命令

第一个定时工作: 每10s每个哨兵对master和slave节点发送INFO命令(获取最新的拓扑构造)

订阅频道

第二个定时工作 每2秒每个sentinel通过master节点的channel替换信息

每个哨兵节点岁会向频道发送对于(__sentinel__: hello)判断信息
也会订阅其余哨兵节点对于主节点的判断

PING命令(检测)

每隔1秒, 每个Sentinel节点会向主节点、 从节点、 其余Sentinel节点发送一条ping命令做一次心跳检测, 来确认这些节点以后是否可达

Redis判断主节点下线(主观 主观)

Redis 主节点下线的过程分为 主观下线,主观下线
在这里如果你的哨兵只有一个会间接下线就行故障转移,如果是多个会进行询问后(少数哨兵就决定下线)
才会就行故障转移。失常状况下都会有多个哨兵。
主节点下线步骤:
1.当哨兵PING命令发现,有节点响应超时,会把节点标记为主观下线.
2.如果主观下线节点为主节点时,会询问其余哨兵,当其余哨兵也断定主观下线(超过半数哨兵认为主观下线)
3.哨兵零碎会抉择一个哨兵把其中的一个从节点降级为主节点,并告诉客户端.

【腾讯云】轻量 2核2G4M,首年65元

阿里云限时活动-云数据库 RDS MySQL  1核2G配置 1.88/月 速抢

本文由乐趣区整理发布,转载请注明出处,谢谢。

您可能还喜欢...

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据