Redis缓存何以一枝独秀?——从百变应用场景与热门面试题中感受下Redis的核心特性与使用注意点

news2024/11/24 4:04:20

大家好,又见面了。


本文是笔者作为掘金技术社区签约作者的身份输出的缓存专栏系列内容,将会通过系列专题,讲清楚缓存的方方面面。如果感兴趣,欢迎关注以获取后续更新。


作为《深入理解缓存原理与实战设计》系列专栏,在前面的文章中,我们一起领略了Guava Cache、Caffeine、Ehcache等优秀的本地JVM级别本地缓存框架的特性、原理与具体的使用方法。除却本地缓存之外,在当前分布式、微服务等架构盛行的时代,本地缓存明显无法满足大型系统中的各种缓存诉求,比如前面文章中反复提及的缓存漂移问题、以及单机缓存无法逾越的内存容量瓶颈。作为应对之法,集中式缓存被广泛的使用在各中分布式系统中,而使用最广泛的莫过于大家耳熟能详的Redis了。

提到Redis,大家应该都不会陌生,至少应该是有听过这个名字。在中大型分布式系统中,Redis似乎成了一种标配,而说到集中缓存,很多人脑海中第一闪过的也是Redis。Redis是一个基于内存的非关系型数据库(NoSQL),主要是存储key-value类型的键值对数据,而value则支持多种不同的类型。由于其强悍的性能表现以及完善的可靠性与集群扩展机制,使其俘获了众多开发人员的青睐,成为了高并发系统的制胜法宝。接下来的几篇文章中呢,我们就一起聊一聊与Redis有关的内容,探讨下Redis在集中式缓存领域一枝独秀的秘诀。

Redis的各种数据类型

作为缓存组件,Redis的数据结构整体而言就是key-value类型的键值对,但是Redis对于value类型的支持还是比较丰富的,提供了5种不同的数据结构,可以满足大部分场景的使用诉求。

对几种类型的结构特点与使用注意点梳理汇总如下:

类型说明支持功能
string普通字符串字符串的基础增删改查能力,如果是整数或者浮点数,还支持自增自减能力。
list链表内容,每个元素都是一个独立的字符串,内容可以相同基础增删改查能力,从链表两端插入或者弹出元素,按照下标获取指定元素列表等等
set无序集合,每个元素都是一个独立字符串,元素之间不允许重复基础增删改查能力,判断元素是否存在,随机获取元素等等
hash无序的key-value键值对集合基础增删改查能力,获取所有的键值对
zset可以理解为一种比较特殊的hash结构,含有member和score两个概念,对应到hash类型上分别是key与value的关系,其区别点在在于score是固定的double类型的value基础增删改查能力,支持根据score排序并获取指定的排序个数的元素列表

实际的使用中,也会根据各自类型不同的特点,用来实现不同的业务诉求。

举个例子:

一个系统内的通知公告查看功能,可以将公告ID作为key,然后这边通知公告的阅读量作为score,在redis中存储为zset类型,然后每次读取详情操作的都累加更新下对应的score值,这样的话,就可以根据score进行降序排列,拉取到热门新闻公告的排行榜。

Redis的百变应用场景

基于Redis提供的基础能力,在项目中不同场景都有被广泛的使用,下面列举几个常见的使用场景。

  • 分布式锁

在分布式系统里面经常会需要用到分布式锁,实现分布式锁的方式有很多种,其中使用的比较广泛的一种策略,就是基于Redis来实现的。之所以采用Redis来作为分布式锁,可以有几方面理由:

  1. redis足够的快
  2. redis提供了setnx + expire的机制,完全契合分布式锁的实现要点
  3. Redisson客户端的流行,使得基于redis的分布式锁更加简单
  • 数据库扛压层

借助redis超高的处理性能,经常会被放置在数据库的前面,用于数据扛压场景使用。比如各种秒杀场景,可以将数据库中的库存信息缓存到redis中,然后利用redis来抗住秒杀期间洪水般的大并发量请求。

  • 登录验证码存储

