Redis分布式缓存

redis 和 memcached 的区别(类型、持久化、集群模式、线程)

  • 1.redis支持更丰富的数据类型(支持更复杂的应用场景):Redis不仅仅支持简单的k/v类型的数据,同时还提供list,set,zset,hash等数据结构的存储。memcache支持简单的数据类型,String。
  • 2.Redis支持数据的持久化,可以将内存中的数据保持在磁盘中,重启的时候可以再次加载进行使用,而Memecache把数据全部存在内存之中。
  • 3.集群模式:memcached没有原生的集群模式,需要依靠客户端来实现往集群中分片写入数据;但是 redis 目前是原生支持 cluster 模式的.
  • 4.Memcached是多线程,非阻塞IO复用的网络模型;Redis使用单线程的多路 IO 复用模型

Redis持久化

  • RDB全量持久化、
  • AOF
    • 每秒同步:异步执行,效率高但如果redis宕机了那么那一秒的数据就丢了
    • 每修改同步。redis中每次有写的操作,都会同步到磁盘,效率比上面的每秒同步要低一些,但是极度安全
    • 不同步

redis有几种数据过期策略

  • 被动删除:当读/写 一个过期的key时,会触发惰性删除策略,直接删除这个key

  • 主动删除由于惰性策略无法保证冷数据已经被删除,所以redis会定期主动删除一些已过期的key,或者当内存达到为redis服务器设置的最大内存的时候,会主动的删除一些数据(触发数据淘汰策略)

Redis如何解决缓存雪崩,缓存穿透,缓存击穿

  • 缓存雪崩呢就表示 在某个时间段设置了过期时间的key都一起失效了,那么db肯定扛不住那么大的并发量,可能会崩溃,所以我们在设置一些热点key的时候,要尽量设置不同的过期时间,以避免在高并发的情况下缓存雪崩问题

  • 缓存穿透呢 从字面上理解就是因为每次做查询请求的时候无法从缓存中查询,从而直接将请请求落入DB,刚好db中也没这条数据,那么返回的就是null,就不会放入缓存中,周而复始知道db炸裂。 这种方案简单粗暴的解决方式就是当db中查询为null的时候自己给个设置过期时间 的默认值,从而解决掉这种查询直接到达db的频率

  • 缓存击穿,某个热点key突然过期了,那么必然会导致,大量的请求入db那么db就会扛不住压力,凉凉。解决方案设置锁,如果是分布式系统就设置分布式锁。

redis如何实现分布式锁呢

实际上要理解的原理就是 设置key的过期时间,然后有请求到来的时候,去redis写入这个key,如果这个key已经被写入redis说明此锁已经被占用了,那么就循环就如等待,上一个占用锁的人,在处理完逻辑后会释放掉锁,那么下一个人就可以获取这个锁了然后执行自己的逻辑。分布式系统下的强制串行操作。

Redis使用场景

  • 1数据缓存(不做过多介绍)

  • 2.手机验证码多长时间过期(可通过设置key的过期时间实现)

  • 3.积分排行(设置key的过期时间,然后定时做统计)

  • 4.计算器(单线程计数,不考虑并发情况下的数据不一致问题)

  • 5.限流(通过设置某个ip的在1分钟内访问次数,来达到限流效果)

  • 6.消息队列

  • 7.分布式锁

  • 8.热门列表(根据访问次数来进行统计)

  • 9.限制登录次数(如果密码错了就计算1次,设置一个过期时间,连错5次就锁定此账号)

  • 10.唯一登录,在系统登录成功后记录这个账号信息,如果此账号在其他地方又登录,就清除某个token信息

  • 11.token信息保存,刚好对应sprong-session中的核心处理

记录一点关于redis和db的数据一致性问题。

方案一 没有使用MQ的系统(并发写量小的系统 )

先更新数据库,数据库更新完成之后,更新缓存(直接将结果给缓存不在查询db)。(直接更新,不是删除),缺点,数据库如若成功,redis更新失败,数据就不一致了。

方案二 使用了MQ的系统

先更新数据库,数据库更新成功返回状态,然后把更新redis的操作使用MQ异步发出,然后使用MQ的消费者机制来保证一定会消费,从而避免由redis更新失败带来 数据不一致。(直接将结果给缓存不在查询db)

方案三(并发量特别大的情况(这里的并发只的是并发写。),如果一个key的修改频率大于查询,那么就要考虑这个key是否 适合缓存)

这个时候使用方案二会出现一个弊端,那就是在你使用MQ消费的时候是肯定存在延迟的,这个时候如果db的值已经改变那么就会造成数据不一致,那么这个时候第二步的做法就可以修改为 消息到达mq只有,从db中查询一次,然后将结果重新放在redis中

方案四 没有使用MQ,系统并发量写太大,但是并发读不是很大,因为删缓存,并发读又太大那么容易造成缓存穿透)

那么可以直接使用先更新数据库,然后删除缓存(等缓存使用的时候,从db中查询,按需加载)

方案五 并发写很大,并发读也很大(秒杀系统(下单,那么就要减库存,下单前要判断是否还与库存))

此种解决方案的核心点是限流,通过各种限流将并发量减小,如果达到db能承受的范围,在达到db能承受的范围之后,将请求下放的数据库层,然后先减去库存,然后修改成功,在修改redis的数值(实际上的做法是先在redis层做限流,然后减去redis的库存,然后再到db去修改。那么这个时候就不用管redis的库存了。)

方案六 基于canal订阅mysql master的binlog,然后进行写入redis,可以实现最小程度的数据不一致。也是最佳方案,不过成本较高。

总结:redis和db的数据一致性在不同的情景下有不同的做法,上面的六种场景第1种是用的最多的,如果对数据一致性比较重视,那么可以用第二种,第三种的使用场景适用于少量写,大量读,情况下,数据的相对一致性。

如何解决rediskey倾斜问题

什么是热点key倾斜?就是在redis集群中某个节点一直承受这大量的查询操作,压力非常大,而其他节点压力都较小。这个时候需要解决这个压力太大的问题

解决思路有两种:

  • 1.在将一些特别热点的key直接放在客户端进行存储,设置过期时间,过期后从后台查询。

  • 2.上面的方法可以解决热点key的倾斜问题,但是如果存储在前端的数据在同一个时间都过期了呢,那么还是有大量的请求到达redis的某一个节点,这个时候我们可以将一个热点key 复制出多分子key,每个子key的value值一样,查询的时候使用hash取模算法,将压力分配到不同的节点

你可能感兴趣的:(面试,redis,分布式,缓存,队列,数据库)