关于redis:Redis总结篇下

主从复制

主从复制是指将一台Redis服务器的数据,复制到其余的Redis服务器,前者称为主节点,后者称为从节点。

数据的复制是单向的,只能从主节点到从节点。
主节点以写为主,从节点以读为主。

  • 默认状况下,每台Redis服务器都是主节点。
  • 一个主节点能够有多个从节点
  • 一个从节点只能有一个主节点

为什么要主从复制

  • 主从复制实现了数据的热备份
  • 故障复原,当主节点呈现问题,服务能够由从节点提供
  • 负载平衡,尤其是在写少读多的场景下,通过多个节点分担读负载
  • 主从复制是高可用的基石

主从复制的外围机制

  1. Redis采纳异步形式复制数据到slave节点,Redis2.8开始,slave node会周期性地确认本人每次复制的数据量
  2. 一个master node能够配置多个slave node
  3. slave能够连贯其余的slave
  4. slave在复制的时候,不会阻塞master失常工作
  5. slave在复制的时候,不会阻塞本人的查问操作,复制实现后加载数据时会暂停对外服务

全量复制|增量复制

残缺同步:

当一个Redis服务器接管到replicaof命令,开始对另一个服务器进行复制的时候,主服务器会进行如下操作:

  • 主服务器bgsave生成一个RDB,缓存区存储bgsave命令之后的写命令
  • 主通过套接字传RDB给从
  • 从接管载入RDB文件
  • 主再把缓存区的写命令发送给从

主机中的所有信息和数据,都会主动被从机备份保留。

全量复制:slave服务在接管到数据库文件数据后,将其存盘并加载到内存中
增量复制:master持续将新的所有收集到的批改命令顺次传给slave,实现同步

外围原理

Slave启动胜利后,会发送一个psync同步命令给master。

如果这是slave首次连贯到master,会触发一次full resynchronization 全量复制。master启动一个后盾线程,生成RDB快照,并且将新收到的写命令缓存在内存中。

master会将RDB发送给slave,slave会先写入本地磁盘,而后再从磁盘加载到内存中,接着master会将内存中的缓存的写命令发送到slave,slave也会同步这些数据。

如果slave和master断开连接会主动重连,连贯之后master仅会复制给slave局部短少的数据。

断点续传

从Redis2.8开始,就反对主从复制的断点续传,如果主从复制过程中,断开了连贯,能够接着上次复制的中央持续复制上来。
master会在内存中保护一个backlog,master和slave都会保留一个replica offset还有一个master run id, offset就是保留在backlog中的,如果master和slave网络连接断掉了,slave会让master从上次replica offset开始持续复制,如果没有找到对应的offset,那么就会执行一次 resynchronization。

无磁盘化复制

master在内存中创立RDB,而后发送给slave,不会在本人本地落地磁盘了。只须要在配置文件中开启repl-diskless-sync yes

如果主机宕机了

主机宕机,群龙无首,如果本台服务器想当老大,能够执行如下命令:

redis> slaveof no one

应用整个命令让本人变成主机,其余从机还是要手动抉择它作为老大。
但如果这个时候,老大又好了,,,,老大也不是老大了,还得手动改回去

哨兵模式

哨兵模式就是主动抉择老大的模式。
Redis从2.8开始正式提供了Sentinel(哨兵)架构来解决这个问题。

哨兵模式是一种非凡的模式,首先Redis提供了哨兵的命令,哨兵是一个独立的过程,作为过程,它会独立运行,其原理是哨兵通过发送命令,期待Redis服务器响应,从而监控运行的多个Redis实例。

Redis哨兵主备切换的数据失落问题

导致数据失落的两种状况

主备切换的过程,可能导致数据失落:

  • 异步复制导致的数据失落
    因为master-slave的复制是异步的,所以可能有局部数据还没复制到slave,master就宕机了,此时这部分数据就失落了
  • 脑裂导致的数据失落
    脑裂,也就是说,某个master所在机器忽然脱离了失常的网络,跟其余slave机器不能连贯,但实际上master还运行着。哨兵认为master宕机,从新选了一个,集群中有两个master。
    尽管某slave变成master,但可能客户端还没来得及切换到新的master,还持续向旧master写数据。旧master复原的时候,会作为slave,本人的数据被清空,新master没有前面客户端写入的数据,所以这部分数据失落了。