这个场景也很常见,比如用户发送的短信验证码,一般都会要求5分钟内有效。这种情况下,可以将验证码信息存储在redis中并设定5分钟后自动过期。这样的话就可以实现超时失效的功能,而无需业务层面去维护过期信息。

  • 全局ID生成&全局限流

在分布式系统中,Redis作为一个可以被所有节点访问的集中节点,加上其具备的incrby原子命令,使得在多个场景下发挥价值:

  1. 将其用作全局唯一ID的生成,以保证各个节点之间生成的唯一ID不会冲突。

  2. incrby可以实现全局请求量的统计计数,结合expire一起可以实现定时重置计数器,进而实现限流能力

  • bitmap方式存储每日签到数据

其实,Redis还支持位图(Bitmap)格式进行数据存储。前面我们说Redis支持五种数据结构里面并没有看到Bitmap类型的身影,其实Redis的bitmap数据最终存储的是string类型,但是Redis为Bitmap操作提供了配套的操作接口,比如setbit命令。

位图的存在就是为了服务于海量数据的存储场景的,比如系统里面有10亿用户,现在需要记录每个人每天的签到情况,每天10亿数据量,如果用普通String类型存储,每天10亿条数据量,时间一久任何的Redis也扛不住。而基于bitmap的方式存储,则可以极大的降低整体数据量。关于redis的bitmap操作与使用,后面文章会展开阐述。

  • 热门榜单生成

基于Redis的zset数据结构,可以将热门值作为score进行存储,这样可以根据需要,按照score进行排序并拉取榜单数据。

后端面试中的常客

这篇文章中,我们改变下以往的文章行文叙事风格。我们先不直接切入到Redis的具体特性或功能点的实现原理与使用层面,而是先从面试场景作为切入口,通过几个面试问题,来感受下Redis整体的“魅力”、引出Redis所具备的核心特性与常见使用注意事项。

因为Redis在项目中的广泛使用,也让其成为了后端面试中的热门嘉宾。很多小伙伴应该在面试中都被问过与Redis有关的问题吧?当然有很多的八股文背诵一下就可以应付很多简单的面试场景,但笔者作为面试官一般不太会直接去问八股文问题,经常会将问题稍作包装之后再去问。

下面举几个例子。

Q1. 很多人都说Redis处理快是因为它是单线程的,Redis进程中真的只有一个线程吗?为什么常规项目中为了提升并发量都会采用线程池等方式来多线程处理,而Redis却反其道而行之呢?

很多的面试八股文中都会提到说Redis是单线程的,这个说法其实不够严谨,因为Redis中并非是只有一个线程,整个进程中还有一些额外的线程负责做一些辅助的其他事务,比如管理与客户端的连接,比如队列中消息的维护等等。

Redis整体基于一种多路复用的机制来实现请求的接收与分配处理。整体简化后的处理逻辑如下图所示。

所以说,其实Redis仅仅是采用单线程来负责执行命令请求处理,而非整个Redis就是一个单线程的。回到最初的问题,为什么Redis选择采用单线程的方式来执行命令。在多线程编程的时候面临问题主要有:

  • 并发线程安全问题, 需要保证操作的先后顺序,需要保证同一时刻只能有1个线程对某个对象进行写操作 —— 需要构建完备的同步保护机制,会对整体性能造成影响。
  • 多线程维护的系统额外开销 —— CPU需要不停的在多个线程之间进行切换,由此会带来一系列的额外开销。

而由于Redis是一种key-value模型的数据结构模式,比如很多查询操作都是O(1)的时间复杂度,其操作执行速度非常快,所以这种情况下,结合I/O多路复用模型一起,使用单线程的方式执行命令,反而可以达到比多线程更加优异的表现。

问题可以进一步引申,可以继续聊一些其他问题。比如:

  • 既然Redis是单线程的,那使用的时候有什么需要注意的事项吗?
    不能执行耗时操作,会阻塞其余请求命令的执行。

  • I/O多路复用是个什么概念?它和BIONIO之间有什么异同?
    诸如此类的问题,都可以进一步的去展开考察。

  • 当前计算机一般都是多核CPU,用单线程去执行的话,相当于其它几个核就浪费了,那有什么方式可以将其余的几个核也利用起来么?
    答案其实也不难,在一台机器上同时去部署多个Redis进程,组成个集群,就可以啦。

