当前位置: 首页 > news >正文

Redis简介

一、什么是Redis?

        Redis是一种基于内存的数据库,对数据的读写操作都是在内存中完成的,因此读写速度非常快,常用于缓存、消息队列、分布式锁等场景。

        Redis提供了多种数据类型来支持不同的业务场景,比如String(字符串)、Hash(哈希)、List(列表)、Set(集合)、Zset(有序集合)等,并且对数据类型的操作都是原子性的,因为执行命令由单线程负责的,不存在并发竞争问题。

        除此之外,Redis还支持事务、持久化、Lua脚本、多种集群方案(主从复制模式、哨兵模式、切片机群模式)、发布/订阅模式、内存淘汰机制、过期删除机制等等。

二、为什么用Redis作为Mysql的缓存?

主要是因为Redis具备高性能和高并发两种特性。

1、Redis具备高性能

        假如用户第一次访问Mysql中的某些数据,这个过程会比较慢,因为是从硬盘上读取的。将该用户访问的数据缓存在Redis中,这样下一次在访问这些数据的时候就可以直接从缓存中读取了,操作Redis缓存就是直接操作内存,所以速度相当快。(读写操作)

        如果Mysql中的对应数据改变之后,同步改变Redis缓存中相应的数据即可。

2、Redis具备高并发

        单台设备的Redis的QPS(Query Per Second,每秒钟处理完请求的次数)是Mysql的10倍,Redis单机的QPS能轻松突破10w,而Mysql单机的QPS很难破1W。

        所以,直接访问Redis能够承受的请求是远远大于直接访问Mysql的,所以我们可以考虑把数据库中的部分数据转移到缓存中去,这样用户的一部分请求会直接到缓存这里而不用经过数据库。

三、Redis线程模型

1、Redis是单线程吗?

        Redis单线程指的是接收客户端请求->解析请求->进行数据读写等操作->发送数据给客户端这个过程是由一个线程(主线程)来完成,这也是我们常说Redis是单线程的原因。

        但是,Redis并不是单线程的,Redis在启动的时候,是会启动后台线程的:

  • Redis在2.6版本,会启动2个后台线程,分别处理关闭文件、AOF刷盘这两个任务;
  • Redis在4.0版本之后,新增了一个后台线程,用来异步释放Redis内存,也就是lazyfree线程。例如执行unlink key/ flushdb async/ flushall async等命令,会把这些删除操作交给后台线程来执行,好处是不会导致主线程卡顿。因此,当我们要删除一个大key的时候,不要使用del命令删除,因为del是在主线程处理的,这样会导致Redis主线程卡顿,因此我们应该使用unlink命令来异步删除大key。

        之所以Redis为关闭文件、AOF刷盘、释放内存这些任务创建单独的线程来处理,是因为这些任务的操作都是很耗时的,如果把这些任务都放在主线程来处理,那么Redis主线程就很容易发生阻塞,这样就无法处理后续的请求了。

        后台线程相当于一个消费者,生产者把耗时任务丢到任务队列中,消费者(BIO)不停轮询这个队列,拿出任务就去执行对应的方法即可。

        关闭文件、AOF刷盘、释放内存这三个任务都有各自的任务队列:

  •  BIO_CLOSE_FILE,关闭文件任务队列:当队列有任务后,后台线程会调用close(fd),将文件关闭;
  • BIO_AOF_FSYNC,AOF刷盘任务队列:当AOF日志配置成everysec选项后,主线程会把AOF写日志操作封装成一个任务,也放到队列中。当发现队列有任务后,后台线程会调用fsync(fd),将AOF文件刷盘;
  • BIO_LAZY_FREE,lazy_free任务队列:当队列有任务后,后台线程会free(obj)释放对象/free(dict)删除数据库所有对象/free(skiplist)释放跳表对象。

2、Redis单线程模式是怎样的?

         图中的蓝色部分是一个事件循环,是由主线程负责的,可以看到网络I/O和命令处理都是单线程。Redis初始化的时候,会做下面这几件事情:

  • 首先,调用epoll_create()创建一个epoll对象和调用socket()创建一个服务端socket
  • 然后,调用bind()绑定端口和调用listen()监听该socket
  • 然后,将调用epoll_ctl()将listen socket加入到epoll,同时注册连接事件处理函数

        初始化完后,主线程就进入到一个事件循环函数,主要会做以下事情:

  • 首先,会调用处理发送队列函数,看是发送队列里是否有任务,如果有发送任务,则通过write函数将客户端发送缓冲区里的数据发送出去,如果这一轮数据没有发送完,就会注册写事件处理函数,等待epoll_wait发现可写后再处理。
  • 接着,调用epoll_wait函数等待事件的到来

        如果是连接事件到来,则会调用连接事件处理函数,该函数会做这些事情:调用accept获取已连接的socket->调用epoll_ctl将已连接的socket加入到epoll->注册读事件处理函数;

        如果是读事件到来,则会调用读事件处理函数,该函数会做这些事情:调用read获取客户端发送的数据->解析命令->处理命令->将客户端对象添加到发送队列->将执行结果写到发送缓冲区等待发送;

        如果是写事件到来,则会调用写事件处理函数,该函数会做这些事情:通过write函数将客户端发送缓冲区的数据发送出去,如果这一轮数据没有发送完,就会继续注册写事件处理函数,等待epoll_wait发现可写后在处理。

