热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

redis解析:缓存及常见问题!

01没缓存的日子对于web来说,是用户量和访问量支持项目技术的更迭和前进。随着服务用户提升。可能会出现一下的一些状况:页面并发量和访问量并不多

01 没缓存的日子

对于web来说,是用户量和访问量支持项目技术的更迭和前进。随着服务用户提升。可能会出现一下的一些状况:

页面并发量和访问量并不多,mysql足以支撑自己逻辑业务的发展。那么其实可以不加缓存。最多对静态页面进行缓存即可。

页面的并发量显著增多,数据库有些压力,并且有些数据更新频率较低反复被查询或者查询速度较慢。那么就可以考虑使用缓存技术优化。对高命中的对象存到key-value形式的redis中,那么,如果数据被命中,那么可以省经效率很低的db。从高效的redis中查找到数据。

当然,可能还会遇到其他问题,你可以需要静态页面本地缓存,cdn加速,甚至负载均衡这些方法提高系统并发量。这里就不做介绍。


02 缓存思想无处不在

我们从一个算法问题开始了解缓存的意义。

问题1&#xff1a;输入一个数n(n<20),求n&#xff01;&#xff1b;

分析1&#xff1a;单单考虑算法&#xff0c;不考虑数值越界问题。当然我们知道n!&#61;n * (n-1) * (n-2) * ... * 1&#61; n * (n-1)!;那么我们可以用一个递归函数解决问题。

这样每输入求一次需要执行n次。

问题2&#xff1a;输入t组数据(可能成百上千)&#xff0c;每组一个x(n<20),求x&#xff01;&#xff1b;

分析2&#xff1a;

时间复杂度才O(n)。这里的思想就和缓存思想差不多。先将数据在jiecheng[21]数组中储存。执行一次计算。当后面继续访问的时候就相当于当问静态数组值。为O(1)。就能大大的减少查询、执行成本啦&#xff01;


03 缓存的应用场景

 

缓存适用于高并发的场景&#xff0c;提升服务容量。主要是将从经常被访问的数据或者查询成本较高从慢的介质中存到比较快的介质中&#xff0c;比如从硬盘—>内存。我们知道大多数关系数据库是基于硬盘读写的&#xff0c;其效率和资源有限&#xff0c;而redis等非关系型就是基于内存存储。其效率差别很大。当然&#xff0c;缓存也分为本地缓存和服务端缓存&#xff0c;这里只讲redis的服务端缓存。

举个例子。例如如果一个接口sql查询需要2s。你每次查询都会2s并且加载的时候都会等在&#xff0c;这个长期等待给用户的体验是非常糟糕的。而用户能够接受的往往是第一次的等待。如果你用了缓存技术。你第一次查询放到redis里面。然后数据再从redis返回给你。后面当你继续访问这个数据的时候。查询到redis中有备份&#xff0c;那么不需要通过db直接能从redis中获取数据。那么&#xff0c;你想想&#xff0c;从一个key value的Nosql中取一个value能要多久呢&#xff01;

所以对于像样的&#xff0c;有点规模的网站&#xff0c;缓存isnecessary的.redis也是必不可少的。并且服务端的缓存设计也是要根据业务有所区别的。也要防止占用内存过大&#xff0c;redis雪崩等问题。


04 需要注意的问题

缓存使用不当会带来很多问题。所以需要对一些细节进行认真考量和设计。笔者对于分布式的经验并不是很丰富&#xff0c;就相对于笔者的眼中谈谈缓存设计不好会带来那些问题。

&#xff08;1&#xff09;是否用缓存

现在不少项目&#xff0c;为了缓存而缓存&#xff0c;然而缓存并不是适合所有场景&#xff0c;比如如果对数据一致性要求极高&#xff0c;又或者数据频繁更改而查询并不多。有的可以不需要缓存。因为如果使用redis缓存多多少少可能会遇到数据一致性问题。那你可以考虑使用redis做成分布式锁去锁sql的数据。同样如果频繁更新数据&#xff0c;那么redis能起到的作用就仅仅是多了一层中转站。反而浪费资源。使得传输过程臃肿。

&#xff08;2&#xff09;过期策略选择