Q2. 如果我想要查询一下生产环境的Redis中有多少以“User_”开头的记录数量,可以怎么做?

这个问题其实是有一点小陷阱的。查找以指定前缀开头的记录,首先很多同学想到的就是keys命令,但问题中有个约束是在生产环境中执行。所以这个问题看似简单,其实需要结合如下几点来综合考虑:

  1. 通常情况下,生产环境中的数据量是非常大的、且请求并发量会比较高;
  2. Redis的keys命令是一个耗时操作,复杂度O(n),数据量越大执行速度越慢;
  3. Redis的命令执行是单线程执行的。

基于上述几点因素,如果在数据量较大的生产环境去执行keys命令将会导致执行耗时特别长,而由于Redis是单线程执行命令,就会导致其余请求命令被阻塞无法执行,这样在一个高并发集群内,很容易造成集群内请求的大面积阻塞,影响系统的整体稳定性。

那么keys命令不可以用,有什么替代方案呢?可以使用scan命令。

Q3. 假如有一批机器,内存都比较小(单机内存小于整体待缓存数据量),用来搭建个Redis做热点数据缓存扛压以降低数据库的请求压力。如果你来做的话,会有哪些应对思路呢?

这个问题就比较开放,而且答案也不唯一,考核的点也比较综合。

首先来分析下题目,从题干描述中可以捕捉到几个信息,以及对应的关联知识点:

  1. 单机内存小于整体数据量,所以想要将所有数据全量加载到单机内存里面是不可行的;
  2. 使用Redis的用途是扛压来降低数据库访问压力的,也就是允许部分请求穿透Redis打到数据库上的,所以可以考虑将有限内存用来存放热点数据,扛住大部分的流量;
  3. 题目说有一批机器,就是说机器的数量不止一台,所以可以考虑构建集群的方式,扩展Redis集群总内存大小,这样以集群的力量来缓存全部的数据量。

所以说这个题目里面其实涉及到了两个考点:

  1. 热点数据的概念、也即Redis的数据淘汰策略。
  2. Redis集群扩展的相关概念。

更进一步,又可以引申出很多其它细节问题,比如:

  • Redis中的数据淘汰策略有哪些?
    no-enviction、volatile-lru、volatile-ttl、volatile-random、allkeys-lru、allkeys-random

  • Redis的数据淘汰策略与数据过期有啥区别?
    数据过期是达到了设定的过期时间之后使数据不可用,而数据淘汰策略主要是在容量满之后采取的被动应对策略。

  • Redis集群中是如何决定一个记录应该保存在哪个节点上的?
    关于一致性Hash相关的内容,以及如何解决数据倾斜问题、节点扩容对缓存命中情况的影响等等。

回头看下,是不是其中蕴含的内容还是蛮多的?

这里我们以面试场景中会被问及的几个问题作为切入点,大概聊了下与Redis有关的一系列内容。当然这里介绍的都比较浅显,甚至只是列了下相关的知识点,主要是先让大家先感受下Redis所包含与涉及的相关知识点。在后续的文章中,我们将逐步逐个地去剖析与介绍。

小结回顾

好啦,作为redis部分的第一篇内容,我们只是简单的聊了下Redis的基础概念以及主要的特性介绍,同时通过几个实际的面试题演示了下Redis整体内容的“博大精深”。而关于Redis的更多细化方向的展开阐述,我们将会在后续文章中逐步介绍。那么你对Redis如何看呢?欢迎评论区一起交流下,期待和各位小伙伴们一起切磋、共同成长。

📣 补充说明1

本文属于《深入理解缓存原理与实战设计》系列专栏的内容之一。该专栏围绕缓存这个宏大命题进行展开阐述,全方位、系统性地深度剖析各种缓存实现策略与原理、以及缓存的各种用法、各种问题应对策略,并一起探讨下缓存设计的哲学。

