当前位置: 首页 > 科技观察

Redis缓存高频问题,问三个问题,你的亿级系统不会炸掉吗?_0

时间:2023-03-12 11:47:46 科技观察

后台缓存设计可谓俗套。更早的时候用的是memcache,现在大家倾向于用redis。除了知道常用的数据存储类型,根据业务场景进行有针对性的选择外,似乎没有其他大的难点。项目中引入RedisClient二方包,初始化一个Bean实例RedisTemplate,一切搞定,soeasy。如果是几十、上百并发的业务场景,缓存设计可能不需要考虑那么多,但是如果是十亿级别的系统呢?1.缓存知识图谱早期的缓存用于加速CPU数据交换的RAM。随着互联网的飞速发展,缓存的应用更加广泛,用于高速数据交换的存储介质称为缓存。我们在使用缓存时应该关注哪些指标?缓存有哪些应用模式?缓存设计的技巧是什么?一图抵千言,如下:二、七大经典问题缓存在使用过程中难免会遇到一些问题。对于高频问题,我们大致分为七类。让我们看看下面的详细信息。1、集中式缓存失效业务系统查询数据时,首先查询缓存。如果缓存中的数据不存在,则查询DB,将数据预热到Cache中,返回。Cache的性能比DB高50~100倍以上。在很多业务场景中,比如闪购商品,微博热搜排名,或者一些活动数据,所有的DB数据都是批量预热到缓存中,通过运行任务集中,缓存数据的过期时间几乎一致。当这批数据过期时,会一起过期。这时候所有对这批数据的请求都会出现缓存失效,从而将压力转移到DB上。DB的请求量激增,压力变大,响应开始变慢。那么有什么解决办法吗?当然有。我们可以从缓存过期时间的入口开始,将原来固定的过期时间调整为过期时间=基本时间+随机时间,这样缓存就会慢慢过期,避免所有的瞬间过期,给DB带来过大的压力。2、缓存穿透不是所有的请求都能找到数据,无论是来自缓存还是DB。假设黑客攻击了一个论坛并使用了一堆机器人来访问一个不存在的帖子ID。按照常规思路,每次都是先查cache,cache里面什么都没有,然后再查DB,一样的没有。这时候缓存不会预热,导致每次查询都会有一次缓存未命中。由于DB的吞吐性能不佳,会严重影响系统的性能,甚至影响正常用户的访问。解决方法:解决方法一:查询和保存DB时,如果数据不存在,预热一个特殊的空值到缓存中。这样,后续查询会命中缓存,但需要解析特殊值。方案二:构造一个BloomFilter过滤器,初始化全量数据。当收到请求时,判断该key是否存在于BloomFilter中。如果没有,直接返回即可,不查询缓存和DB。3、缓存雪崩缓存雪崩是指部分缓存节点不可用,导致整个缓存系统甚至业务系统不可用的情况。分布式缓存设计一般选择一致性Hash。当部分节点异常时,采用rehash策略,即将异常节点的请求平均分配给其他缓存节点。但是当大流量高峰来临时,如果大流量的key比较集中,就在一两个缓存节点,很容易让这些缓存节点的内存和网卡超载,导致缓存节点异常崩溃。这些大流量的key请求被rehash到其他缓存节点,进而导致其他缓存节点过载而Crash,缓存异常不断蔓延,最终导致整个缓存系统出现异常,无法对外提供服务。解决方案:方案一:增加实时监控,及时预警。通过机器更换和各种自动故障转移策略快速恢复缓存的对外服务能力。方案二:添加多份缓存,缓存异常时读取其他缓存副本。为了保证副本的可用性,尽量在不同的机架上部署多个缓存副本,以降低风险。4、缓存热点对于突发事件,当大量用户同时访问热点信息时,突发热点信息所在的缓存节点容易出现过载、卡顿甚至崩溃的情况,我们称之为缓存热点。这在新浪微博上经常遇到。某大V明星出轨、结婚、离婚,瞬间引来百万人看瓜。访问同一个key时,流量集中在某个缓存节点机器上,很容易炸毁网卡。、带宽和CPU限制,最终导致缓存不可用。解决方案:首先我们可以先找到hotkey,比如通过Spark实时流分析,及时发现新的hotkey。分解集中式流量以避免缓存节点过载。由于只有一个key,我们可以在key后面加上序号,比如key#01,key#02。..key#10有多个副本,这些处理过的key位于多个缓存节点上。每次发起请求,客户端可以随机访问一个,设计缓存服务治理管理后台,实时监控缓存的SLA,开辟分布式配置中心,可以快速动态扩容一些热键。5、缓存一个大的key访问缓存时,如果key对应的值太大,读写加载容易超时,造成网络拥塞。另外,当缓存中的字段很多时,每个字段的变化都会引起缓存数据的变化,频繁读写,导致查询变慢。如果大key过期被缓存淘汰,数据预热需要更多时间,也会导致查询变慢。因此,我们在设计缓存的时候,一定要注意缓存的粒度。它不应该太大。如果太大,容易导致网络拥塞;第二次评价。解决方案:解决方案一:设置一个阈值。当value的长度超过阈值时,开始对内容进行压缩,减小kv的大小。解决方案2:评估大键的比例。由于很多框架使用了池化技术,比如Memcache,可以预先分配大对象空间。当需要真正的业务请求时,可以直接使用。方案三:将大key拆分成多个小key,独立维护,成本会降低很多。方案四:给大key设置一个合理的过期时间,尽量不要淘汰那些大key。6、缓存数据一致性缓存用于加速,一般不会持久化存储。因此,一条数据通常存在于DB和缓存中,这就带来了一个问题,如何保证两者之间的数据一致性。另外,缓存热点问题会引入多份备份,也可能出现不一致的情况。解决方法:解决方法一:当缓存更新失败时,重试。如果重试失败,将失败的key写入MQ消息队列,通过异步任务补偿缓存,保证数据一致性。方案二:设置一个较短的过期时间,通过自愈,缓存过期后,缓存会重新加载最新的数据。7、数据并发竞争预热互联网系统的典型特征是流量大。一旦缓存中的数据过期或由于某种原因被删除,缓存中的数据就会为空,大量并发的线程请求(查询同一个key)会一起并发查询数据库,对数据库的压力数据库会突然增加。如果请求量非常大,全部放在数据库中,可能会使数据库不堪重负,导致整个系统的服务不可用。解决方案:方案一:引入全局锁。当缓存未命中时,首先尝试获取全局锁。如果你拿到了锁,你就有资格查询DB并将数据预热到缓存中。虽然客户端发起的请求很多,但是因为无法获取到锁,只能处于等待状态。当缓存中的数据预热成功后,会从缓存中获取。为了便于理解,画了一个简单的流程图。这里要特别注意一点。因为有并发时间差,所以会有二次校验,检查缓存是否有值,防止缓存反复预热覆盖。解决方案2:为缓存数据创建多个备份。当一个备份过期时,可以访问其他备份。在编写最终的缓存设计时,有很多技巧和优化方法千变万化,但一定要抓住核心要素。即在保持数据一致性的情况下,让访问尽量命中缓存。