大部分场景不适合缓存一致存在&#xff0c;首先&#xff0c;你的sql数据库的内容可能很多就不说了&#xff0c;另外&#xff0c;返回给你的对象如果是完整的pojo对象还好&#xff0c;但是如果是使用不同参数各种关联查询出来的结果那么redis中会储存太多冷数据。占用资源而得不到销毁。我们学过操作系统也知道在计算机的缓存实现中有&#xff09;先进先出的算法&#xff08;FIFO&#xff09;&#xff1b;最近最少使用算法&#xff08;LRU&#xff09;&#xff1b;最佳淘汰算法&#xff08;OPT&#xff09;&#xff1b;最少访问页面算法&#xff08;LFR&#xff09;等磁盘调度算法。对于web开发也可以借鉴。根据时间来的FIFO是最好实现的。因为redis在全局key支持过期策略。

而开发中可能还会遇到其他问题。比如过期时间的选择上&#xff0c;如果过久会导致数据聚集。而过少可能导致频繁查询数据库甚至可能会导致缓存雪崩等问题。

所以&#xff0c;过期策略一定要设置。并且对于关键key一定要小心谨慎设计。

&#xff08;3&#xff09;数据一致性问题★

上面其实提到数据一致性问题。如果对一致性要求极高那么不建议使用缓存。下面稍微梳理一下缓存的数据。

在redis缓存中经常会遇到数据一致性问题。对于一个缓存。下面罗列逼仄

① 读

read&#xff1a;从redis中读取&#xff0c;如果redis中没有&#xff0c;那么就从mysql中获取更新redis缓存。该流程图描述常规场景。一般没啥争议。

② 写1&#xff1a;先更新数据库&#xff0c;再更新缓存(普通低并发)

更新数据库信息&#xff0c;再更新redis缓存。这是常规做法&#xff0c;缓存基于数据库&#xff0c;取自数据库。但是其中可能遇到一些问题。例如上述如果更新缓存失败(宕机等其他状况)&#xff0c;将会使得数据库和redis数据不一致。造成DB新数据&#xff0c;缓存旧数据

③ 写2&#xff1a;先删除缓存&#xff0c;再写入数据库(低并发优化)

解决的问题

这种情况能够有效避免写1中防止写入redis失败的问题。将缓存删除进行更新。理想是让下次访问redis为空去mysql取得最新值到缓存中。但是这种情况仅限于低并发的场景中而不适用高并发场景。

存在的问题

写2虽然能够看似写入redis异常的问题。看似较为好的解决方案但是在高并发的方案中其实还是有问题的。我们在写1讨论过如果更新库成功&#xff0c;缓存更新失败会导致脏数据。我们理想是删除缓存让下一个线程访问适合更新缓存。问题是&#xff1a;如果这下一个线程来的太早、太巧了呢&#xff1f;

因为多线程你也不知道谁先谁后&#xff0c;谁快谁慢。如上图所示情况&#xff0c;将会出现redis缓存数据和mysql不一致。当然你可以对key进行上锁。但是锁这种重量级的东西对并发功能影响太大&#xff0c;能不用锁就别用&#xff01;上述情况就高并发下依然会造成缓存是旧数据&#xff0c;DB是新数据。并且如果缓存没有过期这个问题会一致存在。

④ 写3&#xff1a;延时双删策略

这个就是延时双删策略&#xff0c;能过缓解在写2中在更新mysql过程中有读的线程进入造成redis缓存与mysql数据不一致。方法就是删除缓存->更新缓存->延时(几百ms)(可异步)再次删除缓存。即使在更新缓存途中发生写2的问题。造成数据不一致&#xff0c;但是延时(具体实间根据业务来&#xff0c;一般几百ms)再次删除也能很快的解决不一致。

但是就写的方案其实还是有漏洞的&#xff0c;比如第二次删除错误、多写多读高并发情况下对mysql访问的压力等等。当然你可以选择用mq等消息队列异步解决。其实实际的解决很难顾及到万无一失&#xff0c;所以不少大佬在设计这一环节可能会因为一些纰漏会被喷。作为菜菜的笔者在这里就更不献丑了&#xff0c;策略只是提供大纲&#xff0c;具体设计还是需要自己团队实践和摸索。并且也对一致性的要求级别有所区别。

⑤ 写4&#xff1a;直接操作缓存&#xff0c;定期写入sql(适合高并发)

当有一堆并发(写)扔过来的后&#xff0c;前面几个方案即使使用消息队列异步通信但也很难给用户一个舒适的体验。并且对大规模操作sql对系统也会造成不小的压力。所以还有一种方案就是直接操作缓存&#xff0c;将缓存定期写入sql。因为redis这种非关系数据库又基于内存操作KV相比传统关系型要快很多(找值最多多碰撞几次)。

