搜索
首页数据库RedisRedis的技术要点有哪些
Redis的技术要点有哪些Jun 04, 2023 am 08:27 AM
redis

一、为什么使用Redis

在项目中使用Redis,笔者认为需要从性能和并发两个方面考虑。当然,Redis还具备可做分布式锁等功能的其它功能,但如果只是为了分布式锁这些其它功能,完全还有其它中间件(如Zookpeer等)可以代替,并不是非要使用Redis。

因此,这个问题主要从性能和并发两个角度去答:

1、性能

如下图所示,我们在碰到需要执行耗时特别久、且结果不频繁变动的SQL时,就特别适合将运行结果放入缓存。这样,后面的请求就去缓存中读取,使得请求能够迅速响应。

Redis的技术要点有哪些

题外话:忽然想聊一下这个迅速响应的标准——其实根据交互效果的不同,这个响应时间没有固定标准。有人曾经向我表达的意思是:“理想情况下,我们的页面跳转应该瞬间完成,而页内操作需要在刹那间完成。”。另外,超过一弹指的耗时操作要有进度提示,并且可以随时中止或取消,这样才能给用户最好的体验。”

那么瞬间、刹那、一弹指具体是多少时间呢?

根据《摩诃僧祗律》记载:一刹那者为一念,二十念为一瞬,二十瞬为一弹指,二十弹指为一罗预,二十罗预为一须臾,一日一夜有三十须臾。

那么,经过周密的计算,一瞬间为0.36秒,一刹那有0.018秒,一弹指长达7.2秒。

2、并发

当并发量很高时,所有请求直接访问数据库会导致数据库连接异常,如图所示。为了避免直接访问数据库,我们可以在这种情况下使用Redis做缓冲操作,让请求先访问Redis。

Redis的技术要点有哪些

二、使用Redis有什么缺点

大家用Redis这么久,这个问题是必须要了解的,基本上使用Redis都会碰到一些问题,常见的主要是四方面的问题:

1、缓存和数据库双写一致性问题

2、缓存雪崩问题

3、缓存击穿问题

4、缓存的并发竞争问题

这四个问题,笔者个人觉得在项目中比较常遇见,具体解决方案,后文会给出。

三、单线程的Redis为什么这么快

这个问题其实是对Redis内部机制的一个考察。在笔者的面试经验中,实际上许多人没有意识到Redis采用单线程工作模型。所以,这个问题还是应该要复习一下的。主要是以下三点:

1、纯内存操作

2、单线程操作,避免了频繁的上下文切换

3、采用了非阻塞I/O多路复用机制

让我们更详细地讨论一下I/O多路复用机制,因为这个术语过于通俗,普通人不能理解其含义。打一个比方:小曲在S城开了一家快递店,负责同城快送服务。由于资金限制,小曲最初雇佣了很多快递员,但后来发现只有购买一辆车才有足够的资金运营快递。

经营方式一:

客户每送来一份快递,小曲就让一个快递员盯着,然后快递员开车去送快递。慢慢的小曲就发现了这种经营方式存在很多问题,几十个快递员基本上时间都花在了抢车上了,大部分快递员都处在闲置状态,谁抢到了车,谁就能去送快递。

随着快递的增多,快递员也越来越多,小曲发现快递店里越来越挤,没办法雇佣新的快递员了,快递员之间的协调很花时间,大部分时间花在抢车上。综合上述缺点,小曲痛定思痛,提出了下面的经营方式↓

经营方式二:

小曲只聘用了一个快递员,将客户送来的快递按照目的地分类标注后,整齐地放置在一个地方。最终,快递员按顺序取快递,一个一个拿走,驾车送出快递后再返回获取下一个快递。

上述两种经营方式对比,是不是明显觉得第二种,效率更高、更好呢?在上述比喻中:

1、每个快递员→每个线程

2、每个快递→每个Socket(I/O流)

3、快递的送达地点→Socket的不同状态

4、客户送快递请求→来自客户端的请求

5、小曲的经营方式→服务端运行的代码

6、一辆车→CPU的核数

于是我们有如下结论:

1、经营方式一就是传统的并发模型,每个I/O流(快递)都有一个新的线程(快递员)管理。

2、经营方式二就是I/O多路复用。一个快递员通过跟踪每个I/O流的状态,来管理多个I/O流,类似于快递员只有单独一人去送递每个包裹,且需知道每个包裹的送达情况。

下面类比到真实的Redis线程模型,如图所示:

