Redis核心技术与实战-学习笔记(二十三):旁路缓存-Redis是怎么工作的

本文主要是介绍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只读缓存和使用直写策略的读写缓存,这两中缓存都会把数据同步写到后端数据库中,他们的区别在于:

   

  1. 使用只读缓存时,是先把修改写到后端数据库中,再把缓存中的数据删除。当下次访问这个数据时,会以后端数据库中的值为准,重新加载到缓存中。这样做的优点是,数据库和缓存可以保证完全一致,并且缓存中永远保留的是经常访问的热点数据。缺点是每次修改操作都会把缓存中的数据删除,之后访问时都会先触发一次缓存缺失,然后从后端数据库加载数据到缓存中,这个过程访问延迟会变大。
  2. 使用读写缓存时,是同时修改数据库和缓存中的值。这样做的优点是,被修改后的数据永远在缓存中存在,下次访问时,能够直接命中缓存,不用再从后端数据库中查询,这个过程拥有比较好的性能,比较适合先修改又立即访问的业务场景。但缺点是在高并发场景下,如果存在多个操作同时修改同一个值的情况,可能会导致缓存和数据库的不一致。
  3. 当使用只读缓存时,如果修改数据库失败了,那么缓存中的数据也不会被删除,此时数据库和缓存中的数据依旧保持一致。而使用读写缓存时,如果是先修改缓存,后修改数据库,如果缓存修改成功,而数据库修改失败了,那么此时数据库和缓存数据就不一致了。如果先修改数据库,再修改缓存,也会产生上面所说的并发场景下的不一致。
  4. 只读缓存是牺牲了一定的性能,优先保证数据库和缓存的一致性,它更适合对于一致性要求比较要高的业务场景。而如果对于数据库和缓存一致性要求不高,或者不存在并发修改同一个值的情况,那么使用读写缓存就比较合适,它可以保证更好的访问性能。

这篇关于Redis核心技术与实战-学习笔记(二十三):旁路缓存-Redis是怎么工作的的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/190370

相关文章

redis过期key的删除策略介绍

《redis过期key的删除策略介绍》:本文主要介绍redis过期key的删除策略,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录第一种策略:被动删除第二种策略:定期删除第三种策略:强制删除关于big key的清理UNLINK命令FLUSHALL/FLUSHDB命

Redis消息队列实现异步秒杀功能

《Redis消息队列实现异步秒杀功能》在高并发场景下,为了提高秒杀业务的性能,可将部分工作交给Redis处理,并通过异步方式执行,Redis提供了多种数据结构来实现消息队列,总结三种,本文详细介绍Re... 目录1 Redis消息队列1.1 List 结构1.2 Pub/Sub 模式1.3 Stream 结

SpringBoot中配置Redis连接池的完整指南

《SpringBoot中配置Redis连接池的完整指南》这篇文章主要为大家详细介绍了SpringBoot中配置Redis连接池的完整指南,文中的示例代码讲解详细,具有一定的借鉴价值,感兴趣的小伙伴可以... 目录一、添加依赖二、配置 Redis 连接池三、测试 Redis 操作四、完整示例代码(一)pom.

Python列表去重的4种核心方法与实战指南详解

《Python列表去重的4种核心方法与实战指南详解》在Python开发中,处理列表数据时经常需要去除重复元素,本文将详细介绍4种最实用的列表去重方法,有需要的小伙伴可以根据自己的需要进行选择... 目录方法1:集合(set)去重法(最快速)方法2:顺序遍历法(保持顺序)方法3:副本删除法(原地修改)方法4:

在Spring Boot中浅尝内存泄漏的实战记录

《在SpringBoot中浅尝内存泄漏的实战记录》本文给大家分享在SpringBoot中浅尝内存泄漏的实战记录,结合实例代码给大家介绍的非常详细,感兴趣的朋友一起看看吧... 目录使用静态集合持有对象引用,阻止GC回收关键点:可执行代码:验证:1,运行程序(启动时添加JVM参数限制堆大小):2,访问 htt

电脑死机无反应怎么强制重启? 一文读懂方法及注意事项

《电脑死机无反应怎么强制重启?一文读懂方法及注意事项》在日常使用电脑的过程中,我们难免会遇到电脑无法正常启动的情况,本文将详细介绍几种常见的电脑强制开机方法,并探讨在强制开机后应注意的事项,以及如何... 在日常生活和工作中,我们经常会遇到电脑突然无反应的情况,这时候强制重启就成了解决问题的“救命稻草”。那

Redis在windows环境下如何启动

《Redis在windows环境下如何启动》:本文主要介绍Redis在windows环境下如何启动的实现方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Redis在Windows环境下启动1.在redis的安装目录下2.输入·redis-server.exe

Go 语言中的select语句详解及工作原理

《Go语言中的select语句详解及工作原理》在Go语言中,select语句是用于处理多个通道(channel)操作的一种控制结构,它类似于switch语句,本文给大家介绍Go语言中的select语... 目录Go 语言中的 select 是做什么的基本功能语法工作原理示例示例 1:监听多个通道示例 2:带

利用Python快速搭建Markdown笔记发布系统

《利用Python快速搭建Markdown笔记发布系统》这篇文章主要为大家详细介绍了使用Python生态的成熟工具,在30分钟内搭建一个支持Markdown渲染、分类标签、全文搜索的私有化知识发布系统... 目录引言:为什么要自建知识博客一、技术选型:极简主义开发栈二、系统架构设计三、核心代码实现(分步解析

Redis实现延迟任务的三种方法详解

《Redis实现延迟任务的三种方法详解》延迟任务(DelayedTask)是指在未来的某个时间点,执行相应的任务,本文为大家整理了三种常见的实现方法,感兴趣的小伙伴可以参考一下... 目录1.前言2.Redis如何实现延迟任务3.代码实现3.1. 过期键通知事件实现3.2. 使用ZSet实现延迟任务3.3