如果有兴趣,也欢迎关注此专栏。

📣 补充说明2

  • 关于本文中涉及的演示代码的完整示例,我已经整理并提交到github中,如果您有需要,可以自取:https://github.com/veezean/JavaBasicSkills

我是悟道,聊技术、又不仅仅聊技术~

如果觉得有用,请点赞 + 关注让我感受到您的支持。全网同名,欢迎关注,获取更及时的更新。

期待与你一起探讨,一起成长为更好的自己。

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

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

相关文章

国产高清卫星影像时代来了,打造中国版“谷歌地球”!

随着国家数字化战略转型进程不断加快,卫星遥感影像作为基础数据,应用越来越广泛。目前已经成为资源环境调查、监测、评价和管理等不可或缺的技术手段。 不止于此,在推动行业发展、提高生产力以及节约成本等方面,卫星遥感影像都实…

【半监督医学图像分割 2022 CVPR】S4CVnet 论文翻译

【半监督医学图像分割 2022 CVPR】S4CVnet论文翻译 论文题目:When CNN Meet with ViT: Towards Semi-Supervised Learning for Multi-Class Medical Image Semantic Segmentation 中文题目:当CNN与ViT相遇:面向多类医学图像语义分割的半监督学习 论文链接…

kotlin必备基础一

kotlin 必备基础方法的声明成员方法类方法(静态方法)单表达式方法局部方法方法高级特性高阶函数函数作为参数函数作为返回值闭包(Cloure)闭包的特性闭包的好处解构申明匿名方法kotlin 方法字面值方法参数默认参数可变数量参数Lamb…

【机器学习】K近邻算法(K-NearestNeighbors , KNN)详解 + Java代码实现

文章目录一、KNN 基本介绍二、KNN 核心思想三、KNN 算法流程四、KNN 优缺点五、Java 代码实现 KNN六、KNN 改进策略一、KNN 基本介绍 邻近算法,或者说K最邻近(KNN,K-NearestNeighbors)分类算法是分类方法中最简单的方法之一。所谓…

Cadence PCB仿真使用Allegro PCB SI为分立元件创建统一的模型并赋值方法图文教程

⏪《上一篇》   🏡《总目录》   ⏩《下一篇》 目录 1,概述2,配置方法3,总结1,概述 本文简单介绍使用Allegro PCB SI软件配置电压地网络电压的方法。 2,配置方法 第1步:打开待仿真的PCB文件,并确认软件为Allegro PCB SI 如果,打开软件不是Allegro PCB SI则可这样…

[ 数据结构 ] 背包问题(动态规划)

0 背包问题 有一个背包,容量为4磅,现有如下物品 物品重量价格吉他(G)11500音响(S)43000电脑(L)32000 1)要求达到的目标为装入的背包的总价值最大,并且重量不超出 2)要求装入的物品不能重复(01背包) 1 动态规划 动态规划(Dynamic Programming)算法的核心思想是&…

从0到1完成一个Vue后台管理项目(十一、前端分页实现)

往期 从0到1完成一个Vue后台管理项目(一、创建项目) 从0到1完成一个Vue后台管理项目(二、使用element-ui) 从0到1完成一个Vue后台管理项目(三、使用SCSS/LESS,安装图标库) 从0到1完成一个Vu…

测试分析--精准分析

测试分析的概念 测试分析是建立在对「需求本身」、「用户使用场景」以及对应的「系统架构」和「实现细节」的充分了解的基础上,通过对数据流、状态变化、逻辑时序、功能/性能/兼容性等方面的分析,得出测试点的过程; 在现阶段敏捷开发模式普遍…

【部分真题】2022年12月QMS质量管理体系试题(1-5题)尚大解析版

注1:由于是机考,题目顺序随机变化,但题目内容所有考生一致。 注2:选择题的选项顺序会随机改变,但选项的内容不变。 注3:为了方便学员学习与复习,已经按教程&考试大纲进行全面优化排序。 注4…