数据失落的解决方案

进行如下配置:

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

示意要求至多有1个slave,数据复制和同步的提早不能超过10秒
一旦所有的slave,数据复制和同步的提早都超过了10秒钟,master就不会再接管任何申请了

缩小异步复制数据的失落
有了min-slaves-max-lag配置,就能够确保说,一旦slave复制数据和ack延时过长,就认为可能master宕机后损失的数据太多了,那么就回绝写申请,这样能够把master宕机时因为数据未同步到slave导致的数据失落升高的可控范畴内。

缩小脑裂的数据失落
如果一个master呈现了脑裂,跟其余slave丢了连贯,那么下面两个配置能够确保说,如果不能持续给指定数量的slave发送数据,而且slave超过10秒没有给本人ack音讯,那么就间接回绝客户端的写申请。因而在脑裂场景下,最多失落10秒数据。

启动Sentinel

用户须要在配置文件中指定想要被Sentinel监督的主服务器,并且Sentinel也须要在配置文件中写入信息以记录主从服务器的状态。

$> redis-sentinel sentinel.conf 
//配置文件门路看具体的,也可能是/etc/sentinel.conf

Sentinel配置文件须要蕴含以下选项:

sentinel monitor <master-name> <ip> <port> <quorum>
  • master-name: 指定主服务器的名字
  • quorum: 判断这个主服务器下线所需的Sentinel数量

当Sentinel开始监督一个主服务器之后,就会去获取被监督主服务器的从服务器名单,并依据名单对各个从服务器施行监督,整个过程是齐全主动的,所以用户只需输出待监督主服务器的地址就能够了。

Sentinel会对每个被监督的主从服务器施行心跳检测,记录各个服务器的在线状态、响应速度等信息,当Sentinel发现被监督的主服务器进入下线状态时,就会开始故障转移。

redis-sentinel是一个运行在非凡模式下的Redis服务器,
也能够应用:
redis-server sentinel.conf --sentinel去启动一个sentinel

一个Sentinel能够监督多个主服务器,
在配置文中指定多个 sentinel monitor选项,
给不同的主机设置不同的名字

新主机筛选规定

设置从服务器优先级:
配置文件里的replica-priority

  • 默认值100,值越小优先级越高。
  • 0示意永远不会被选为主服务器。

新主机的筛选规定:

先剔除不符合条件的从服务器

  • 否决曾经下线、长时间没用回复心跳检测疑似下线的服务器
  • 否决长时间没有与主机通信,数据状态过期的服务器
  • 否决优先级为0的服务器

依据以下规定,在残余的当中选

  • 优先级最高的从服务器
  • 等同优先级复制偏移量最大的服务器
  • 以上都雷同选运行ID最小的

Sentinel网络

只抉择一个哨兵对Redis服务进行监控,可能会呈现问题,能够应用多个哨兵进行监控,各个哨兵之间还能够相互监控,这样就造成了多哨兵模式。

假如主服务器宕机,哨兵1查看到了这个后果,但他不会马上进行failover(故障转移)过程,仅仅只是哨兵1主观的认为主服务器不可用,这个景象称为主观下线。当前面的哨兵也检测到主服务器不可用,并且数量达到肯定值时,哨兵之间就会进行一次投票,投票的后果由一个哨兵发动,进行failover(故障转移)操作。切换胜利后,就会告诉公布订阅模式,让各个哨兵把本人监控的从服务器实现切换主机,这个过程称为主观下线。

当Sentinel网络中的其中一个Sentinel认为某个主服务器曾经下线时,它会将这个主服务器标记为主观下线,而后询问其余的Sentinel是否也将这个主服务器标记成了主观下线(sdown)
当这个批准主机下线的数量达到配置中设置的quorum指定的数量时,将主服务器标记为主观下线(odown)

哨兵集群的主动发现机制

哨兵相互之间的发现,是通过Redis的pub/sub零碎实现的。
每个哨兵都会往__sentinel__:hello这个channel里发送一个音讯,这时候所有其余哨兵都能够生产到这个音讯,并感知到其余哨兵的存在。

