redis总结

最近看了redis的书,总结一下

redis持久化的方式
有两种,一种是rdb方式,一种是aof方式。

rdb存储
rdb存储的是最终的数据,可以配置触发rdb的方式有两种,一种是save,一种是bgsave,前者会阻塞服务器响应其他的请求,后者是用一个子进程来操作,不会阻塞服务器,所以都要用后者。redis可以配置自动的保存,比如save 900 1,表示900秒内触发一次修改的操作就要出发生成rdb文件。
rdb文件最终存储的实际的数据,相比于aof存储的是实际的操作命令。

aof存储
aop存储的是实际的命令,比如
set a “hello1”;
set a “hello2”;
set a “hello3”;
aop实际存储了三遍;
aof持久化存储可以根据配置选择是否每次都持久化到磁盘,有三种配置,分别是:

  1. always:每次写都持久化到磁盘,即每次都刷盘,这样是最可靠的,不会丢失数据,但是性能最差。
  2. everysecond:每次只写入到文件,但是不强制刷盘,而是靠一个另外的线程额外的刷盘,这样如果操作系统宕机的话,会丢失一部分数据,但是最多丢失1秒钟的数据。
  3. no:只将命令写入到文件,但是不刷盘,这样性能最好,但是安全性最差,如果操作系统宕机,则数据丢失。

aof的重写功能
一个key多次操作的话,aof会写多次,这样aof效率很低,且随着程序的运行,aof的文件会大的无法保存,所以aof有一个重写的功能,会创建一个新的aof文件来替换旧的aof文件。aof的重写功能是读取的数据库中的输入,根据数据库的数据翻译成命令,然后将命令保存在新的aof文件中。
aof在重写的过程中,还会有新的aof操作,对于这种问题,redis设置了一个aof重写缓冲区。在重写的过程中,新的操作会保存在这个aof重写缓冲区中,当aof重写完成后,会将aof重写缓冲区的命令再次写入到新的aof文件中,然后使用新的文件替换旧的aof文件,清空aof重写缓冲区即可。

redis中的事件
redis服务器是基于事件的驱动程序。redis基于reactor模式开发了自己的网络事件处理器,叫做文件事件处理器,文件事件处理器使用io多路复用技术来同时监听多个套接字,当被监听的套接字发生链接、可读、可写、关闭等操作时,与之相对应的文件事件就会产生,所以同时会有很多个文件事件,这些多个事件会暂时写入到一个队列中,然后等待文件事件分派器的处理,文件事件分派器会根据文件事件找到事件处理器来处理事件。

redis中的主从复制
redis中的主从复制是异步的,即客户端只要写到主节点即认为是成功,靠主节点写入到主节点的从节点。
当有一个新的从节点加入的时候要做主从复制,即全量复制。从节点发送sync请求,主节点会先做一次rdb存储,生成一个文件,同时会缓存新的写请求到缓存区,等rdb文件准备好以后发送给从节点,从节点在接收到rdb文件后再从主节点接受缓存的写操作,就算同步完成,后续只需要主节点发送给从节点写操作即可。这个方式有一个问题,即如果因为网络问题从节点落后了一部分的写操作,也需要使用rdb来同步所有的数据,效率太低,可以把这种情况叫做部分同步。
对于部分同步的低效率问题,有了新的同步方法:使用psync命令,即partial sync。当主从延迟不是很大的时候,只需要把落后的命令发送给从节点即可,这样效率就会大大的提升了。
部分同步的三个功能有下面三个部分组成:

  • 主服务器的复制偏移量(replication offset)和从服务器的复制偏移量
  • 主服务器的复制积压缓冲区
  • 服务器的运行id,即每个server都有一个唯一的id,用于判断主节点是否是原先
    主服务器会维持一个缓冲区,实际就是一个fifo的队列,里面存有最新的写操作的请求。当主服务器收到写的请求的时候,会把命令写入到复制积压缓冲区里面去。当从节点断开又重写连接上主节点的时候(此处是部分同步,区别于全部同步),会发送psync 请求主节点,如果主节点发现落后的比较小,就可以通过复制缓冲区来完成数据同步,同步完成之后就可以进入正常的命令传播阶段。

命令传播阶段
命令传播阶段,redis的主从节点之间保持长连接,主节点将收到的命令发送到从节点。
命令传播阶段,主节点每秒会发送ping请求给从节点;从节点向主节点每秒发送一次REPLCONE ACK <复制偏移量> 请求,即会带着自己的复制偏移量发送请求,这样做的目的有三个

  • 检测主从服务器的网络连接状态
  • 辅助实现min-slaves功能
    redis的min-slave功能是为了防止redis在不安全的状态下提供功能,redis有min-slaves-to-write和min-slave-max-lag,redis的主节点只有在最大延迟小于指定的值的从节点的数量大于指定的值的情况下才会进行写操作。
  • 检测命令丢失
    主节点向从节点做命令传播,如果发生了命令丢失,可以从节点的复制偏移量发现。

