目录
1.redis主要消耗什么物理资源?
内存
2.单线程为什么快
1.纯内存操作
2.核心是基于非阻塞的IO多路复用机制,避免了多线程的频繁上下文切换带来的性能问题
3.Redis 内置了多种优化过后的数据结构实现,性能非常高
3.为什么要使用Redis
高性能:操作缓存就是直接操作内存,所以速度相当快
高并发:Redis每秒查询次数最高能达到 30w+,能够承受的请求数量是远远大于直接访问数据库的
4.简述redis事务实现
事务是一个单独的隔离操作:一组按顺序执行的命令集合;事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。
事务是一个原子操作:事务中的命令要么全部被执行,要么全部都不执行
实现:
1.执行命令 multi 开启一个事务
2.开启事务之后执行的命令都会被放入一个队列,如果成功之后会固定返回队列
3.执行命令 exec 提交事务之后,Redis 会依次执行队列里面的命令,并依次返回所有命令结果(如果想要放弃事务,可以执行 discard 命令)
命令:
multi:开启事务
exec:执行事务
discard:取消事务
watch:监视
5.redis缓存读写策略
旁路缓存模式:服务端同时维护Mysql和Redis,并且以Mysql的主要存储;
读:先从Redis中读,如果Redis中没有,再从Mysql中读取,并将结果返回写入Redis
写:先写Mysql,再删除Redis
缺陷:1.首次请求数据一定不在 Redis中(可以将热点数据可以提前放入Redis中)2.写操作比较频繁的话导致 cache 中的数据会被频繁被删除,这样会影响缓存命中率(加一个锁)
读写穿透:视Redis为主要存储
读:先从Redis中读,读到直接返回。没有读到就从Mysql中读取数据放入到Redis中后,再返回数据
写:先看Redis中是否存在该数据,存在则先更新换,再更新数据库
缺陷:1.首次请求数据一定不在 Redis中(可以将热点数据可以提前放入Redis中)
异步缓存写入:视Redis为主要存储
只更新缓存,不直接更新Mysql,而是改为异步批量的方式来更新Mysql
6.redis除了做缓存,还能做些什么?
分布式锁
限流:一般是通过 Redis + Lua 脚本的方式来实现限流
消息队列 ........
7.redis主从复制的原理
数据可以从主服务器向任意数量的从服务器上同步,从服务器可以是关联其他从服务器的主服务器;
好处:
- 数据冗余:主从复制实现了数据的热备份,是持久化之外的一种数据冗余方式
- 负载均衡:可以轻易地实现横向扩展,实现读写分离
- 故障恢复:如果master宕掉了,使用哨兵模式,可以提升一个 slave 作为新的 master,进而实现故障转移,实现高可用
流程:
slave服务器连接到master服务器,便开始进行数据同步
master服务器收到psync命令之后,开始执行bgsave命令生成RDB快照文件并使用缓存区记录此后执行的所有写命令
master服务器bgsave执行完之后,就会向所有Slava服务器发送快照文件,并在发送期间继续在缓冲区内记录被执行的写命令。
slave服务器收到RDB快照文件后,会将接收到的数据写入磁盘,然后清空所有旧数据,在从本地磁盘载入收到的快照到内存中,同时基于旧的数据版本对外提供服务。
master服务器发送完RDB快照文件之后,便开始向slave服务器发送缓冲区中的写命令。
slave服务器完成对快照的载入,开始接受命令请求,并执行来自主服务器缓冲区的写命令;
如果slave node开启了AOF,那么会立即执行BGREWRITEAOF,重写AOF。
8.Redis有哪些数据结构?分别有哪些典型的应用场景?
String:字符串;计数器、分布式id、token
hash:哈希;用户信息、商品信息、文章信息、购物车信息
List:列表;最新文章、最新动态
Set:集合;共同关注、点赞
ZSet:有序集合;排行榜
9.如何解决 Redis 的并发竞争 Key 问题
Redis 的并发竞争 Key 的问题也就是多个系统同时对一个 key 进行操作
解决方案:
- 乐观锁:适用于大家一起抢着改同一个key,对修改顺序没有要求的场景,使用watch命令来实现
- 分布式锁:在业务层进行控制,操作 redis 之前,先去申请一个分布式锁,拿到锁的才能操作
- 时间戳:写入时保存一个时间戳,写入前先比较自己的时间戳是不是早于现有记录的时间戳,如果早于,就不写入
- 消息队列:在并发量很大的情况下,可以通过消息队列进行串行化处理
10.缓存雪崩、缓存穿透、缓存击穿,如何解决
缓存雪崩:缓存同一时间大面积失效,所有请求落在数据库上
解决:
缓存数据过期时间设置随机,防止同一时间大面积过期
给每个缓存增加标记,记录缓存是否失效,如果失效,则更新数缓存
缓存预热
互斥锁
缓存穿透:缓存和数据库中都没有数据,所有请求都落在数据库上
解决:
接口层增加校验,如用户鉴权校验,id做基础校验
从缓存取不到的数据,在数据库中也没有取到,可以将value设为null
布隆过滤器,将所有数据存到bitmap中,不存在数据会被拦截掉
缓存击穿:同一条数据,缓存中没有,数据库中有,但由于访问并发量大,造成数据库压力大
解决:
设置热点数据永远不过期
加互斥锁,互斥锁缓存预热
11.Redis和Mysql如何保证数据一致
延迟双删:先删除redis数据,再更新mysql,延迟几百毫秒,再删除redis数据;
12.redis的持久化机制
持久化机制:redis数据都是存储在内存中,为了避免数据丢失,需要将数据以某种形式从内存中保存到硬盘中,重启时利用持久化数据恢复。
RDB(快照):指定时间间隔将数据进行快照存储,重启时读取文件来恢复数据
触发方式:
- 配置文件
- 执行filshall命令(这个命令就相当于删库跑路)
- 执行shutdown命令(客户端执行命令)
- 执行bgsave命令(对save命令的优化,异步操作)
- 执行save命令(同步操作命令)
AOF(日志文件):记录每次对服务器的操作,当服务器重启重新执行这些命令恢复原始数据
aof持久化方式redis是默认不开启的,我们可以通过配置文件开启aof持久化方式(appendonly的值默认为no,改为yes)
13.redis内存淘汰机制
跟redis的内存淘汰机制有关,默认是当内存用完写入数据报错
内存淘汰机制:
1.从已设置过期时间的数据中挑选最近最少使用的数据淘汰
2.从已设置过期时间的数据中挑选将要过期的数据淘汰
3.从已设置过期时间的数据中任意选择数据淘汰
4.从已设置过期时间的数据中挑选最不经常使用的数据淘汰
5.移除最近最少使用的 key
6.移除最不经常使用的 key
7.任意选择数据淘汰
8.写入数据报错
14.Redis如何设置key的过期时间
redis作为缓存存储的时候,一般都要设置过期时间,否则垃圾数据会占用大量的内存
分开设置:先设置值,再设置时间(非原子操作,极端情况下会出现问题);
合并设置:一条命令设置过期时间和值(推荐)
命令:
设置过期时间:expire name 1000
查看剩余时间:ttl name
取消过期时间:persist name
15.Redis过期键的删除机制
惰性过期:当访问key时,检查是否过期,过期则删除;最大化节约cpu,但对内存不友好;极端情况下出现大量过期key未被访问,会占用大量内存
定期过期:每隔一段时间扫描一定数量的key,并清除已过期的key;通过调整扫描时间间隔和扫描耗时,可以让cpu和内存达到最优的平衡效果
16.Redis集群会有写操作丢失吗?为什么?
Redis并不能保证数据的强一致性,这意味这在实际中集群在特定的条件下可能会丢失写操作
条件:
- 过期key被清理
- 最大内存不足,导致 Redis 自动清理部分 key 以节省空间
- 主库故障后自动重启,从库自动同步
- 单独的主备方案,网络不稳定触发哨兵的自动切换主从节点,切换期间会有数据丢失
17.redis集群方案
主从模式:使用一个redis实例作为主机,其余的实例作为备份机,主机和从机的数据完全一致,主机支持数据的写入和读取等各项操作,而从机则只支持与主机数据的同步和读取
优缺点:
- 一个主节点可以同步多个从节点
- 难以支持在线扩容
- 不具备自动容错与恢复功能
- 主从之间的同步是以非阻塞的方式进行的,同步期间,客户端仍然可以提交查询或更新请求
- 主节点自动将数据同步到从节点,可以进行读写分离
哨兵模式:Redis集群站哨的,一旦发现问题能做出相应的应对处理;监控主节点、从节点是否正常运行当主节点出现故障时,能自动将一个从节点转换为主节点(大哥挂了,选一个小弟上位)多个哨兵可以监控同一个Redis,哨兵之间也会自动监控
Redis Cluster模式:Cluster采用无中心结构,客户端与redis节点直连,客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可
18.Redis常见性能问题和解决方案?
- 主节点不要做任何持久化工作,包括内存快照和AOF日志文件,特别是不要启用内存快照做持久化
- 如果数据比较关键,某个从节点开启AOF备份数据,策略为每秒同步一次
- 为了主从复制的速度和连接的稳定性,主从节点最好在同一个局域网内
- 尽量避免在压力较大的主库上增加从库
- 为了主节点的稳定性,主从复制不要用图状结构,用单向链表结构更稳定,主节点挂了,可以立马启用Slave1做主节点,其他不变
19.Redis分布式锁是如何实现的?
分布式锁,即分布式系统中的锁,解决了分布式系统中控制共享资源访问的问题;
- 基于set命令的分布式锁
- 基于setnx、get、getset的分布式锁
- 基于RedLock的分布式锁
- 基于Redisson看门狗的分布式锁
20.Redis死锁情况,如何避免死锁
发生条件:
- ⼀个资源每次只能被⼀个线程使用
- ⼀个线程在阻塞等待某个资源时,不释放已占有资源
- ⼀个线程已经获得的资源,在未使用完之前,不能被强制剥夺
- 循环等待
解决:
- 使用事务时,尽量缩短事务的逻辑处理过程,及早提交或回滚事务
- 所有的程序都要有错误处理
- 对所有的脚本和程序都要仔细测试
- 优化程序,检查并避免死锁现象出现
- 设置死锁超时参数为合理范围,超过时间,自动放弃本次操作,避免进程悬挂
21.redis 6.0新增特性
新增特性:
- 多线程
- 客户端缓存
- 细粒度权限控制
- resp3协议的使用
- rdb文件加载更快
- 用于复制的rdb文件不再有用,将立刻被删除
22.redis 6.0为什么要改为多线程
随着硬件性能的提升,redis单个线程处理网络读写的速度跟不上底层网络硬件的速度。读写占用了大部分cpu的时间,瓶颈主要是网络的io消耗;优化的方向主要是:
1.优化网络 I/O 模块
2.提高机器内存读写的速度
提高机器内存读写的速度依赖于硬件,暂时无解;所以,Redis 采用多个 IO 线程来处理网络请求,提高网络请求处理的并行度。
Redis 多 IO 线程模型只用来处理网络读写请求,对于 Redis 的读写命令,依然是单线程处理
23.redis和redisson有什么关系?
Redisson是一个高级的分布式协调Redis客服端,能帮助用户在分布式环境中轻松实现一些Java的对象