4644. 求和

4644. 求和 https://www.acwing.com/problem/content/description/4647/ 第十三届蓝桥杯省赛CA/C组 , 第十三届蓝桥杯省赛JAVAA组 算法标签:推公式;前缀和 思路 推公式做法: (a1a2a3...an)2a12a22a32...an22a1a22a1a3...2a1an2a2a3...2an−…

【模板】最小生成树(C++)

题目描述 如题,给出一个无向图,求出最小生成树,如果该图不连通,则输出 orz。 输入格式 第一行包含两个整数 N,MN,MN,M,表示该图共有 NNN 个结点和 MMM 条无向边。 接下来 MMM 行每行包含三个整数 Xi,Yi,ZiX_i,Y_i,…

设计师必备的免费样机素材

很多设计师会用样机模型来展示自己的作品,让设计图案、应用界面等作品应用到实物效果图中,能体现作品的最终效果,更加形象逼真。哪里能下载到样机模板呢?今天我就推荐6个网站帮你解决,赶紧收藏! 1、菜鸟图库…

20230109测试ToyBrick的RK3588开发板运行Buildroot的V0.02版本(20220312)

20230109测试ToyBrick的RK3588开发板运行Buildroot的V0.02版本(20220312) 2023/1/9 18:03 https://wiki.t-firefly.com/zh_CN/Firefly-Linux-Guide/manual_buildroot.html 1. Buildroot 使用手册 1.1. 桌面应用 官方发布的 Buildroot 固件,默…

RabbitMQ学习一【尚硅谷】

一、消息队列 1、MQ的相关概念 2、RabbitMQ 2.1 四大核心概念 生产者: 交换机:交换机是 RabbitMQ非常重要的一个部件,一方面它接收来自生产者的消息,另一方面它将消息 推送到队列中。交换机必须确切知道如何处理它接收到的消息…

一文详解Linux Python3安装

在公司申请了一台CentOS 7的Linux版本虚拟机,需要安装一个Python3的环境,定期进行特定任务处理。这里对CentOS 7配置Python3环境的步骤进行了记录,供大家参考。 本文基于如下Linux系统版本: 一、默认Python版本 默认情况下&am…

Excelize 2.7.0 发布, 2023 年首个更新

Excelize 是 Go 语言编写的用于操作 Office Excel 文档基础库,基于 ECMA-376,ISO/IEC 29500 国际标准。可以使用它来读取、写入由 Microsoft Excel™ 2007 及以上版本创建的电子表格文档。支持 XLAM / XLSM / XLSX / XLTM / XLTX 等多种文档格式&#xf…

C 程序设计教程(13)—— 顺序结构程序设计练习题

C 程序设计教程(13)—— 顺序结构程序设计练习题 该专栏主要介绍 C 语言的基本语法,作为《程序设计语言》课程的课件与参考资料,用于《程序设计语言》课程的教学,供入门级用户阅读。 目录C 程序设计教程(1…

【openGauss】在openEuler(ARM架构)上安装openGauss(一主两备含CM版)

一、系统版本介绍 当前案例中的openGauss安装,底层操作系统为openEuler-20.03-LTS版本,当前openGauss对Python版本兼容性最好的是Python 3.6版本与Python 3.7版本,该实验使用的openEuler版本自带Python 3.7.4,不需要再自行安装 二…

汽车电子系统网络安全活动

声明 本文是学习GB-T 38628-2020 信息安全技术 汽车电子系统网络安全指南. 下载地址 http://github5.com/view/764而整理的学习笔记,分享出来希望更多人受益,如果存在侵权请及时联系我们 汽车电子系统网络安全活动 7.1 概念设计阶段 7.1.1 概述 概念设计阶段的活动流程如图…

房产管理系统分布架构分析

一、数图互通房产管理系统采用分布式架构下的高可用设计: (1)可以避免因单点故障造成系统平台宕机: a、负载均衡技术(failover ,选址,硬件负载,软件负载,去中心化负载(g…