Redis

Redis是一种高性能的NoSql数据库,支持五种数据类型,如string、list、hash等。它使用单线程模型,基于内存运行,提供快速读写操作。持久化包括RDB快照和AOF日志记录,以防止数据丢失。过期key的删除策略结合定时和惰性删除。Redis支持主从复制、哨兵模式和Cluster集群模式实现高可用性。内存管理和淘汰策略确保高效使用内存。此外,Redis提供事务支持,虽然不完全符合ACID属性,但能满足特定场景的并发需求。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Redis

一、概述

1、是什么?

redis是单进程单线程的,Nginx是多进程多线程的

	Redis是用C语言编写的,高性能NoSql数据库
	可以存储五种不同类型的值,key只能是字符串,value可以是string、list、hash、set、zset
    Redis数据库是基于内存的,读写速度非常快,广泛应用于缓存方向。一秒钟10万次。也常用来做分布式锁,Redis支持事务、持久化、LUA脚本、多种集群方案等   	 
关系型数据库和非关系型数据库的区别?
    关系型数据库:数据和数据之间有联系----存储在硬盘上--------数据不会丢失
    非关系型数据库:数据和数据之间没有联系----存储在内存中--------数据有可能会丢失
2、优缺点:
优点:
    读写速度非常快,读的速度是110000/s,写的速度是81000/s。
    支持数据持久化,RDBAOF两种方式
    支持事务,redis所有操作都是原子性的,同时还支持对几个操作合并后的原子性执行。
    数据结构丰富
    支持主从复制,可以进行读写分离
缺点:
    数据库容量受到物理内存的限制,不能用作海量数据的高性能读写
    Redis 不具备自动容错和恢复功能
    主机宕机,宕机前有部分数据未能及时同步到从机,切换IP后还会引入数据不一致的问题
3、怎么用(为什么要用):
高性能:
    用户访问数据库是从硬盘读取,速度慢,访问redis,是从内存读取,速度快
高并发:
    直接操作缓存能够承受的请求是远远大于直接访问数据库的,我们可以把经常查询,不经常修改的放到缓存中,这样可以大大的减少数据库压力。MySQL的并发是16384  redis的并发 读11万次/s写 8万次/s(超过10+就需要集群了)
高扩展:
	(高可用)数据和数据之间没有联系,可以很方便的扩展
4、Redis为什么这么快
1、完全基于内存,速度非常快
2、采用单线程,避免了不必要的上下文切换和竞争条件
3、数据结构简单,对数据操作也简单

二、数据类型

string  		设置短息验证码 优惠卷 、分类信息   
hash    		存放一个用户的整个信息,存放Session信息,Session分离
list 			秒杀、抢购、12306、异步
set     		一个人只能点一次赞的那种,交集、并集、差集,从而实现共同好友等功能
sortedset   	排行榜  、热搜榜 等  去重+排序

三、持久化

内存的数据写到磁盘中去,防止服务宕机了内存数据丢失。
    