3、Redis采用单线程为什么还这么快?

        官方使用基准测试的结果是,单线程的Redis吞吐量达到10W/每秒,如下图所示:

       之所以Redis采用单线程(网络I/O和执行命令)那么快,有如下几个原因:

  • Redis的大部分操作都在内存中完成,并且采用了高效的数据结构,因此Redis瓶颈可能是机器的内存或者网络带宽,而并非CPU,既然CPU不是瓶颈,那么自然就采用单线程的解决方案了;
  • Redis采用单线程模型可以避免多线程之间的竞争,省去了多线程切换带来的时间和性能上的开销,而且也不会导致锁问题。
  • Redis采用了I/O多路复用机制处理大量的客户端Socket请求,IO多路复用机制是指一个线程处理多个IO流。

四、RDB持久化

1、Redis如何实现数据不丢失?

        Redis的读写操作都是在内存中,所以Redis性能才会高,但是当Redis重启后,内存中的数据就会丢失,那为了保证内存中的数据不会丢失,Redis实现了数据持久化的机制,这个机制会把数据存储到磁盘,这样在Redis重启就能够从磁盘中恢复原有的数据。

        Redis共有三种数据持久化的方式:

  • AOF日志:每执行一条写操作命令,就把该命令以追加的方式写入到一个文件里;
  • RDB快照:将某一时刻的内存数据,以二进制的方式写入磁盘;
  • 混合持久化方式:Redis 4.0新增的方式,继承了AOF和RDB的优点。

2、AOF日志是如何实现的?

        Redis在执行完一条写操作命令后,就会把该命令已追加的方式写入到一个文件里,然后Redis重启时,会读取该文件记录的命令,然后逐一执行命令的方式来进行数据恢复。

 

五、Redis集群

1、Redis如何实现服务高可用?

        要想设计一个高可用的Redis服务,一定要从Redis的多服务节点来考虑,比如Redis的主从复制、哨兵模式、切片集群。

(1)主从复制

        主从复制是Redis高可用服务的最基础的保证,实现方案就是将从前的一台Redis服务器,同步数据到多台从Redis服务器,即一主多从的模式,且主从服务器之间采用的是读写分离的方式。

        主服务器可以进行读写操作,当发生写操作时自动将写操作同步给从服务器,而从服务器一般是只读,并接受主服务器同步过来写操作命令,然后执行这条命令。

         也就是说,所有的数据修改只在主服务器上进行,然后将最新的数据同步给从服务器,这样就使得主从服务器的数据是一致的。

        注意,主从服务器之间的命令复制是异步进行的。

        具体来说,在主从服务器命令传播阶段,主服务器接收到新的写命令后,会发送给从服务器。但是,主服务器并不会等到从服务器实际执行完命令后,再把结果返回给客户端,而是主服务器自己在本地执行完命令后,就会向客户端返回结果了。如果从服务器还没有执行主服务器同步过来的命令,主从服务器之间的数据就不一致了。

        所以,无法实现强一致性保证(主从数据时时刻刻保持一致),数据不一致是难以避免的。

(2)哨兵模式 

        在使用Redis主从服务的时候,会有一个问题,就是当Redis的主从服务器出现故障宕机时,需要手动进行恢复。

        为了解决这个问题,Redis增加了哨兵模式,因为哨兵模式做到了可以监控主从服务器,并且提供主从节点故障转移的功能。

 (3)切片机群模式

        当Redis缓存数据量大到一台服务器无法缓存时,就需要使用Redis切片集群方案,它将数据分布在不同的服务器上,以此来降低系统对单主节点的依赖,从而提高Redis服务的读写性能。

六、Redis过期删除与内存淘汰

1、Redis使用的过期策略是什么?

        Redis是可以对KEY设置过期时间的,因此需要有相应的机制将已过期键值对删除,而做这个工作的就是过期键值删除策略。

        每当我们对一个key设置了过期时间时,Redis会把该key带上过期时间存储到一个过期字典中,也就是说过期字典保存了数据库中所有key的过期时间。

        当我们查询一个Key时,Redis首先检查key是否存在于过期字典中:

  • 如果不在,则正常读取键值;
  • 如果存在,则会获取该key的过期时间,然后与当前系统时间进行比对,如果比系统时间大,那就没有过期,否则判定该key已过期。

        Redis使用的过期删除策略是惰性删除+定期删除这两种策略配合使用。

