redis的学习笔记(二)

keys命令和scan命令

keys:全量遍历,用于找出符合特定正则规则的key。当存储的是一个bigkey时,性能比较差,会引起阻塞,尽量避免使用;

scan:相比于 keys 来说对于遍历key更加友好,采用的是一种渐进式的遍历方式,完整命令:

SCAN cursor [MATCH pattern] [COUNT count]

cursor:哈希桶的索引值;
pattern:正则表达式
count:一次遍历的key的数量,这个值仅能作为参考,实际底层不一定会以这个值进行遍历。

第一次遍历时,cursor为0,然后遍历完成后返回下一次遍历需要传的cursor的值,一直到最后返回0代表遍历结束。
在这里插入图片描述

主从工作原理

在这里插入图片描述
当slave连接上了master并建立起了一个socket长连接,无论salve是否已经连接过master,都会发送一个psync命令给master。

master收到命令的时候会生成当前数据的rdb快照文件,然后将快照文件发送给salve。

salve收到master的rdb文件后会情况当前记录的数据集,然后开始从快照文件中同步数据。

master在发送快照文件之后会继续接收客户端的指令,这时候会将修改数据集的指令缓存到内存中,当salve同步完后会将这部分的指令通过socket长连接陆续发送给slave。

当master和slave因为某些原因断开时,salve会自动重连到master。master同时接收多个salve的连接请求时,也只会生成一份rdb快照文件。

在这里插入图片描述

数据断点续传

在redis 2.8之后,如果salve和master之前进行数据同步时连接突然断开,在下次连接时可以不用全部复制,可以进行部分数据复制,也就是断点续传。

slave和master在各自的内存中红都维护了 offset(偏移量)和 master的id。如果断开重连后,slave会发送带有offset参数的psync命令,告诉master需要从offset开始的地方进行未完成数据的复制。但是需要注意的是,如果offset已经不在master记录里,或者master的id已经改变,记录的id和现有id对不上,就会进行数据的全量复制。
在这里插入图片描述

redis集群方案
哨兵模式

在这里插入图片描述
哨兵模式下,会启动sentinel的redis服务,这种服务并不提供读写功能,只用来监控redis的实例节点。
当client第一次连接redis时,会从sentinel获取到master的信息,后续的指令直接发送到master,不经过sentinel。
当master宕机时,会经历如下步骤:

  1. 发现master宕机的sentinel节点A发起投票,投票内容是是否认为master宕机,过半数的sentinel节点同意才可将master下线;
  2. 发现master宕机的sentinel节点A再发起投票,投票内容是要求其他sentinel将自己选为leader,一个sentinel在一轮投票中只会投一次票;
  3. 如果超过半数节点同意,那么sentinel节点A就会成为leader,如果这一轮平票,那么每次参选的节点会休息一个随机的时间,再发起下一轮投票,知道选出一个leader为止;
  4. leader选出后,会进行故障转移,从slave节点选出一台做为master节点,matser节点恢复后会成为slave节点继续运行。

优点:

  1. 主从备份;
  2. 具备一定的容错与恢复功能,即使matser宕机,也能保证系统运行。

缺点:

  1. 无法在线扩容,容量限制与单机的配置;
  2. 需要额外的资源启动 sentinel,且slave节点不提供服务。
集群模式

在这里插入图片描述
集群模式具备以下特点:

  1. redis会将数据划分为16384 个 slots(槽位),每个节点只负责存储一部分的slots,slots的信息存储在每个节点中;
  2. client本地也缓存了一份slots信息,client可以连接到任何一个节点当中,当client发起指令时,会对key进行CRC16算法得到一个整型值,然后用整型值对16384 进行取余,这样就可以得到这个key的slots;
  3. 如果client想要操作的key的slots不在client连接的节点负责的slots中,该节点会发送一个带有目标节点的信息的命令给client,client收到信息后会更新本地的slots,并且跳转到目标节点上。
  4. 每个节点除了开放提供服务的端口号,还会开放一个用于集群中进行通信的端口号,这个值默认是己提供服务的端口号+10000;
  5. 每个节点都至少有一个slave节点,并且由于内部的投票半数原则,所以构建一个集群需要6个节点(3主3从);