每隔两秒钟,每个哨兵都会往本人监控的某个master+slaves对应的__sentinel__:hello channel里发送一个音讯,内容是本人的host、ip、runid还有对这个master的监控配置。

每个哨兵也会去监听本人监控的每个master+slaves对应的__sentinel__hello channel,而后去感知到同样在监听这个master+slaves的哨兵的存在。

每个哨兵还会跟其余哨兵替换对master的监控配置,相互过程监控配置的同步。

Sentinel治理命令

获取所有被监督主服务器的信息

redis> sentinel masters

获取指定被监督主服务器的信息

redis> sentinel master <master-name>

获取被监督主服务器的从服务器信息

redis> sentinel slaves <master-name>

获取其余Sentinel的相干信息

redis> sentinel sentinels <master-name>

重置主服务器状态

sentinel reset <pattern>

强制执行故障转移

sentinel failover <master-name>

查看可用Sentinel的数量

sentinel ckquorum <master-name>

集群 ✍

Redis集群是Redis 3.0版本开始正式引入的性能,带来了在线扩大Redis零碎读写性能的能力。

根本个性

  • 提供主从复制性能、Sentinel性能,局部master不可用还是能够持续工作
  • 分片和重分片,Redis集群会将整个数据空间划分为16384(slot)来实现数据分片,集群中的各个主节点会别离负责解决其中的一部分
  • 集群采纳无代理模式,客户端发送的命令会间接交给节点执行

Redis cluster间接集成了replication和sentinel的性能,所以具备高可用性,主备替换原理也基本上是统一的。

在Redis cluster架构下,每个Redis要凋谢两个端口号,比方一个是6379,另一个是加1万的端口号,16379。
16379端口号是用来进行节点间通信的,也就是cluster bus的货色。
cluster bus的通信,用来进行故障检测、配置更新、故障转移受权。cluster bus用了另外一种二进制的协定,gossip协定,用于节点间高效数据交换。

搭建集群

搭建集群有两种办法:

  • 应用源码附带的集群主动搭建程序
  • 配置文件手动搭建集群

F1 主动搭建

create-cluster程序位于源码的utils/create-cluster/create-cluster地位

通过start命令创立6个节点:

应用create命令把6个节点组合成一个集群,包含3个主节点和3个从节点


create命令会依据现有节点制订出一个响应的角色和槽调配打算,会询问一下你的意见。
这里是30001、30002、30003被设置为主节点,别离负责槽0 ~5460、5461 ~ 10922、10923 ~ 16383,30004、30005、30006别离设置为以上3个节点的从节点。

胜利构建集群后,就能够应用客户端来连贯和应用集群。


敞开集群,清理节点信息:


F2 手动搭建

搭建一个3个主节点和3个从节点组成的Redis集群。
创立6个文件夹,用于寄存相应节点数据和配置文件。

redis.conf里的内容:

cluster-enabled yes
port 30001

启动6个节点:

连贯6个节点,并为它们调配槽:

执行命令:redis-cli --cluster create 127.0.0.1:30001 127.0.0.1:30002 127.0.0.1:30003 127.0.0.1:30004 127.0.0.1:30005 127.0.0.1:30006 --cluster-replicas 1

这里留神,redis版本要5.0.0以上能力应用 --cluster

这样就胜利了,打印的信息能够看到具体的分配情况。

如果想从新搭建集群,先将下图30001~30006的server的PID给kill

而后再将一个个节点从新redis-server redis.conf启动

散列标签

能够通过散列标签将本来不属于同一个槽的键放到雷同的槽里。
(ps: 集群客户端命令须要加-c)

应用散列标签,该性能会找出键中第一个被大括号突围并且非空的字符串子串,而后依据子串计算出该键所属的槽。即便两个键原本不属于一个槽,只有领有雷同的被突围子串,就能够把它们放到同一个槽中。

尽管从逻辑上说,把user::101和{user}::101看作同一个键,但散列标签只是Redis集群对键名的一种非凡解释,这两个键在理论中不雷同,它们同时存在于数据库,由下面的图也能够看进去。

节点间的外部通信机制

根本通信原理

