本文主要是介绍Redis核心技术与实战-学习笔记(二十三):旁路缓存-Redis是怎么工作的,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
一.Redis提供了什么
- Redis提供了高性能的数据存储功能,所以广泛应用在缓存场景中,既能有效提升业务应用的响应速度,还可以避免高并发压力请求发送到数据库层。
Redis缓存失效的后果
- Redis做缓存出现问题,比如缓存失效,大量请求会直接积压到数据库层,必然会给数据库带来巨大的压力,导致数据库宕机或者故障,业务应用没办法存取数据,响应用户请求。产生生产事故。
需要解决的四个关键问题:
- Redis缓存具体是怎么工作的
- Redis缓存满了,该怎么解决
- 缓存一致性,缓存穿透,缓存雪崩,缓存击穿等异常该如何应对
- Redis内存有限,如果使用快速的固态硬盘来保存数据,那么可以增加缓存的数据量,那么Redis缓存可以使用快速固态硬盘吗?
缓存的特征
缓存产生的原因:一个系统中不同层之间访问速度不一样,所以我们需要缓存将一些需要频繁访问的数据放到缓存中,加快他们的访问速度
计算机的三级结构:
存在问题:
- 不同存储之间的处理数据速度有差异,如果每次CPU处理数据时,都要从ms级别的慢速磁盘中读取数据,然后在进行处理,那么CPU只能等磁盘的数据传输完成,这样一来,高速CPU就会被慢速磁盘拖累,整个计算机系统的运行速度就会变得非常慢。
解决方案:
计算机系统中,默认有两种缓存:
- CPU 里面的末级缓存,即 LLC,用来缓存内存中的数据,避免每次从内存中存取数据;
- 内存中的高速页缓存,即Page cache,用来缓存磁盘中的数据,避免每次从磁盘中存取数据。
缓存的第一个特征:
- 在一个层次化的系统中,缓存一定是一个快速的子系统,数据存在缓存中时,避免每次从慢速子系统中存取数据。
- 对应到互联网应用中,Redis就是快速子系统,而数据库就是慢速子系统。
缓存的第二个特征:
- 缓存系统的容量大小总是小于后端慢速系统的,我们不可能把所有数据放在缓存系统中。
- 缓存的容量终究有限,缓存中的数据量也是有限的,肯定没法时刻满足访问需。所以,缓存 和后端慢速系统之间,必然存在数据写回和再读取的交互过程。
- 简单来说,缓存中的数据需要按一定规则淘汰出去,写回到后端系统,而新的数据又要从后端中读取进去,写入缓存。
二.Redis缓存处理请求的两种情况
把Redis用作缓存时,我们会把Redis部署在数据库的前端,业务应用在访问数据时,会先查询Redis中是否保存了相应的数据。此时,根据数据是否存再缓存中:
- 缓存命中:Redis中有相应的数据,就直接读取Redis,性能非常快。
- 缓存缺失:Redis中没有保存相应数据,就从后端数据库中读取数据,性能就会变慢。
- 缓存更新:一旦发生缓存缺失,为了让后续请求能从缓存中读取到数据,我们需要把缺失的数据写入Redis。缓存更新操作会涉及到保证缓存和数据库之间的数据一致性问题。
使用Redis缓存时,我们基本有三个操作:
- 应用读取数据,需求先读取Redis;
- 发生缓存缺失时,需求从数据库读取数据;
- 发生缓存缺失时,需要从数据还需要更新缓存。发生缓存缺失时,需要从数据库读取数据;发生缓存缺失时,还需要更新缓存。
三.Redis作为旁路缓存的使用操作
- Redis是一个独立的系统软件,和业务应用程序是两个软件。
- Redis只能被动的等待客户端发送请求,然后再进行处理。
- 应用程序要向使用Redis作为缓存,我们就要在程序中增加响应的缓存操作代码。
- 所以,我们也把 Redis 称为旁路缓存,也就是说,读取缓存、读取数据库和更新缓存的操作都需要在应用程序中来完成。
这和我们刚才讲的计算机系统中的LLC和page cache不一样。
- 平时开发程序时,我们是没有专门在代码中显式地创建LLC或page cache的实例,也没有显式的调用过GET接口。
- 我们在构建计算机硬件系统时,已经把LLC和page cache放在应用程序的数据访问路径上,应用程序访问数据时候就能直接用上缓存。
使用Redis缓存时,具体来说,我们需要在应用程序中增加三方面的代码:
- 当应用程序需要读取数据时,我们需要代码中显式调用Redis和GET操作接口,我们进行查询。
- 如果缓存缺失了,应用程序需要再和数据库连接,从数据库中读取数据。
- 当缓存中的数据需要更新时,我们也需要在应用程序中显式的调用SET操作接口,把更新的数据写入缓存。
String cacheKey=“productid_11010003”;
String cacheValue=rediscache.get(cacheKey);
//缓存命令
if(cacheValue!=null)return cacheValue;
else{cacheValue = getProductFromDB();redisCache.put(cacheValue) //缓存更新
}
需要新增程序代码来使用缓存,所以,Redis并不适用于哪些无法获得源码的应用。
四.缓存的类型
按照Redis缓存是否接受写请求,我们可以它分成只读缓存和读写缓存。
只读缓存
- 当Redis用作只读缓存时,应用要读取数据的话。会调用Redis GET 接口,查询数据是否存在。而所有的数据写请求,都会直接发往后端的数据库 ,在数据库中增删改。对于删改的数据来说,如果Redis已经相应的数据,应用需要把这些缓存的数据删除,Redis中就没有这些数据了。
- 当应用再次读取这些数据时,会发生缓存缺失,应用会把这些数据从数据库中读取出来并写入缓存中。这样一来,这些数据后续再被读取时,可以直接从缓存中获取,就能起到加速访问的效果。
假设业务应用到修改数据A,此时,数据A在Redis中也缓存了,那么应用会先直接在数据库中修改A,并且把Redis中A删除,等到应用程序需要读取数据A时,会发生缓存缺失,此时应用程序从数据库中读取A,并写入Redis,以便后续请求从缓存中直接读取:
只读缓存直接在数据库中更新数据的好处是,所有最新的数据都在数据库中,而数据库提供数据的可靠性保障,这些数据不会有丢失的风险。当我们需要缓存图片,短视频这些用户只读的数据时,就可以使用只读缓存这些类型。
读写缓存
对于读写缓存来说,除了读请求会发送到缓存进行处理(直接在缓存中查询数据是否存在),
所有写请求也会发送到缓存,在缓存中直接对数据进行增删改操作。此时,得益于Redis的高性能访问特性,数据的增删改查操作可以在缓存中快速完成,处理结果也会快速返回给业务应用提升响应速度。
数据又丢失风险
- 同步直写:写请求发给缓存的同时,也会发给后端数据库进行处理,等到缓存和数据库都写完数据才给客户端返回。这样即使缓存宕机或者发生故障,最新的数据仍然保存在数据库中,这就提供了数据可靠性保证。
- 同步直接:会降低缓存的访问性能,这是因为缓存在处理写请求速度快,数据库处理写请求速度慢。即使缓存很快的处理了写请求,也需要等待数据库处理完所有的写请求才能给应用返回结果,这就增加了缓存的响应延迟。
- 异步写回策略:优先考虑响应延迟,此时所有写请求都在缓存中处理。等到这些增改的数据要被缓存淘汰时,缓存将它回写到后端数据库,这样一来,处理这些数据的操作实在缓存中进行的,很快就能完成,不过数据有丢失风险。
应用场景
- 在商品大促的场景中,商品的库存信息会一直被修改,如果每次修改都需要在数据库中处理,就会拖慢整个应用。选择读写缓存的模式。
- 短视频APP场景中,视频的属性很多,但是修改不频繁,此时数据库中进行修改对缓存影响不大,所以选择只读缓存模式。
五.Redis只读缓存和使用直写策略的读写缓存,这两中缓存都会把数据同步写到后端数据库中,他们的区别在于:
- 使用只读缓存时,是先把修改写到后端数据库中,再把缓存中的数据删除。当下次访问这个数据时,会以后端数据库中的值为准,重新加载到缓存中。这样做的优点是,数据库和缓存可以保证完全一致,并且缓存中永远保留的是经常访问的热点数据。缺点是每次修改操作都会把缓存中的数据删除,之后访问时都会先触发一次缓存缺失,然后从后端数据库加载数据到缓存中,这个过程访问延迟会变大。
- 使用读写缓存时,是同时修改数据库和缓存中的值。这样做的优点是,被修改后的数据永远在缓存中存在,下次访问时,能够直接命中缓存,不用再从后端数据库中查询,这个过程拥有比较好的性能,比较适合先修改又立即访问的业务场景。但缺点是在高并发场景下,如果存在多个操作同时修改同一个值的情况,可能会导致缓存和数据库的不一致。
- 当使用只读缓存时,如果修改数据库失败了,那么缓存中的数据也不会被删除,此时数据库和缓存中的数据依旧保持一致。而使用读写缓存时,如果是先修改缓存,后修改数据库,如果缓存修改成功,而数据库修改失败了,那么此时数据库和缓存数据就不一致了。如果先修改数据库,再修改缓存,也会产生上面所说的并发场景下的不一致。
- 只读缓存是牺牲了一定的性能,优先保证数据库和缓存的一致性,它更适合对于一致性要求比较要高的业务场景。而如果对于数据库和缓存一致性要求不高,或者不存在并发修改同一个值的情况,那么使用读写缓存就比较合适,它可以保证更好的访问性能。
这篇关于Redis核心技术与实战-学习笔记(二十三):旁路缓存-Redis是怎么工作的的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!