写点什么

Redis 二三事之事前预防和事中恢复

  • 2022 年 3 月 11 日
  • 本文字数:3453 字

    阅读完需:约 11 分钟

Redis二三事之事前预防和事中恢复

事中恢复:


  1. 可以先把流量拦截在入口的地方,比如通过 Nginx 的配置把请求都转到一个特别设计的页面,主要是 一些对用户友好的错误展示。

  2. 然后把 Redis 重新启动起来。

  3. 这样做的目的是为了防止流量过大,直接把新启动的服务,启动一个打挂一个的情况出现。

  4. 要是启动起来了,没多久又挂了,那就可以考虑缓存预热


缓存预热是当 Redis 服务重新启动后,通过程序先放点已知的热点 key 进去后,系统再对外提供服务,防止缓存击穿的场景。 缓存预热也是系统上线后,提前将相关的缓存数据直接加载到缓存系统。避免在用户请求的时候,先查询数据库,然后再将数据缓存的问题!用户直接查询事先被预热的缓存数据! 缓存预热常用的解决方案:(1)直接写个缓存刷新页面,上线时手工操作下;(2)数据量不大,可以在项目启动的时候自动进行加载;(3)定时刷新缓存;
复制代码


  1. 在设计服务的时候做到服务无状态,以达到快速扩容(Redis 提供了灵活的节点扩容和收缩方案。在不影响集群对外服务的情况下,可以为集群添加节点进行扩容也可以对下线节点进行缩容)的目的。


事前预防:


  1. 我首先想到的是 Redis 崩了,也就是发生了缓存雪崩。


解决方案:1、在原有的失效时间上加上一个随机值,比如1-5分钟随机。这样就避免了因为采用相同的过期时间导致的缓存雪崩。
如果真的发生了缓存雪崩,有没有什么兜底的措施?
2、使用熔断机制。当流量到达一定的阈值时,就直接返回“系统拥挤”之类的提示,防止过多的请求打在数据库上。至少能保证一部分用户是可以正常使用,其他用户多刷新几次也能得到结果。
3、提高数据库的容灾能力,可以使用分库分表,读写分离的策略。
4、为了防止Redis宕机导致缓存雪崩的问题,可以搭建Redis集群,提高Redis的容灾性。
复制代码


  1. 在高并发的情况下,除了缓存雪崩,我们还必须得考虑到缓存的击穿、穿透问题。


解决方案:
1、如果业务允许的话,对于热点的key可以设置永不过期的key。
2、使用互斥锁。如果缓存失效的情况,只有拿到锁才可以查询数据库,降低了在同一时刻打在数据库上的请求,防止数据库打死。当然这样会导致系统的性能变差。
复制代码


  缓存穿透是指一个请求要访问的数据,缓存和数据库中都没有,而用户短时间、高密度的发起这样的请求,每次都打到数据库服务上,给数据库造成了压力。
复制代码


解决方案:
1、把无效的Key存进Redis中。如果Redis查不到数据,数据库也查不到,我们把这个Key值保存进Redis,设置value="null",当下次再通过这个Key查询时就不需要再查询数据库。这种处理方式肯定是有问题的,假如传进来的这个不存在的Key值每次都是随机的,那存进Redis也没有意义。
2、使用布隆过滤器。布隆过滤器的作用是某个 key 不存在,那么就一定不存在,它说某个 key 存在,那么很大可能是存在(存在一定的误判率)。于是我们可以在缓存之前再加一层布隆过滤器,在查询的时候先去布隆过滤器查询 key 是否存在,如果不存在就直接返回。
复制代码


  1. 服务中是不是需要考虑限流、降级和熔断机制,最大程度的保护程序的运行?