集群元数据的保护有两种形式:集中式、Goosip协定。
Redis cluster节点间采纳gossip协定进行通信,所有节点都持有一份元数据,不同的节点如果呈现了元数据的变更,就一直将元数据发送给其余节点,让其余节点进行元数据的变更。

goosip益处在于,元数据的更新比拟扩散,不是集中在一个中央,更新申请会陆陆续续打到所有节点下来更新,升高了压力,不好的在于元数据的更新有提早。

gossip协定

gossip协定蕴含多种音讯,蕴含ping、pong、meet、fail等等

  • meet :某个节点发送meet给新退出的节点,让新节点退出集群中,而后新节点就会开始与其余节点进行通信。
  • ping :每个节点都会频繁给其余节点发送ping,其中蕴含本人的状态还有本人保护的集群元数据,相互通过ping替换元数据。
  • pong :返回ping和meet,蕴含本人的状态和其余信息,也用于信息播送和更新。
  • fail :某个节点判断另一个节点fail之后,就发送fail给其余节点,告诉其余节点某节点宕机。

分布式寻址算法

  • hash算法 (大量缓存重建)
  • 一致性hash算法(主动缓存迁徙) + 虚构节点(主动负载平衡)
  • Redis cluster 的 hash slot算法

图解一致性hash算法

hash算法

给一个key,计算hash值,对节点数取模,打在对应的master节点上。
问题是如果某台机器宕机了,取模无奈拿到想要的数据,因为节点数变了。

一致性hash算法

将整个hash值空间组织成一个虚构的圆环,整个空间按顺时针方向组织。
将各个master节点(应用服务器的ip或主机名)进行hash。这样就能确定每个节点在hash环上的地位。

给一个key,计算hash值,确定在环上的地位,从次地位沿环顺时针走,遇到的第一个master节点就是key所在的地位。

该办法如果有一个节点挂了,受影响的也仅仅只是此节点到环空间前一个节点之间的数据,其余都不受影响。减少一个节点也是这样。

然而当节点太少的时候,节点散布不平均会造成缓存热点,所以引入了虚构节点机制,对每个节点计算多个hash,每个计算结果都搁置一个虚构节点。这样就能够实现数据均匀分布,负载平衡。

Redis cluster的 hash slot算法

Redis cluster有固定的16384个hash slot,对每个key计算CRC16值,而后对16384取模,能够获取key对应的hash slot。
Redis cluster每个master都会持有局部slot,hash slot让节点的减少移除很简略,减少一个master,就将其余master的hash slot挪动局部过来,缩小一个master,就将它的hash slot挪动到其余master下来。挪动hash slot的老本是很低的,任何一台机器宕机对其余机器都不影响,因为key找的是hash slot,不是机器。

Redis cluster的高可用原理

  • 判断节点宕机

    和哨兵模式一样有主观宕机和主观宕机,在cluster-node-timeout内,某节点始终没有返回pong,被认为pfail(主观宕机)
    如果一个节点认为某节点宕机,会在gossip ping音讯中,ping给其余节点,如果超过半数节点都认为宕机,就会判断为主观宕机、

  • 从节点过滤

    对于宕机的master,从其所有的slave node中,选一个切换为master node,如果salve和master断开连接的工夫超过了cluster-node-timeout * cluster-slave-validity-factor,那么就没有资格切换成master。

  • 从节点选举

    每个从节点,依据本人对master复制数据的offset,来设置一个选举工夫,offset越大的从节点,选举工夫越靠前,优先进行选举。
    所有的master节点开始slave选举投票,要给进行选举的slave进行投票,如果大部分master都投票给了某个从节点,那么选举通过,那个从节点能够切换成master。从节点执行主备切换,从节点切换为主节点。

缓存穿透和雪崩 ✍

缓存雪崩

比方某平台每天的高峰期,每秒10000个申请,缓存在高峰期能够抗住每秒8000个申请,但是缓存产生了全盘宕机,所有的申请都给了数据库,数据库挂了。
这就是缓存雪崩。

缓存雪崩的解决方案:

  • 事先:Redis高可用,主从+哨兵,Redis cluster,防止全盘解体
  • 事中:本地ehcache缓存+hystrix限流&降级,防止MySQL被打死
  • 预先:Redis长久化,一旦重启,主动从磁盘上加载数据,疾速复原缓存数据