上面适用于高并发情况下业务设计&#xff0c;这个时候以redis数据为主&#xff0c;mysql数据为辅助。定期插入(好像数据备份库一样)。当然&#xff0c;这种高并发往往会因为业务对读、写的顺序等等可能有不同要求&#xff0c;可能还要借助消息队列以及锁完成针对业务上对数据和顺序可能会因为高并发、多线程带来的不确定性和不稳定性。提高业务可靠性。

总之&#xff0c;越是高并发、越是对数据一致性要求高的方案在数据一致性的设计方案需要考虑和顾及的越复杂、越多。上述也是笔者针对redis数据一致性问题的学习和自我发散(胡扯)学习。如果有解释理解不合理或者还请联系告知&#xff01;


05 缓存穿透、缓存雪崩和缓存击穿

如果不了解&#xff0c;可能对这几个概念都不了解&#xff0c;听着感觉太高大上&#xff0c;至少笔者刚开始是这么觉得&#xff0c;本文并不是详细介绍如何解决和完美解决&#xff0c;更主要的是认识和认知吧。

&#xff08;1&#xff09;redis缓存穿透

① 理解

重在穿透吧&#xff0c;也就是访问透过redis直接经过mysql&#xff0c;通常是一个不存在的key,在数据库查询为null。每次请求落在数据库、并且高并发。数据库扛不住会挂掉。

② 解决方案

可以将查到的null设成该key的缓存对象。

当然&#xff0c;也可以根据明显错误的key在逻辑层就就行验证。

同时&#xff0c;你也可以分析用户行为&#xff0c;是否为故意请求或者爬虫、攻击者。针对用户访问做限制。

其他等等&#xff0c;比如看到其他人用布隆过滤器(超大型hashmap)过滤。

&#xff08;2&#xff09;redis缓存雪崩

① 理解

雪崩&#xff0c;就是某东西蜂拥而至的意思&#xff0c;像雪崩一样。在这里&#xff0c;就是redis缓存集体大规模集体失效&#xff0c;在高并发情况下突然使得key大规模访问mysql&#xff0c;使得数据库崩掉。可以想象下国家人口老年化。以后那天人集中在70-80岁&#xff0c;就没人干活了。国家劳动力就造成压力。

② 解决方案

通常的解决方案是将key的过期时间后面加上一个随机数&#xff0c;让key均匀的失效。

考虑用队列或者锁让程序执行在压力范围之内&#xff0c;当然这种方案可能会影响并发量。

&#xff08;3&#xff09;redis缓存击穿

① 理解

击穿和穿透不同&#xff0c;穿透的意思是想法绕过redis去使得数据库崩掉。而击穿你可以理解为正面刚击穿,这种通常为大量并发对一个key进行大规模的读写操作。这个key在缓存失效期间大量请求数据库&#xff0c;对数据库造成太大压力使得数据库崩掉。就比如在秒杀场景下10000块钱的mac和100块的mac这个100块的那个订单肯定会被抢到爆。所以缓存击穿就是针对某个常用key大量请求导致数据库崩溃。

② 解决方案

能够达到这种场景的公司其实不多&#xff0c;我也不清楚他们的具体处理方法&#xff0c;但是一个锁拦截请求总是能防止数据库崩掉吧。


06 总结与感悟

其实缓存看起来&#xff0c;理解起来看似简单然而实际上的设计方案非常有学问。在细节设计上还会遇到消息队列、布隆过滤器、分布式锁、服务降级、熔断、分流这些。在缓存处理上甚至还有缓存预热(提前缓存部分热点数据防止刚开始缓存全部命中导致服务崩掉)等其他热门名词和问题这里就不做介绍了。

 