熔断在分布式系统中,我们往往需要依赖下游服务,不管是内部系统还是第三方服务,如果下游出现问题,我们不在盲目地去请求,在一个周期内失败达到一定次数,不在请求,及时失败。过一段时间,在逐步放开请求,这样既能防止不断的调用,使下游服务更坏,保护了下游方,还能降低自己的执行成本,快速的响应,减少延迟,增加吞吐量。熔断措施:阿里出的Sentinel。hystrix熔断,状态机熔断机制,好处是可以自动熔断和恢复,细粒度把控熔断,坏处是在集群负载均衡很好的情况下,单机平摊流量才能比较好的实现熔断效果。redis计数法分布式熔断机制,利用redis的incr和失效时间判断在一段时间内的异常请求数量达到一定值,直接熔断,可以通过状态位设置判断是否熔断,熔断置状态位为熔断。可以通过diamond在分布式环境下保证。
降级降级就是为了解决资源不足和访问量增加的矛盾。在有限的资源情况下,为了能抗住大量的请求,就需要对系统做出一些牺牲,有点“弃卒保帅”的意思。放弃一些功能,保证整个系统能平稳运行。比如:抢购可以占时限流评论,将流量让给秒杀业务。
降级牺牲的一部分特性:1 强强一致性变成最终一致性大多数的系统是不需要强一致性的。强一致性就要求多种资源的占用,减少强一致性就能释放更多资源这也是我们一般利用消息中间件来削峰填谷,变强一致性为最终一致性,也能达到效果2 干掉一些次要功能停止访问不重要的功能,从而释放出更多的资源举例来说,比如电商网站,评论功能流量大的时候就能停掉,当然能不直接干掉就别直接,最好能简化流程或者限流最好
降级所需要注意的:1 对业务进行仔细的梳理和分析哪些是核心流程必须保证的,哪些是可以牺牲的2 什么指标下能进行降级吞吐量、响应时间、失败次数等达到一个阈值才进行降级处理3 如何降级降级最简单的就是在业务代码中配置一个开关或者做成配置中心模式,直接在配置中心上更改配置,推送到相应的服务。
限流通过对并发访问进行限速。最简单的方式,把多余的请求直接拒绝掉,做的高大上一些,可以根据一定的用户规则进行拒绝策略。
限流的一些行为1 拒绝服务最简单的方式,把多余的请求直接拒绝掉,或者可以根据一定的用户规则进行拒绝策略。2 服务降级降级甚至关掉后台的某些服务。3 特权请求在多租户或者对用户进行分级时,可以考虑让一些特殊的用户有限处理,其他的可以考虑干掉4 延时处理可以利用队列把请求缓存住。削峰填谷。
限流的实现方式1 计数器最简单的实现方式 ,维护一个计数器,来一个请求计数加一,达到阈值时,直接拒绝请求。一般实践中用 ngnix + lua + redis 这种方式,redis 存计数值2 漏斗模式流量就像进入漏斗中的水一样,而出去的水和我们系统处理的请求一样,当流量大于漏斗的流出速度,就会出现积水,水对了会溢出。漏斗很多是用一个队列实现的,当流量过多时,队列会出现积压,队列满了,则开始拒绝请求。3 令牌桶令牌通和漏斗模式很像,主要的区别是增加了一个中间人,这个中间人按照一定的速率放入一些token,然后,处理请求时,需要先拿到token才能处理,如果桶里没有token可以获取,则不进行处理。
限流的一些注意点1 限流越早设计约好,架构成型后,不容易加入2 限流模块不要成为系统的瓶颈,性能要求高3 最好有个开关,可以直接介入4 限流发生时,能及时发出通知事件5 限流发生时,给用户提供友好的提示 。
复制代码


  1. 我们是否应该建立多级缓存的机制,防止 Redis 挂掉之后,大批流量直接打到 MySQL 服务导致数据库的崩盘?


 多级缓存 引入CPU缓存的概念   CPU缓存的容量比内存小的多但是交换速度却比内存要快得多。缓存的出现主要是为了解决CPU运算速度与内存读写速度不匹配的矛盾,因为CPU运算速度要比内存读写速度快很多,这样会使CPU花费很长时间等待数据到来或把数据写入内存。  缓存大小是CPU的重要指标之一,而且缓存的结构和大小对CPU速度的影响非常大,CPU内缓存的运行频率极高,一般是和处理器同频运作,工作效率远远大于系统内存和硬盘。实际工作时,CPU往往需要重复读取同样的数据块,而缓存容量的增大,可以大幅度提升CPU内部读取数据的命中率,而不用再到内存或者硬盘上寻找,以此提高系统性能。但是从CPU芯片面积和成本的因素来考虑,缓存都很小。  按照数据读取顺序和与CPU结合的紧密程度,CPU缓存可以分为一级缓存,二级缓存,部分高端CPU还具有三级缓存,每一级缓存中所储存的全部数据都是下一级缓存的一部分,这三种缓存的技术难度和制造成本是相对递减的,所以其容量也是相对递增的。当CPU要读取一个数据时,首先从一级缓存中查找,如果没有找到再从二级缓存中查找,如果还是没有就从三级缓存或内存中查找。一般来说,每级缓存的命中率大概都在80%左右,也就是说全部数据量的80%都可以在一级缓存中找到,只剩下20%的总数据量才需要从二级缓存、三级缓存或内存中读取,由此可见一级缓存是整个CPU缓存架构中最为重要的部分。  故而应用于SOA甚至微服务的场景,内存相当于存储业务数据的持久化数据库,其吞吐量肯定是远远小于缓存的,而对于java程序来讲,本地的jvm缓存优于集中式的redis缓存。关系型数据库操作方便、易于维护且访问数据灵活,但是随着数据量的增加,其检索、更新的效率会越来越低。所以在高并发低延迟要求复杂的场景,要给数据库减负,减少其压力。
复制代码


多级缓存解决方案


有赞透明多级缓存解决方案(TMC)



相关链接:https://tech.youzan.com/tmc/


著作权归 NoLongerConfused 所有。商业转载请联系 NoLongerConfused 获得授权,非商业转载请注明出处。

发布于: 刚刚阅读数: 2
用户头像

相信奇迹的人本身就和奇迹一样了不起。 2022.01.05 加入

每个人,都可以因为读了一本书,或者一段经历,生活开始有了一些不一样。

评论

发布
暂无评论
Redis二三事之事前预防和事中恢复_3 月月更_NoLongerConfused_InfoQ写作平台