前言
缓存(Cache)是目前互联网中使用得比较多的技术,原始意义是指访问速度比一般随机存取存储器(RAM)快的一种高速存储器,通常它不像系统主存那样使用DRAM技术,而使用昂贵但较快速的SRAM技术。缓存在当今应用产品必不可少的一部分,这个技术能解决成千上万用户并发请求查询数据的问题,同时,在合理的配置下,可以让应用产品在运维成本上做到降本增效的作用。
缓存应用场景
- 电子商城
- 搜索引擎
- 文档搜索
- 异地服务数据同步……
缓存实现技术
前端
- Cookie
- localStorage
- sessionStorage
- WebSQL
- indexedDB
- applicationCache
- cacheStorage
前端资源服务端
- NGINX-缓存配置
后端
- Redis
- Mybatis
- Memcache
缓存测试
测试要点:缓存击穿 缓存击穿 缓存雪崩
缓存击穿
基础概念:
在超级热点数据突然过期,导致针对超级热点的数据请求在过期期间直接打到数据库,这样数据库服务器会因为某一超热数据导致压力过大而崩掉。
简易理解:
- 相同点:缓存击穿和缓存穿透有点像但是性质又不相同,都是缓存中没有数据,请求命中数据库。
- 两者区别:缓存穿透指的是数据库中不存在的数据,缓存击穿则是指缓存失效的问题。
触发场景:
热门商品查询,redis缓存查询记录:12h,查询时,redis缓存对应缓存商品已超时清理,后台程序查询时,查询不存在,直接查询数据库结果。
解决方案:
- 加互斥锁(mutex key):
在并发的多个请求中,只有第一个请求线程能拿到锁并执行数据库查询操作,其他的线程拿不到锁就阻塞等着,等到第一个线程将数据写入缓存后,直接走缓存。 - 热点数据过期时间调整:
- 根据实际业务情况,在Redis中维护一个热点数据表,批量设为更长的过期时间。
- 批量设置永不过期(如top1000),并定时更新top1000数据。
缓存穿透
基础概念:
缓存和数据库中都没有的数据,导致所有的请求都打到数据库上,然后数据库还查不到(如null),没法写缓存,造成数据库短时间线程数被打满而导致其他服务阻塞,最终导致线上服务不可用。此时缓存就好像被穿透了一样,起不到任何作用。
触发场景:
对于热数据安排不合理的应用就存在这个问题,常见场景是搜索引擎-搜索商品时接口响应慢。
如何判断(大致):
- 压力测试时,接口响应慢
- Redis服务器负载明显飙升
- DB数据库负载明显飙升
解决方案:
- 互联网业务的数据访问模型一般是遵循二八原则的,即 20% 的数据为热点数据,80% 的数据是非热点不被常访问的数据。既然缓存容量有限,且20%的数据为热点数据,那我们可以利用有限的容量去缓存那 20% 的数据来保护我们的系统,至于80%非热点不常用的数据发生穿透就穿透了,数据库吃得住。
- 接口参数校验:
防君子不防小人。在参数校验层加上参数合法性校验,如查询订单ID为20位随机值,正则核对一下ID长度是否规范,不规范地直接过滤掉。 - 设置空值:
当访问缓存和DB都没有查询到值时,该key我们当做是恶意参数来看,可以将该key的空值写进缓存,设置较短的过期时间。
但是如果有大量的获取并不存在数据的穿透请求的话如恶意攻击,则会浪费缓存空间,如果这种null值过量的话,还会淘汰掉本身缓存存在的数据,这就会使我们的缓存命中率下降。
因此在使用设置空值方案时,我们要做好监控,预防缓存空间被过多null值占领造成的缓存空间浪费,如果这种数据量太大,就不再建议使用,那就使用另一种方案,即布隆过滤器。 - 布隆过滤器:
布隆过滤器在查询缓存之前起到初步过滤作用,布隆过滤器存储所有可能访问的 key,将不存在的 key 直接过滤,存在的 key 再进一步查询缓存和数据库。
布隆过滤器的特点是判断不存在的,则一定不存在;判断存在的,大概率存在,但也有小概率不存在。并且这个概率是可控的,根据具体需求,我们可以让这个概率小幅降低或变高。
缓存雪崩
基础概念:
突然缓存层不可用,导致大量请求直接打到数据库,最终由于数据库压力过大可能导致系统崩掉。
缓存层不可用指以下两方面:
- 缓存服务器宕机,系统将请求打到数据库。
- 缓存数据突然大范围集中过期失效,导致大量请求打到数据库重新加载数据, 与缓存击穿的区别在于这里针对很多key缓存,前者则是某一个key。
简易理解:
- 相同点:缓存击穿和缓存雪崩有点像,都是缓存中没有数据,且请求命中数据库有数据。
- 两者区别:缓存雪崩更像是缓存击穿升级版,瞬时查数据库的量更大。
触发场景:
- 缓存服务器宕机/网络阻断。
- 缓存时间设置的过期时间为同一个时间。
解决方案:
- 根据实际情况打散缓存失效时间
- 热点数据不过期
- 加互斥锁(与缓存击穿方案类似)
总结(Conclusion)
缓存测试的发现与问题判断,首要做的是对该产品/接口对应的业务场景定义进行分析,得出合理的场景进行压力测试,然后,根据测试接口响应结果结合链路上的服务器压力情况进行分析并推理出大致的问题点。