redis——基础服务

news/2024/7/2 1:10:39

首先为什么要做一个redis出来?数据库不够用了吗?考虑到原本的应用程序是客户端访问服务端,服务端访问业务数据需要去数据库去拿,而数据库是个持久化的应用程序,是需要磁盘IO的,这就导致了速度会慢,并且如果存在大量的访问,会导致数据库崩溃。除去导致崩溃这样严重且极端的情况,这点性能虽然对一个二个用户来说并没有什么感知,但是对于应用程序来说,是个有着很大加速空间的点,为了吃这部分性能,出现了redis[^1],承担了缓存的作用。目前,redis因为它的高性能,出现了很多应用场景。

[redis是什么初衷 • Worktile社区](https://worktile.com/kb/ask/755946.html)

什么是Redis?为什么要用Redis? - 知乎 (zhihu.com)

做一个缓存简单,应用程序选择合适的数据结构向redis中存储键值对,redis开辟内存空间存储,一个缓存就做好了。有什么问题吗?想想应用程序是如何使用redis的:不论是数据库亦是应用程序本身的键,选择redis提供的数据结构,然后向里面set后,数据就保存在里面了,就这么一直一直放,即便有过期时间,也有把内存塞满的可能,哪怕几率很小,那作为一个为其他服务提供服务的服务,也要解决这个问题——不能让应用程序把自己的内存空间塞满而崩溃。

这样就会主要涉及到两个问题:

  • 过了期的键怎么删除
  • 内存满了怎么处理

针对上面的两个问题,按顺序介绍解决方案,以及为什么是这样:

  • 删除过期键?

    挨个检索是不现实的,数量太大,如果停下来去专门清理,则会影响到主要的业务,那么就需要其他的策略。但是删除前需要准确地找到设置了过期时间的键,这涉及到redis的内存是怎么组织的(键管理)。

    (这个图我不会画,也画不好,因此找到了网上几篇优秀的博客的图片并附上链接以作补充)

    图片 普通的键值对存储 较完整的redis键管理
    来源 一文讲清楚Redis 内存模型,Redis 的快是有理由的! - 知乎 (zhihu.com) 详解 Redis 内存管理机制和实现 - 知乎 (zhihu.com)

    左图是一对键"hello"->"world"的存储模型,如果是默认的存储(默认redis创建16个db,redis-cli连接到redis-server使用的是db0),并且没有设置过期时间,就是存到db0的redisDb中的dict下,table指向dictEntry按顺序往下存储,dictEntry的组织形式如图所示。内存模型传递的一个信息很重要,也就是设置了过期时间的键存储在一起的,这也是redis可以随机删除过期了的键的基础,不然删除时找一个键是永久的,再找一个还是永久的,删除过期的键这个任务又要快速,岂不是这次任务执行的效率极低?

    从内存模型扯回来谈过期策略。redis提供了两种过期策略,分别是:

    • 惰性删除: 惰性删除很好理解,当有人要用到这个键,查到键是在过期字典里,那先判断是不是过期了,如果过期了就不返回,并且将键删除。可能有人有疑问,既然还在内存中,已经有请求想要访问这个键,为什么不返回一次再删除?我个人的理解是绝对不可以返回,有几点理由:
      • 返回不符合逻辑:已经过期的键,理想状态下就应该不存在。我是被动地让它存在在内存中,如果我有更好的办法能让它自动消失,它早已不存在,返回的话语义不一致。
      • 可能造成错误:这个要根据场景来具体地考虑。比如存储token,如果token已经过期,那么用户携带的token不应该能通过登录,如果还能成功返回用户就可能登录成功访问账户里的资源,这一操作可能是危险的。(比如token过期了几天,这个键值对都好运地没有被删除)
    • 定时删除: 这是一个相对复杂的算法。现在我们已知的是,所有存放了过期时间的键已经码好了,排成一排放在那,redis提供的策略是每秒扫描 10 次,即100ms检查一次是否有键过期,这是可以通过配置调整的。不过这一过程不能扫描全部,上面也提到这样做会阻塞线程,导致主要的工作长时间不响应,本身redis就是用来应对高并发,这是致命的。那么具体是怎么做的呢?首先推荐一篇博客,从源码级别来解读,并且条理清晰:Redis学习笔记(三)redis 的键管理 - 归思君 - 博客园 (cnblogs.com)不过,既然作为我自己的学习笔记,一定要留下我的理解和记录,大致流程——从过期字典中随机抽取20个键进行删除,如果删除超过25%就再次执行,再抽取20个键删除,直到删除的个数小于等于25%,这是do-while循环中做的。并且会确定一个执行删除算法的时长,如果执行删除算法的时间太长,则会退出这个删除过程,默认删除过程最多执行25ms左右。也即如果这时有key想要set,最多也就等待25ms。redis删除的操作显得格外小心,以提供安稳的服务,这对于我们应用开发者有启示吗?当然是有的。这提示我们要设置合理的过期时间,在应用程序中也要精打细算,尽可能不然大量的key在同一时间过期[^2],那么最佳实践是如果有很多key要一起放入redis中的时候,最好将过期时间分散一下,在”应用需要的过期时间后“加上一个随机的散列值,使得删除时的循环尽可能地早退出。
  • 内存(快)满了怎么办?

    即便有过期时间的限制,redis依然有可能被“挤满”,这是不可避免的。而redis无法控制应用程序的行为,那么只能本身提供坚强的服务,当内存满了的时候,redis应该怎么做能让自己运行的更久,这是redis的开发者应该考虑的事情。

    没有什么别的办法,内存满了就只能删除,即常常提到的内存淘汰。首先是时机,redis有很多监控自己状态的指标,这里用到的是maxmemory。字面意思,当使用的内存达到了这个值,那么redis就认为自己已经存满了,就要执行一些内存淘汰策略来释放自己的空间。主要有以下几种策略:

    • noeviction:不淘汰任何数据,当内存不足时,执行缓存新增操作会报错,默认
    • allkeys-lru:淘汰整个键值中最久未使用的键值。
    • allkeys-random:随机淘汰任意键值。
    • volatile-lru:淘汰所有设置了过期时间的键值中最久未使用的键值。
    • volatile-random:随机淘汰设置了过期时间的任意键值。
    • volatile-ttl:优先淘汰更早过期的键值。
    • **volatile-lfu: **淘汰所有设置了过期时间的键值中最少使用的键值。
    • **alkeys-lfu: **淘汰整个键值中最少使用的键值

    alkeys 开头的表示从所有键值中淘汰相关数据,而 volatile 表示从设置了过期键的键值中淘汰数据。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hjln.cn/news/46970.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈,一经查实,立即删除!

相关文章

接口测试:Mock 的价值与意义

简介 做测试的过程中,对于一些不容易构造、不容易获取的对象,用一个虚拟的对象来替代它,来达到相同的效果,这个虚拟的对象就是 Mock。当做测试的时候,如果后端某些接口还不成熟、所依赖的接口不稳定或者所依赖的接口为第三方接口、构造依赖的接口数据太复杂等等这些问题的…

【CC2DX引擎分析】Action动作的执行流程源码分析

cocos2dx内Action动作的管理与执行流程在引擎源码上的分析。 本文旨在自己对cocos2dx引擎学习的一个笔记总结,对Action动作源码进行分析,加深对动作执行流程的把握,学习架构并之后更好的提高代码质量。 分析总览 从main函数中的Application::getInstance()->run();开始作…

实验一 客户端脚本编程

一、实验目的 通过设计一个个人主页网站,学习常用的HTML标记,学习使用CSS对页面进行美化,掌握JavaScript的语法和常用的浏览器对象,初步学会使用Eclipse创建网站和编辑网页的方法。 二、实验内容和要求 1) 自己设计网页内容,做一张展示自己网页。要求展示的主要内容有:基…