//redis的持久化机制1RDB(快照):默认方式,在一定时间间隔内,检测到key的变化情况,符合配置就是持久化数据。
    		save  900 1       (15分钟内,至少有一个key发生变化,就保存数据)
    		save  300 10	  (在5分钟内,至少有10key发生变化,就保存数据)
    		save  60  10000   (在一分钟内,有10000个可以发生变化,就保存数据)
    		服务器正常关闭也会保存一次数据
    		bgsave 模式
    (2AOF(日志记录模式)可以记录每一条命令的操作,
    		每一次操作持久化
    		每隔一秒持久一次
    		不持久化(系统自动刷盘持久化)
优缺点:
	AOF文件比RDB更新频率高,优先使用AOF还原数据。
    AOFRDB更安全也更大
    RDB性能比AOF好
    如果两个都配了优先加载AOF

四、过期key的删除策略

	Redis中有个设置时间过期的功能,即对存储在 redis 数据库中的值可以设置一个过期时间。登录信息,尤其是短信验证码(expire key 时间)
过期策略通常有以下三种:
	1、定时过期:每个设置过期时间的key都需要创建一个定时器,到过期时间就会立即清除。对内存友好,但是会占用大量CPU资源去处理。
   	2、惰性删除:只有当访问这个key时,才会判断该key是否已过期,过期则清除。可以最大化地节省CPU资源,却对内存非常不友好。可能出现大量的过期key没有再次被访问,从而不会被清除,占用大量内存。
    3、定期删除:每隔一定的时间,扫描一定数量的key,如果过期则删除。因为每隔100ms就遍历所有的设置过期时间的 key 的话,就会给 CPU 带来很大的负载。这个方案是前两种的折中方案,使得CPU和内存资源达到最优的平衡
    Redis中同时使用了惰性过期和定期过期两种过期策略。	

五、内存相关

//MySQL里有2000w数据,redis中只存20w的数据,如何保证redis中的数据都是热点数据
	0、正常来说,就按照内存淘汰策略都可以实现,就是当内存不足的时候,淘汰掉最近最少使用的key
	1、 sortedset数据结构,淘汰调访问频次低的数据
    2、 设置过期时间,每次访问续时,那不经常访问了就过期淘汰了
//当内存不足时,redis的内存淘汰策略?
    //全局的key选择性移除
	当内存不足以容纳新写入数据时,新写入操作会报错。
    当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的key。(常用)
    当内存不足以容纳新写入数据时,在键空间中,随机移除某个key。
    //设置过期时间的key选择性移除
    当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,移除最近最少使用的key。
    当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,随机移除某个key。
    当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,有更早过期时间的key优先移除。
    总结:内存淘汰策略用于处理内存不足时的需要申请额外空间的数据;过期策略用于处理过期的缓存数据。
//Redis主要消耗什么资源?
     内存
//redis内存用完了会怎么办?
     Redis的写命令会返回错误信息(但是读命令还可以正常返回。),如果配置了内存淘汰机制,当Redis达到内存上限时会冲刷掉旧内容。
//redis如何做内存优化?
     不要存很小的数据,尽可能使用hash、set等,比如你要存一个东西,不要姓名、性别、邮箱、密码都设置单独的Key,而是要用hash,存整个对象。

六、事务

//什么是事务:
	事务中的所有命令都会序列化、按顺序地执行。
	事务是一个原子操作:事务中的命令要么全部被执行,要么全部都不执行。
	redis事务就是一次性、顺序性、排他性的执行一个队列中的一系列命令。
//事务的三个阶段:
    1、事务开始 MULTI 2、命令入队  3、事务执行 EXEC
    事务执行过程中,如果服务端收到有EXECDISCARDWATCHMULTI之外的请求,将会把请求放入队列中排队
    
    redis 不支持回滚,“Redis 在事务失败时不进行回滚,而是继续执行余下的命令”
    如果在一个事务中的命令出现错误,那么所有的命令都不会执行;
    如果在一个事务中出现运行错误,那么正确的命令会被执行。
    
//事务特性
    ACID(原子性、一致性、隔离性、持久性)
    Redis具有一致性和隔离性,其他特性不支持。当持久化采用AOF时,并且时记录每一条命令时,也支持持久性
    原子性:不保证、没有回滚、事务中任意命令执行失败,其他命令也会执行。
    一致性:支持
    隔离性:Redis是单进程程序,并且在执行事务的时候,不会对事务进行中断,所以Redis总是具有隔离性
    持久性:参考Redis的两种持久化方式  

七、集群

redis有三种集群方式:主从复制、哨兵模式、集群
主从复制
//主从复制原理:
    从服务器连接主服务器,发送SYNC命令; 
    主服务器接收到SYNC命名后,开始执行同步命令生成RDB文件并使用缓冲区记录此后执行的所有写命令; 
    主服务器BGSAVE执行完后,向所有从服务器发送快照文件,并在发送期间继续记录被执行的写命令; 
    从服务器收到快照文件后丢弃所有旧数据,载入收到的快照; 
    主服务器快照发送完毕后开始向从服务器发送缓冲区中的写命令; 
    从服务器完成对快照的载入,开始接收命令请求,并执行来自主服务器缓冲区的写命令;(从服务器初始化完成)
    主服务器每执行一个写命令就会向从服务器发送相同的写命令,从服务器接收并执行收到的写命令(从服务器初始化完成后的操作)
//主从复制优缺点:
    //优点:
    	支持主从复制,主机会自动将数据同步到从机,可以进行读写分离
    //缺点:
        主数据库唯一,主挂掉,则redis无法对外提供写服务。
哨兵模式
	Redis 2.8中提供了哨兵工具来实现自动化的系统监控和故障恢复功能。当主服务器中断服务后,可以将一个从服务器升级为主服务器,以便继续提供服务。根据优先级选,如果一样就选个id小的。当主数据库重启后,它不再是主数据库,而是作为一个从数据库,从主数据库同步数据。
	哨兵是一个进程,所以哨兵也会启动。多个哨兵可以形成一个哨兵集群。哨兵不要和redis部署在一台机器上,要不让redis挂了,哨兵也挂了。当使用哨兵模式的时候,客户端不要直连redis,而是连哨兵的ip和端口。由哨兵来提供redis实例,这样当主数据库挂掉之后,哨兵会提供给你新的主节点。
//哨兵的作用:
    集群监控:监控主节点和从节点服务是否正常
    消息通知:如果某个redis实例有故障,那么哨兵负责发送消息作为报警通知给管理员。
	故障转移:主服务器出现故障时自动将从服务器转换为主服务器。
哨兵用于实现 redis 集群的高可用,本身也是分布式的,作为一个哨兵集群去运行,互相协同工作。
//原理:
     每个Sentinel(哨兵)进程以每秒钟一次的频率向整个集群中的Master主服务器,Slave从服务器以及其他Sentinel(哨兵)进程发送一个 PING 命令。
	如果一个实例(instance)距离最后一次有效回复 PING 命令的时间超过 down-after-milliseconds 选项所指定的值,则这个实例会被 Sentinel(哨兵)进程标记为主观下线。
	如果一个Master主服务器被标记为主观下线(SDOWN),则正在监视这个Master主服务器的所有 Sentinel(哨兵)进程要以每秒一次的频率确认Master主服务器的确进入了主观下线状态
	当有足够数量的 Sentinel(哨兵)进程(大于等于配置文件指定的值)在指定的时间范围内确认Master主服务器进入了主观下线状态(SDOWN), 则Master主服务器会被标记为客观下线(ODOWN)
    sentinel哨兵就会将新的master节点提供给使用者。
	若没有足够数量的 Sentinel(哨兵)进程同意 Master主服务器下线, Master主服务器的客观下线状态就会被移除。若 Master主服务器重新向 Sentinel(哨兵)进程发送 PING 命令返回有效回复,Master主服务器的主观下线状态就会被移除。	
//优点:
    支持主从复制,主机会自动将数据同步到从机,可以进行读写分离
 	主从可以自动切换,高可用。
//缺点
     主要还是中心架构,仅存在一个主节点,写的效率低
Cluster 集群模式(靠死他)
	但是当数据量过大到一台服务器存放不下的情况时,主从模式或sentinel模式就不能满足需求了,这个时候需要对存储的数据进行分片,将数据存储到多个Redis实例中。cluster模式的出现就是为了解决单机Redis容量有限的问题,将Redis的数据根据一定的规则分配到多台机器,也就是分布式存储。
	Redis Cluster 集群节点最小配置 6 个节点以上(33),其中主节点提供读写操作,从节点作为备用节点,不提供请求,只作为故障转移使用。
//优点:
    无中心架构。(有多个主节点,多个主节点都可以存储数据)
//缺点:
     不支持同时处理多个key(如MSET/MGET),因为redis需要把key均匀分布在各个节点上,并发量很高的情况下同时创建key-value会降低性能并导致不可预测的行为。
     搭建麻烦

八、分区

//:是什么:
	分区是分割数据到多个Redis实例的处理过程
//为什么要分区:
	1、分区可以让Redis管理更大的内存,Redis将可以使用所有机器的内存。如果没有分区,你最多只能使用一台机器的内存。
    2、它允许将计算能力扩展到多核和多台计算机,将网络带宽扩展到多台计算机和网络适配器。
//方式:
    1、按照范围分区(ID0~10000的就分到R010001~20000R1,以此类推,但是有一个缺点是需要一张表来维护这个映射关系。,而且每一个key都需要一个这样的表,因此Redis中的范围分区通常是不受欢迎的,因为它比其他分区方法效率低得多。)
    2、哈希分区(取key,用哈希函数将其转换为一个数,再取模,例如:93024922 % 4 = 2,因此应该存储到R2实例上。)
//不同分区的实现:
    1、客户端分区 : 对于一个给定的key,客户端直接选择正确的节点来进行读写。许多Redis客户端都实现了客户端分区。
	2、代理分区 : 客户端发送请求到一个代理,由代理来和Redis通信,代理根据分区规则决定请求哪些Redis实例,然后根据Redis的响应结果返回给客户端。
	3、查询路由 : 你可以将你的查询发送到任何一个Redis实例,实例会将你的查询重定向到正确的服务器。
//分区有什么特点:
    1、涉及到多个key的操作不会被支持,因为key可能在不同的实例,
    2、事务也不好操作,
    3、分区后,数据的备份会非常复杂,必须从不同的Redis实例和主机同时收集RDB / AOF文件。

九、分布式

//Redis实现分布式锁:
	Redis为单进程单线程模式,采用队列模式将并发访问变成串行访问,且多客户端对Redis的连接并不存在竞争关系Redis中可以使用SETNX命令实现分布式锁。
    SETNX 是『SET if Not eXists』(如果不存在,则 SET)的简写。
    当且仅当 key 不存在,将 key 的值设为 value。 若给定的 key 已经存在,则 SETNX 不做任何动作
//流程:
	使用SETNX命令获取锁,若返回0(key已存在,锁已存在)则获取失败,反之获取成功
	为了防止获取锁后程序出现异常,导致其他线程/进程调用SETNX命令总是返回0而进入死锁状态,需要为该key设置一个“合理”的过期时间
	释放锁,使用DEL命令将锁数据删除

十、缓存异常

//缓存雪崩
	缓存雪崩是指缓存同一时间大面积的失效,所以,后面的请求都会落到数据库上,造成数据库短时间内承受大量请求而崩掉。
    解决:缓存数据的过期时间设置随机,或者说增加一个随机值,这样就很难集体失效,防止同一时间大量数据过期现象发生。
//缓存穿透
	缓存穿透是指缓存和数据库中都没有的数据,导致所有的请求都落到数据库上,造成数据库短时间内承受大量请求而崩掉。要是有人利用不存在的key频繁攻击我们的应用,这就是漏洞。
    解决:从缓存取不到的数据,在数据库中也没有取到,这时也可以将key-value对写为key-null,缓存有效时间可以设置短点,如30秒(设置太长会导致正常情况也没法使用)。这样可以防止攻击用户反复用同一个key暴力攻击
//缓存击穿
	缓存击穿是指缓存中没有但数据库中有的数据(一般是缓存时间到期), 缓存一个"热点"key在某个时间点过期的时候,恰好在这个时间点对这个Key有大量的并发请求过来,这些请求发现缓存过期一般都会从后端DB加载数据并回射到缓存,这个时候大并发的请求可能会瞬间把后端DB压垮。和缓存雪崩不同的是,缓存击穿指并发查同一条数据,缓存雪崩是不同数据都过期了,很多数据都查不到从而查数据库。
    解决:设置热点数据永远不过期。
//缓存预热
	提前将相关的缓存数据直接加载到缓存系统。这样就可以避免在用户请求的时候,先查询数据库,然后再将数据缓存的问题!用户直接查询事先被加载进缓存的缓存数据!
    解决:1、可以在项目启动的时候自动进行加载;   2、定时刷新缓存;
//缓存降级
	服务降级的目的,是为了防止Redis服务故障,导致数据库跟着一起发生雪崩问题。因此,对于不重要的缓存数据,可以采取服务降级策略,
	例如一个比较常见的做法就是,Redis出现问题,不去数据库查询,而是直接返回默认值给用户。
//热点数据和冷数据
	热点数据,缓存才有价值
	对于冷数据而言,大部分数据可能还没有再次访问到就已经被挤出内存,不仅占用内存,而且价值不大。频繁修改的数据,看情况考虑使用缓存

十一、常见问题

//如何保证缓存与数据库双写时的数据一致性?
	先更新数据库,然后再删除缓存
    情况一:先写缓存,再写数据库,缓存写成功,数据库写失败(这个写缓存的方式,本身就是错误的,需要改为先写数据库,把旧缓存置为失效;读取数据的时候,如果缓存不存在,则读取数据库再写缓存) 
    情况二:先写数据库,再写缓存,数据库写成功,缓存写失败(缓存使用时,假如读缓存失败,先读数据库,再回写缓存的方式实现)
    情况三:需要缓存异步刷新(数据库操作和写缓存不在一个操作步骤中,比如在分布式场景下,无法做到同时写缓存或需要异步刷新的时候)
//Redis常见性能问题和解决方案?
	1Master最好不要做任何持久化工作,包括内存快照和AOF日志文件,特别是不要启用内存快照做持久化。
    1、为了主从复制的速度和连接的稳定性,SlaveMaster最好在同一个局域网内。
//Redis官方为什么不提供Windows版本?
	Linux版本已经相当稳定,而且用户量很大,开发windows版本,反而会带来兼容性等问题。
//一个字符串类型的值能存储最大容量是多少?
	512M
//Redis如何做大量数据插入?
	pipe mode,(写redis命令的脚本文件,将命令转化成Redis Protocol//假如Redis里面有1亿个key,其中有10w个key是以某个固定的已知的前缀开头的,如果将它们全部找出来?
	使用keys指令可以扫出指定模式的key列表。
    如果Redis正在给线上业务提供服务,使用keys会有什么问题
        redis的单线程的。keys指令会导致线程阻塞一段时间,线上服务会停顿,直到指令执行完毕,服务才能恢复。这个时候可以使用scan指令,scan指令可以无阻塞的提取出指定模式的key列表,但是会有一定的重复概率,在客户端做一次去重就可以了,但是整体所花费的时间会比直接用keys指令长。
//使用Redis做过异步队列吗,是如何实现的
	使用list类型保存数据信息,rpush生产消息,lpop消费消息
//Redis如何实现延时队列
	使用zSet,用时间戳做那个分数,然后获取60秒之前的,就达到了延时队列的效果
//Redis回收进程如何工作的?
	一个新的命令被执行
    Redis检查内存使用情况,如果大于maxmemory的限制, 则根据设定好的策略进行回收。
//Redis回收使用的是什么算法?
	LRU算法:(最近最少使用)算法在缓存写满的时候,会根据所有数据的访问记录,淘汰掉未来被访问几率最低的数据。也就是说该算法认为,最近被访问过的数据,在将来被访问的几率最大。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值