【encache】
EhCache 是一个纯Java的过程内缓存框架,具备疾速、精干等特点,是Hibernate中默认的CacheProvider。

【Hystrix】
hystrix是高可用性保障的一个框架,能够让咱们在分布式系统中对服务间的调用进行管制,退出一些调用提早或者依赖故障的容错机制。
Hystrix通过将依赖服务进行资源隔离,进而阻止某个依赖服务呈现故障时在整个零碎所有的依赖服务调用中进行蔓延,同时Hystrix还提供故障时的fallback降级机制。

用户发送一个申请,零碎收到申请后,先查本地ehcache缓存,如果没有查到再查Redis。如果ehcache都没有,再查数据库,将数据库的后果写入ehcache和Redis中。

组件限流,能够设置每秒的申请,有多少能通过组件,残余的未通过的申请能够走降级,能够返回一些默认的值,或者情谊提醒,或者空值。

  • 数据库相对不会死,限流组件确保了每秒只有多少个申请能通过
  • 只有数据库不死,对用户来说还是有局部申请能够被解决的
  • 只有还有局部申请不死,零碎就没死,对用户来说就是多刷几次

缓存穿透

对于某零碎,一秒6000个申请,后果5000个都是歹意攻打。5000个攻打缓存中查不到数据库中也查不到
每次申请都直奔数据库,这种歹意的攻打场景的缓存穿透就会间接把数据库给打死。

解决形式:每次零碎从数据库中只有没查到,就写一个空值到缓存中,而后设置一个过期工夫,这样的话,下次有雷同的key来拜访的时候,在缓存生效之前,都能够间接从缓存中取数据。

缓存击穿

缓存击穿就是说某个key十分热点,拜访十分频繁,处于集中式高并发拜访的状况,当这个key在生效的霎时,大量的申请就击穿了缓存,间接申请数据库。

解决方案如下:

  • 若缓存的数据是根本不会产生更新的,则可尝试将该热点数据设置为永不过期
  • 若缓存的数据更新不频繁,且缓存刷新的整个流程耗时较少的状况下,则能够采纳基于Redis、Zookeeper等分布式中间件的分布式互斥锁,或者本地互斥锁以保障仅大量的申请能申请数据库并从新构建缓存,其余线程则在锁开释后能拜访到新缓存。
  • 若缓存的数据更新频繁或者在缓存刷新的流程耗时较长的状况下,能够利用定时线程在缓存过期前被动地从新构建缓存或者延后缓存的过期工夫,以保障所有的申请能始终拜访到对应的缓存。

缓存和数据库的双写一致性✍

如果零碎不是严格要求缓存数据库必须放弃一致性的话,能够读申请和写申请串行化,串到一个内存队列里去
串行化能够保障肯定不会呈现不统一的状况,然而它也会导致系统的吞吐量大幅度降低。

Cache Aside Pattern

最经典的缓存+数据库读写的模式,就是Cache Aside Pattern。

  • 读的时候先读缓存,缓存没有去数据库读,而后取出数据后放入缓存,同时返回响应。
  • 更新的时候,先更新数据库,而后再删除缓存(不是更新!因为有时候缓存不仅只是数据库中间接取出来的值,可能须要缓存的是两个数据的计算值)

缓存不统一解决方案

  • 先更新数据库,再删除缓存,如果删除缓存失败了,那么会导致数据库中是新数据,缓存中是旧数据,数据就呈现了不统一。

🔋解决方案:先删除缓存,再更新数据库。

  • 然而如果先删除了缓存,再批改数据库时一个申请过去,去读缓存,发现缓存空,去读数据库,查到了旧数据,放到了缓存中,而后前面数据库实现了更新,又不统一了。

🔋解决方案:这里我临时也无奈给出精确答案。并发场景下如果要更新数据库,能够强制删除缓存反复更新申请几次?或者更新数据的时候给数据加个标识,如果发现在缓存里找不到数据,就删除缓存从新更新数据库。(未必正确)

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

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

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

您可能还喜欢...

发表回复

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

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