Linux 提权-MySQL UDF

本文通过 Google 翻译 MySQL User Defined Functions – Linux Privilege Escalation 这篇文章所产生,本人仅是对机器翻译中部分表达别扭的字词进行了校正及个别注释补充。导航0 前言 1 什么是用户定义函数 (UDF) ? 2 枚举 UDF 漏洞利用条件2.1 手动枚举 UDF 漏洞利用条件2.1…

1.2 陶瓷电容(MLCC)选型----硬件设计指南(持续补充更新)

本系列文章是笔者总结多年工作经验,结合理论与实践进行整理备忘的笔记。希望能直接指导硬件工程师的设计实操,争取每一条设计要点指南都做到有理有据。既能帮助自己温习整理避免遗忘也能帮助其他需要参考的朋友。笔者也会不定期根据遇到的问题和想起的要点进行查漏补缺。如有…

Profibus转Modbus网关帮助PLC实现智能激光设备通讯

通过Profibus转Modbus网关(XD-MDPB100),可以实现PLC与激光设备之间的无缝连接,实现数据的实时传输与指令的可靠执行。本文将深入探讨PLC通过Profibus转Modbus网关(XD-MDPB100)与激光设备进行通讯的应用案例,带您一窥其中的奥秘。它简单易实现,具有良好的兼容性和可靠性…

【Spring】Bean管理

获取Bean 要从IOC容器当中来获取到bean对象,需要先拿到IOC容器对象@Autowiredprivate ApplicationContext applicationContext; //IOC容器对象Spring容器中提供了一些方法,可以主动从IOC容器中获取到bean对象,下面介绍3种常用方式:根据name获取bean Object getBean(String …

记录--createObjectURL这个API真好用,我举几个场景你们就懂了

🧑‍💻 写在开头 点赞 + 收藏 === 学会🤣🤣🤣 前言 随着我用 URL.createObjectURL 这个 API 越来越多次,越发感觉真的是一个很好用的方法,列举一下我在项目中用到它的场景吧~图片预览 以前我们想要预览图片,只能是上传图片到后端后,获取到url然后赋予给img标签,…