集群的通信
每个redis的节点上都会有一个clusterNode的数据结构记录自己的状态,每个节点上都含有集群中所有其他节点的clusterNode节点用来记录状态,而且,对于集群中所有的节点,都会有一个clusterNode的数据结构。culsterNode上存储了每个节点存储的槽的id,当前节点的clusterNode还存储了槽中含有的key。另外每个节点上还会有clusterState的结构,用来保存自己视角下的集群的状态,比如集群中包含多少个节点,当前集群的纪元是多少。
集群间的通信是通过gossip协议,蠕虫协议,每个节点每秒都会选择集群中的几个节点做通信,其中一定包含最久没有做过通信的节点,发送ping请求。请求中会带有自己节点的信息还有几个自己节点上存储的其他节点的信息,以及当前节点和选中的发送节点的最后的ping、pong消息的时间戳,其他节点收到请求后会更新自己节点上存储的值,并发挥一个pong响应,响应中也含有类似请求中的消息提,这样就实现了集群信息的传播。
Gossip 协议的最大的好处是,即使集群节点的数量增加,每个节点的负载也不会增加很多,几乎是恒定的。这就允许 Redis Cluster 或者 Consul 集群管理的节点规模能横向扩展到数千个

redis集群的master选举
如果收到ping请求的节点没有返回pong响应,那么就被认为疑似下线(pfail),如果集群中半数以上的主节点都认为一个节点是pfail,那么就认为这个节点是下线的,就会向集群中广播一个fall的消息,所有收到这个消息的节点都将对应的节点设置为下线。原先复制该主节点的从节点收到主节点下线的通知后,会向集群中发出一个CLUSTERMSG_TYPE_FAILOVER_AUTH_REQUEST请求,申请成为主节点,收到这个请求的主节点会投一个赞成票,如果某个从节点收到的赞成票超过了一半以上的主节点,那么就会成为master,然后这个从节点就会向集群中发送一个PONG的请求,让其他的节点知道这个节点成了主节点。
问题:如果一个下线的主节点有多个从节点,怎么处理?
急群众有一个配置是纪元,每当有一次fail over的时候纪元就会+1,每个leader对于一个纪元的投票只能投一次,如果一个下线的主节点有多个从节点,那么只有一个从节点能得到一票。如果主节点的数量是偶数,则存在一定的概率每个从节点得到的票数一样多,此时就会再次进行竞选,纪元再加一,不过多个从节点在竞选的时候会先等待随机的一定时间,避免竞选失败。

redis的消息有哪几种?
一共有ping、pong、meet、fall这四种。
其中pong用来回应收到收到的meet和ping请求,表示已经收到了该请求,另外一个节点也可以通过向集群中广播自己的pong消息来让集群中的其他节点立即刷新关于这个节点的认识,比如当进行了fail over以后,新的节点就会向集群中广播一条pong消息。

redis zipList的数据结构
ziplist是list、zset、hash在数据量比较小时的实现方式,有一个前提条件,存储的数量不能超过128个,每个对象的长度不超过64个byte的时候才能使用。
他是一个数组,每个元素紧密挨在一起,当修改的时候,会新建一个。里面有header和tail两个指针,方便便利。

redis 渐进式hash扩容
redis的hash的扩容不是一次处理完成的,一次处理完成如果对于特别大的hash对象,耗时太久,所以redis采用了渐进式hash的方式,redis有两个数组,每次读写的请求都只会挪动一个旧数组中的桶位到新的数组中,将整个扩容过程分散到多个请求中去,降低每个请求的耗时。有一个指针表示已经处理过的桶位,如果要读写的桶位小于这个指针,则去新的数组中去读写,否则去旧的数组中去读写。

redis的热点key如何处理
有两种方式,一种是有热点探测的客户端,在发现热点key之后,把热点数据缓存在本地,相当于是本地调用,然后会启动一个线程,单独更新本地缓存和redis上的数据。
第二种方式是:将热点数据复制多份,存多个不同的key,比如在原来的key上加上0-9的后缀,然后写到redis上,在读取的时候,随机的读取一个key,这样就能将流量分配到不同的redis节点上。

redis是如何处理大key的
可以将大key分成多个key,比如在key的名字上添加0-9,然后就可以保存在不同的节点上。
如果value是字符串,则可以将字符串截断;
如果是list,可以根据元素的hash值来确定存储在哪个key中。

如何将一个用户的所有的key都存储在同一个节点上?
Redis会将每个键的键名的有效部分使用CRC16算法计算出散列值,然后对16384的取余,然后分配到对应的slot中,所以只需要控制相关的key的有效部分相同即可,有效部分用{}表示,比如{user100}.username和{user100}.id,这两个key的有效部分就相同,就会路由到相同的slot。

redis的缓存雪崩、缓存击穿、缓存穿透
雪崩指的是崩掉,即过多的请求都请求到了mysql,使mysql宕机或者假死,导致程序没有反应,崩溃,解决办法是所有的key的失效时间不要一起失效,而是要错开失效的时间。
击穿是拿不存在的id攻击,数据在缓存中不存在,所以都达到mysql,使mysql压力太大,影响程序性能。解决的方案是:对于不存在的数据在redis中设置为null,并设置过期时间;或者将可以使用的id写在布隆过滤器中。
穿透是:类似于雪崩,只是没有崩溃,但是很多key在缓存中不存在,解决方案:热点数据不要过期。

redis如何保证双写的一致性的?
1、监听binlog的方式,开源的有canel;
2、延时双删方式,在更新完mysql的数据后,立刻把redis中的数据删掉,并生成一个定时任务,10秒后再次删掉。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值