如果有一个master宕机,会经历以下恢复步骤:

  1. slave节点发现自己的master宕机了,会向其他节点的master发送FAILOVER_AUTH_REQUEST,请求其他节点进行失败确认,并将集群中的currentEpoch +1;
  2. 其他节点的matser收到FAILOVER_AUTH_REQUEST,验证发送者的合法性后,会发送FAILOVER_AUTH_ACK信号,对于一个epoch只会响应一次;
  3. 发起失败确认的slave收集所有的FAILOVER_AUTH_ACK信号后,如果收到的信号超过集群中半数master以上的ack,那么salve节点就会成为master节点,并给其他master节点发送pong信号告知。
  4. 如果选举失败,说明不止一个salve节点在进行选举,每个slave节点在进行下一次投票选举之前都会延迟一段时间。

延迟时间公式:

DELAY = 500ms + random(0 ~ 500ms) + SLAVE_RANK * 1000ms

SLAVE_RANK 表示已经从master同步数据数量的rank,rank越低,代表同步的数据越新。

currentEpoch 作用:
当集群状态改变,该值就会增加,这是为了保证,每个matse节点对于每一次投票对只有一次响应的结果。

salve并不是matser一宕机就马上进行选举,而是会延迟一段时间进行选举,这是为了保证master的宕机状态能在集群中广播。

缓存穿透

缓存穿透是值客户端查询一个根本不存在的键,在缓存层找不到数据,然后直接穿透到数据库层进行查询,使得数据库压力增大,一般出现这种问题可能有两个原因:

  1. 业务设计不规范或数据出现问题
  2. 恶意攻击。

解决办法:

  1. 业务层面接收数据时可对请求参数简单做一些校验,如果不符合规则直接拒绝;
  2. 查询不到数据时,可对该key缓存一个空对象,并设置过期时间,保证短时间内请求不会落到数据库层;
  3. 使用布隆过滤器,每次进行查询时,先询问布隆过滤器,布隆过滤器回答不存在,则该key一定不存在;布隆过滤器回答存在,该key不一定存在。
缓存击穿

缓存击穿指的是在高并发场景下,某一批热点数据在同一时刻缓存集体失效,导致请求在短时间内落到数据库层导致压力突然增大,甚至宕机。

解决办法:

  1. 增加一批缓存数据时,不要设置一样的过期时间,而是随机设置同一时间段内不同的过期时间;
  2. 对于热点key,每次访问都获取一把分布式锁,不过这样会对锁的访问压力较大。
缓存雪崩

缓存雪崩指的是打在缓存层上的请求过多,超过了缓存层能承受住的压力,这时就会像雪崩一样,导致数据库压力突然增大。

解决办法:

  1. 保证缓存层的服务高可用,使用哨兵架构或者集群架构;
  2. 依赖隔离组件为后端限流并降级,如Sentinel或Hystrix限流降级组件。
缓存与数据库数据不一致

双写不一致
出现原因:更新数据时,会分为更新缓存和更新数据库两步操作,但这两步不是原子操作,就会出现缓存与数据库数据不一致的场景。
在这里插入图片描述
线程1写完数据库,在更新缓存之前cpu转而执行后来的线程2,线程2写完数据库后并且更新缓存,回到线程1后更新缓存,就会使线程2的缓存值失效。

删除key模式
如果更新数据时,采用删除key的模式。这样还是会出现不一致的情况。
在这里插入图片描述
这里线程1写完数据库后,删除了缓存,然后执行线程3查询缓存层没有,查询到了数据库层,在更新缓存之前线程转而执行了线程2,并写数据和删除缓存后,回到了线程3,这里线程3查到的就是一个旧值,出现了不一致的情况。
延迟双删
在这里插入图片描述
延迟双删指的是线程在写完数据库删除缓存后,延迟一段时间再进行删除,这样能有效减少不一致的概率。
这种做法并没有完全解决,还是会出现不一致的情况。并且增加了每次写数据的耗时,使得系统的吞吐量变小 。

不一致的解决方案:

  1. 对于能容忍一段时间的脏数据情况,并不需要考虑这个问题,只要给每个key都设置一个过时时间就可;
  2. 加锁,使访问数据串行化:每次写数据时都放进一个队列中,操作数据时从队列取出进行操作;使用读写锁,读读的情况相当于无锁。

总结:
我们使用缓存都是为了解决读多写少的情况,这种情况都是可以容忍一段时间的不一致的;如果场景是写多读少,又要保证数据的强一致,就没必要使用缓存了,这种情况还不如直接访问数据库来的实在,不要为了使用缓存,又做了很多设计保证数据的一致性而导致系统复杂性增加,这样得不偿失。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值