2、什么是惰性删除策略?

        惰性删除策略的做法是,不主动删除过期键,每次从数据库访问key时,都检测key是否过期,如果过期则删除该key。

 

3、什么是定期删除策略?

        定期删除策略的做法是,每隔一段时间随机从数据库取出一定数量的key进行检查,并删除其中的过期key。

七、Redis缓存设计

 1、如何避免缓存雪崩、缓存击穿、缓存穿透?

(1)缓存雪崩

        通常我们为了保证缓存中的数据与数据库中的数据一致性,会给Redis里的数据设置过期时间,当缓存数据过期后,用户访问的数据如果不在缓存里,业务系统需要重新生成缓存,因此就会访问数据库,并将数据更新到Redis里,这样后续请求都可以直接命中缓存。

        那么,当大量缓存数据在同一时间过期时,如果此时有大量的用户请求,都无法在Redis中处理,于是全部请求都直接访问数据库,从而导致数据库的压力骤增,严重的会造成数据库宕机,从而形成一系列连锁反应,造成整个系统崩溃,这就是缓存雪崩的问题。

        对于缓存雪崩的问题,我们可以采用两种方案解决:

  • 将缓存失效时间随机打散。在原有失效时间的基础上增加一个随机值,这样每个缓存过期的时间就不重复了。
  • 设置缓存不过期。

(2)缓存击穿 

        我们的业务通常会有几个数据会被频繁地访问,比如秒杀活动,这类被频繁地访问的数据称为热点数据。

        如果缓存中的某个热点数据过期了,此时大量的请求访问了该热点数据,就无法从缓存中读取,直接访问数据库,数据库很容易就被高并发的请求冲垮,这就是缓存击穿的问题。

         应对缓存击穿可以采取前面说到的两种方案:

  • 不给热点数据设置过期时间,由后台异步更新缓存,或者在热点数据准备更新前,提前通知后台线程更新缓存以及重新设置过期时间。

(3)缓存穿透

        当发生缓存雪崩或击穿时,数据库中还是保存了应用要访问的数据,一旦恢复相对应的数据,就可以减轻数据库的压力,而缓存穿透就不一样了。

        当用户访问的数据,既不在缓存,也不在数据库中,导致请求在访问缓存时,发现缓存缺失,再去访问数据库时,发现数据库中也没有要访问的数据,没办法构建缓存数据,来服务后续的请求。那么当有大量这样的请求到来时,数据库的压力骤增,这就是缓存穿透的问题。

        

        缓存穿透的发生一般由这两种情况:

  • 业务误操作,缓存中的数据和数据库中的数据都被误删除了,所以导致缓存和数据库中没有数据;
  • 黑客恶意攻击,故意大量访问某些读取不存在数据的业务。

        应对缓存穿透的方案,常见的方案有三种:

  • 非法请求的限制:当有大量恶意请求访问不存在的数据的时候,也会发生缓存穿透,因此要在API处判断请求参数是否合理、是否有非法值、请求字段是否存在,如果判断不符合就直接返回错误。
  • 设置空值或者默认值

        

相关文章:

  • 支付宝沙箱支付报错“订单信息无法识别,建议联系卖家”
  • NOIP2017提高组.宝藏
  • 【强化学习】Deep Reinforcement Learning: A Survey综述学习
  • fast_pow(),c语言幂函数
  • 性能比拼: Go(Gin) vs Python(Flask)
  • 按规则批量修改 txt/html/json/xml/csv/记事本等文本文件内容
  • 【企业级Web应用中的文件下载处理:从S3预签名URL到压缩状态管理】
  • 24、网络编程基础概念
  • Appscan下载及安装教程
  • Vue3中的Icon理方案
  • OCR第三个方案:PP-OCRv4的初步探索
  • 2015年国家队选拔赛试题改编题
  • 基于卷积神经网络的眼疾识别系统,resnet50,efficentnet(pytorch框架,python代码)
  • 什么是开发者社区(Developer Communities)?
  • OCCT(2)Windows平台编译OCCT
  • 【大模型】微调一个大模型需要多少 GPU 显存?
  • 论文阅读《P​roximal Curriculum for Reinforcement Learning Agents》——提升智能体学习速度的
  • 11 配置Hadoop集群-免密登录
  • OpenBMC:BmcWeb 处理http请求3 字典树查找节点
  • 搜索算法------深度优先搜索
  • wordpress做社交网站吗/网站推广怎么优化
  • web网站百度不收录吗/深圳抖音推广公司
  • 河南省建设厅网站136号文件/百度霸屏推广一般多少钱
  • 那个网站教你做美食/今日西安头条最新消息
  • 网站建设的费用预算/爱链
  • 网站开发用哪个软件/电商网页