Redis的技术要点有哪些

参照上图,简单来说就是,我们的Redis-client在操作的时候,会产生具有不同事件类型的Socket。在服务端,有一段I/O多路复用程序,将其置入队列之中。然后文件事件分派器依次去队列中取,转发到不同的事件处理器中。

需要说明的是,这个I/O多路复用机制,Redis还提供了Select、Epoll、Evport、Kqueue等多路复用函数库,大家可以自行去了解。

四、Redis的数据类型及各自使用场景

看到这个问题,是不是觉得它很基础?其实笔者也这么觉得。然而根据面试经验发现,至少80%的人答不上这个问题。建议在项目中用到后,再类比记忆,体会更深,不要硬记。基本上,一个合格的程序员五种类型都会用到:

1、String

这个其实没什么好说的,最常规的Set/Get操作,Value可以是String也可以是数字,一般做一些复杂的计数功能的缓存。

2、Hash

这里的Value是一个包含结构化对象的变量,它允许方便地操作其中的特定字段。笔者在做单点登录的时候,就是用这种数据结构存储用户信息,以CookieId作为Key,设置30分钟为缓存过期时间,能很好地模拟出类似Session的效果。

3、List

使用List的数据结构,可以做简单的消息队列的功能。除此之外,还可以使用 Redis 的 Lrange 命令来实现分页功能,其性能非常优异,能够提供良好的用户体验。

4、Set

因为Set堆放的是一堆不重复值的集合,所以可以做全局去重的功能。

为什么不用JVM自带的Set进行去重?因为我们的系统一般都是集群部署,使用JVM自带的Set比较麻烦,难道为了做一个全局去重,再起一个公共服务?太麻烦了。

另外,就是利用交集、并集、差集等操作,可以计算共同喜好、全部的喜好、自己独有的喜好等功能。

5、Sorted Set

通过给集合中的元素赋予Score参数,Sorted Set可以根据Score对元素进行排序。可以做排行榜应用,取TOP N操作。另外,Sorted Set还可以用来做延时任务。最后一个应用就是可以做范围查找。

五、Redis的过期策略及内存淘汰机制

这个问题的重要性不言而喻,它能揭示Redis是否得到了正确的应用。例如,如果你的Redis仅能存储5G的数据,而你写入了10G,则会删除5G的数据。怎么删的?这个问题思考过么?还有,你的数据已经设置了过期时间,但是时间到了,内存占用率还是比较高,有思考过原因么?

Redis采用的是定期删除 惰性删除策略。

为什么不用定时删除策略?

定时删除,用一个定时器来负责监视Key,过期则自动删除。虽然内存及时释放,但是十分消耗CPU资源。在大并发请求下,CPU要将时间应用在处理请求,而不是删除Key,因此没有采用这一策略。

定期删除 惰性删除是如何工作的呢?

定期删除,Redis默认每个100ms检查是否有过期的Key,有过期Key则删除。需要说明的是,Redis不是每个100ms将所有的Key检查一次,而是随机抽取进行检查(如果每隔100ms,全部Key进行检查,Redis岂不是卡死)。因此,如果只采用定期删除策略,会导致很多Key到时间没有删除。

于是,惰性删除派上用场。也就是说在你获取某个Key的时候,Redis会检查一下,这个Key如果设置了过期时间,那么是否过期了?如果过期了此时就会删除。

采用定期删除 惰性删除就没其他问题了么?

不是的,如果定期删除没删除Key。然后你也没及时去请求Key,也就是说惰性删除也没生效。为了防止Redis的内存不断增加,需要启用内存淘汰机制。

在Redis.conf中有一行配置:

# maxmemory-policy volatile-lru

该配置就是配内存淘汰策略的:

Noeviction:当内存不足以容纳新写入数据时,新写入操作会报错。应该没人使用吧;

Allkeys-lru:当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的Key。推荐使用,目前项目在用这种;

Allkeys-random:当内存不足以容纳新写入数据时,在键空间中,随机移除某个key,应该也没人使用吧;

Volatile-lru:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,移除最近最少使用的Key。这种情况一般是把Redis既当缓存又做持久化存储的时候才用。不推荐;

Volatile-random:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,随机移除某个Key。依然不推荐;

Volatile-ttl:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,有更早过期时间的Key优先移除。不推荐。

PS:如果没有设置Expire的Key,不满足先决条件(Prerequisites);那么Volatile-lru、Volatile-random和Volatile-ttl策略的行为,和Noeviction(不删除)基本上一致。