推荐阅读
  • 本文深入探讨了NoSQL数据库的四大主要类型:键值对存储、文档存储、列式存储和图数据库。NoSQL(Not Only SQL)是指一系列非关系型数据库系统,它们不依赖于固定模式的数据存储方式,能够灵活处理大规模、高并发的数据需求。键值对存储适用于简单的数据结构;文档存储支持复杂的数据对象;列式存储优化了大数据量的读写性能;而图数据库则擅长处理复杂的关系网络。每种类型的NoSQL数据库都有其独特的优势和应用场景,本文将详细分析它们的特点及应用实例。 ... [详细]
  • 字节跳动深圳研发中心安全业务团队正在火热招募人才! ... [详细]
  • NoSQL数据库,即非关系型数据库,有时也被称作Not Only SQL,是一种区别于传统关系型数据库的管理系统。这类数据库设计用于处理大规模、高并发的数据存储与查询需求,特别适用于需要快速读写大量非结构化或半结构化数据的应用场景。NoSQL数据库通过牺牲部分一致性来换取更高的可扩展性和性能,支持分布式部署,能够有效应对互联网时代的海量数据挑战。 ... [详细]
  • Linux学习精华:程序管理、终端种类与命令帮助获取方法综述 ... [详细]
  • 阿里巴巴终面技术挑战:如何利用 UDP 实现 TCP 功能?
    在阿里巴巴的技术面试中,技术总监曾提出一道关于如何利用 UDP 实现 TCP 功能的问题。当时回答得不够理想,因此事后进行了详细总结。通过与总监的进一步交流,了解到这是一道常见的阿里面试题。面试官的主要目的是考察应聘者对 UDP 和 TCP 在原理上的差异的理解,以及如何通过 UDP 实现类似 TCP 的可靠传输机制。 ... [详细]
  • 美团优选推荐系统架构师 L7/L8:算法与工程深度融合 ... [详细]
  • 网站访问全流程解析
    本文详细介绍了从用户在浏览器中输入一个域名(如www.yy.com)到页面完全展示的整个过程,包括DNS解析、TCP连接、请求响应等多个步骤。 ... [详细]
  • 在多线程并发环境中,普通变量的操作往往是线程不安全的。本文通过一个简单的例子,展示了如何使用 AtomicInteger 类及其核心的 CAS 无锁算法来保证线程安全。 ... [详细]
  • 在CentOS 7环境中安装配置Redis及使用Redis Desktop Manager连接时的注意事项与技巧
    在 CentOS 7 环境中安装和配置 Redis 时,需要注意一些关键步骤和最佳实践。本文详细介绍了从安装 Redis 到配置其基本参数的全过程,并提供了使用 Redis Desktop Manager 连接 Redis 服务器的技巧和注意事项。此外,还探讨了如何优化性能和确保数据安全,帮助用户在生产环境中高效地管理和使用 Redis。 ... [详细]
  • Cosmos生态系统为何迅速崛起,波卡作为跨链巨头应如何应对挑战?
    Cosmos生态系统为何迅速崛起,波卡作为跨链巨头应如何应对挑战? ... [详细]
  • 深入浅析JVM垃圾回收机制与收集器概述
    本文基于《深入理解Java虚拟机:JVM高级特性与最佳实践(第3版)》的阅读心得进行整理,详细探讨了JVM的垃圾回收机制及其各类收集器的特点与应用场景。通过分析不同垃圾收集器的工作原理和性能表现,帮助读者深入了解JVM内存管理的核心技术,为优化Java应用程序提供实用指导。 ... [详细]
  • 本文深入解析了Java 8并发编程中的`AtomicInteger`类,详细探讨了其源码实现和应用场景。`AtomicInteger`通过硬件级别的原子操作,确保了整型变量在多线程环境下的安全性和高效性,避免了传统加锁方式带来的性能开销。文章不仅剖析了`AtomicInteger`的内部机制,还结合实际案例展示了其在并发编程中的优势和使用技巧。 ... [详细]
  • 智能制造数据综合分析与应用解决方案
    在智能制造领域,生产数据通过先进的采集设备收集,并利用时序数据库或关系型数据库进行高效存储。这些数据经过处理后,通过可视化数据大屏呈现,为生产车间、生产控制中心以及管理层提供实时、精准的信息支持,助力不同应用场景下的决策优化和效率提升。 ... [详细]
  • 为何Serverless将成为未来十年的主导技术领域?
    为何Serverless将成为未来十年的主导技术领域? ... [详细]
  • 随着各类门户网站、短视频平台、剧集播放和在线教育等互联网内容生态的迅猛发展,网络流量呈现爆炸性增长。为提升用户体验,边缘云计算与CDN(内容分发网络)技术应运而生。这些技术通过在靠近用户的位置部署节点,有效降低了数据传输延迟,提高了内容加载速度,确保用户能够通过手机或电脑流畅访问互联网资源。此外,边缘计算还能够在本地处理部分数据,进一步减轻核心网络的压力,优化整体网络性能。 ... [详细]
author-avatar
昔日重来r_510
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有