六、Redis和数据库双写一致性问题

一致性问题是分布式常见问题,还可以再分为最终一致性和强一致性。数据库和缓存双写,就必然会存在不一致的问题,想要回答这个问题,就要先明白一个前提:如果对数据有强一致性要求,就不能放缓存。我们所做的一切,只能保证最终一致性。

我们提出的方案只能减少不一致发生的可能性,而不能完全杜绝。因此,有强一致性要求的数据不能放缓存。

《分布式数据库与缓存双写一致性方案解疑》

给出了详细的分析,在这里简单地说一说:首先,采取正确更新策略,先更新数据库,再删缓存;其次,因为可能存在删除缓存失败的问题,提供一个补偿措施即可,例如利用消息队列。

七、应对缓存穿透和缓存雪崩问题

一般中小型传统软件企业很少会遇到缓存穿透和缓存雪崩这两个问题。如果要处理数百万级别的流量,这两个问题必须经过深思熟虑:

1、应对缓存穿透

缓存穿透,即黑客故意去请求缓存中不存在的数据,导致所有的请求都怼到数据库上,从而数据库连接异常。

解决方案:

利用互斥锁,缓存失效的时候,先去获得锁,得到锁了,再去请求数据库,没得到锁,则休眠一段时间重试;

1、采用异步更新策略,无论Key是否取到值,都直接返回。Value值中维护一个缓存失效时间,缓存如果过期,异步起一个线程去读数据库,更新缓存,需要做缓存预热(项目启动前,先加载缓存)操作;

2、提供一个能迅速判断请求是否有效的拦截机制,比如利用布隆过滤器,内部维护一系列合法有效的Key,迅速判断出,请求所携带的Key是否合法有效,如果不合法,则直接返回。

2、应对缓存雪崩

缓存雪崩,即缓存同一时间大面积的失效,这个时候又来了一波请求,结果请求都怼到数据库上,从而导致数据库连接异常。

解决方案:

1、给缓存的失效时间加上一个随机值,避免集体失效;

2、使用互斥锁,但是该方案吞吐量明显下降了;

3、双缓存。我们有两个缓存,缓存A和缓存B。缓存A的失效时间为20分钟,缓存B不设失效时间,自己做缓存预热操作。

然后细分以下几个小点:

a. 从缓存A读数据库,有则直接返回;

b. A 没有数据,直接从B读数据,直接返回,并且异步启动一个更新线程;

c. 更新线程同时更新缓存A和缓存B。

八、如何解决Redis并发竞争Key问题

这个问题大致就是同时有多个子系统去Set一个Key。在这种情况下,应该注意使用Redis事务机制。根据我提前在百度上的搜索结果,大部分人推荐使用这种方法。但本人不推荐使用Redis的事务机制。我们在生产环境中主要使用Redis集群,并且进行了数据分片处理。当你在一个事务中涉及多个Key操作时,这些Key不一定都存储在同一个Redis-Server上。因此,Redis的事务机制,十分鸡肋。

解决方法如下:

如果对这个Key操作不要求顺序

这种情况下,准备一个分布式锁,大家去抢锁,抢到锁就做Set操作即可,比较简单。

如果对这个Key操作要求顺序

假设有一个Key1,系统A需要将Key1设置为ValueA,系统B需要将Key1设置为ValueB,系统C需要将Key1设置为ValueC。希望根据Key1的Value值以ValueA→ValueB→ValueC的顺序进行变化。这种时候我们在数据写入数据库的时候,需要保存一个时间戳。假设时间戳如下:

1、系统A Key 1 {ValueA  3:00}

2、系统B Key 1 {ValueB  3:05}

3、系统C Key 1 {ValueC  3:10}

那么,假设这会系统B先抢到锁,将Key1设置为{ValueB 3:05}。如果系统A抢到锁后发现其ValueA的时间戳早于缓存中的时间戳,则不会执行Set操作。以此类推。

以上是Redis的技术要点有哪些的详细内容。更多信息请关注PHP中文网其他相关文章!

声明
本文转载于:亿速云。如有侵权,请联系admin@php.cn删除
es和redis区别es和redis区别Jul 06, 2019 pm 01:45 PM

Redis是现在最热门的key-value数据库,Redis的最大特点是key-value存储所带来的简单和高性能;相较于MongoDB和Redis,晚一年发布的ES可能知名度要低一些,ES的特点是搜索,ES是围绕搜索设计的。

一起来聊聊Redis有什么优势和特点一起来聊聊Redis有什么优势和特点May 16, 2022 pm 06:04 PM

本篇文章给大家带来了关于redis的相关知识,其中主要介绍了关于redis的一些优势和特点,Redis 是一个开源的使用ANSI C语言编写、遵守 BSD 协议、支持网络、可基于内存、分布式存储数据库,下面一起来看一下,希望对大家有帮助。

实例详解Redis Cluster集群收缩主从节点实例详解Redis Cluster集群收缩主从节点Apr 21, 2022 pm 06:23 PM

本篇文章给大家带来了关于redis的相关知识,其中主要介绍了Redis Cluster集群收缩主从节点的相关问题,包括了Cluster集群收缩概念、将6390主节点从集群中收缩、验证数据迁移过程是否导致数据异常等,希望对大家有帮助。

详细解析Redis中命令的原子性详细解析Redis中命令的原子性Jun 01, 2022 am 11:58 AM

本篇文章给大家带来了关于redis的相关知识,其中主要介绍了关于原子操作中命令原子性的相关问题,包括了处理并发的方案、编程模型、多IO线程以及单命令的相关内容,下面一起看一下,希望对大家有帮助。

Redis实现排行榜及相同积分按时间排序功能的实现Redis实现排行榜及相同积分按时间排序功能的实现Aug 22, 2022 pm 05:51 PM

本篇文章给大家带来了关于redis的相关知识,其中主要介绍了Redis实现排行榜及相同积分按时间排序,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,希望对大家有帮助。

实例详解Redis实现排行榜及相同积分按时间排序功能的实现实例详解Redis实现排行榜及相同积分按时间排序功能的实现Aug 26, 2022 pm 02:09 PM

本篇文章给大家带来了关于redis的相关知识,其中主要介绍了Redis实现排行榜及相同积分按时间排序,本文通过实例代码给大家介绍的非常详细,下面一起来看一下,希望对大家有帮助。

一文搞懂redis的bitmap一文搞懂redis的bitmapApr 27, 2022 pm 07:48 PM

本篇文章给大家带来了关于redis的相关知识,其中主要介绍了bitmap问题,Redis 为我们提供了位图这一数据结构,位图数据结构其实并不是一个全新的玩意,我们可以简单的认为就是个数组,只是里面的内容只能为0或1而已,希望对大家有帮助。

一起聊聊Redis实现秒杀的问题一起聊聊Redis实现秒杀的问题May 27, 2022 am 11:40 AM

本篇文章给大家带来了关于redis的相关知识,其中主要介绍了关于实现秒杀的相关内容,包括了秒杀逻辑、存在的链接超时、超卖和库存遗留的问题,下面一起来看一下,希望对大家有帮助。

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

仓库:如何复兴队友
1 个月前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.能量晶体解释及其做什么(黄色晶体)
2 周前By尊渡假赌尊渡假赌尊渡假赌
Hello Kitty Island冒险:如何获得巨型种子
1 个月前By尊渡假赌尊渡假赌尊渡假赌

热工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

适用于 Eclipse 的 SAP NetWeaver 服务器适配器

适用于 Eclipse 的 SAP NetWeaver 服务器适配器

将Eclipse与SAP NetWeaver应用服务器集成。

Atom编辑器mac版下载

Atom编辑器mac版下载

最流行的的开源编辑器

mPDF

mPDF

mPDF是一个PHP库,可以从UTF-8编码的HTML生成PDF文件。原作者Ian Back编写mPDF以从他的网站上“即时”输出PDF文件,并处理不同的语言。与原始脚本如HTML2FPDF相比,它的速度较慢,并且在使用Unicode字体时生成的文件较大,但支持CSS样式等,并进行了大量增强。支持几乎所有语言,包括RTL(阿拉伯语和希伯来语)和CJK(中日韩)。支持嵌套的块级元素(如P、DIV),

SecLists

SecLists

SecLists是最终安全测试人员的伙伴。它是一个包含各种类型列表的集合,这些列表在安全评估过程中经常使用,都在一个地方。SecLists通过方便地提供安全测试人员可能需要的所有列表,帮助提高安全测试的效率和生产力。列表类型包括用户名、密码、URL、模糊测试有效载荷、敏感数据模式、Web shell等等。测试人员只需将此存储库拉到新的测试机上,他就可以访问到所需的每种类型的列表。