1.什么是Redis
Redis (REmote DIctionary Server) 是用 C 语言开发的一个开源的高性能键值对(key-value)数据库
特征:
1.数据间没有必然的关联关系
2.内部采用单线程机制进行工作
3.高性能,官方提供测试数据,50个并发执行100000 个请求,读的速度是110000 次/s,写的速度是 81000次/s。
4.多数据类型支持
5.持久化支持。可以进行数据灾难恢复
2.Redis数据类型
Redis支持五种数据类型:string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted_set:有序集合)。
- String(字符串):这是Redis最基本的数据类型,一个key对应一个value,并且是二进制安全的,可以包含任何数据,例如jpg图片或者序列化的对象。
- Hash(哈希):哈希是一个键值(key=>value)对集合,是string类型的field和value的映射表,适合用于存储对象,比将每个字段都存储为string更节省内存。
- List(列表):列表是一个简单的字符串列表,按照插入顺序进行排序,可以添加一个元素到列表的头部或者尾部。
- Set(集合):Set是一个无序的字符串集合,其元素是唯一的,但本身不保证顺序。
- Zset(sorted_set:有序集合):Zset是有序的字符串集合,其元素是唯一的,但元素会根据提供的分数进行排序。每个元素都会关联一个double类型的分数,通过分数来为集合中的元素进行从小到大的排序。
3.什么是乐观锁和悲观锁
悲观锁(Pessimistic Lock),顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每 次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。传统的关系型数据库里 边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。
乐观锁(Optimistic Lock) 顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。 乐观锁适用于多读的应用类型,这样可以提高吞吐量。Redis就是利用这种check-and-set(CAS)机制实现事务的
4.Redis的持久化机制有哪些?
持久化的方案有两种,分别是RDB和AOF,根据不同的场景,可以选择只使用其中一个或者一起使用。
RDB是通过保存快照的方式来对数据进行持久化处理,所保存的数据的本身,默认使用的是bgsave来保存快照数据。
RDB的优缺点:
? ? ? ? 优点:
- 基于二进制文件完成数据备份,占用空间少,便于文件传输
- 能够自定义规则,根据Redis繁忙状态进行数据备份
? ? ? ? 缺点:
- 无法保证数据完整性,会丢失最后一次快照后的所有数据
- bgsave执行每次执行都会阻塞Redis服务进程创建子线程,频繁执行影响系统吞吐量
RDB方式会出现数据丢失的问题,对于这个问题,可以通过Redis中另一个持久化方式解决:AOF
当AOF持久化开启后,Redis会将客户端发送的所有更改数据的命令保存至磁盘中,通过读取AOF文件,按照顺序获取所记录的数据命令,来达到恢复数据的效果。
AOF写数据三种策略(appendfsync)
- always(每次):每次写入操作均同步到AOF文件中,该方式效率最高,数据零误差,安全性最高,但是十分浪费资源。
- everysec(每秒):每秒将缓冲区中的指令同步到AOF文件中,并且每隔一秒同步到磁盘当中一次,数据准确性较高,性能较高 在系统突然宕机的情况下丢失1秒内的数据。
- no(系统控制):由操作系统控制每次同步到AOF文件的周期,将同步操作交给系统来做,整体过程不可控,改方式最快,但是最不安全。
持久化方式 | RDB | AOF |
占用存储空间 | 小(数据级:压缩) | 大(指令级:重写) |
存储速度 | 慢 | 快 |
恢复速度 | 快 | 慢 |
数据安全性 | 会丢失数据 | 依据策略决定 |
资源消耗 | 高/重量级 | 低/轻量级 |
启动优先级 | 低 | 高 |
将当前数据状态进行保存,快照形式,存储数据结果,存储格式简单,关注点在数据 (RDB);
将数据的操作过程进行保存,日志形式,存储操作过程,关注点在数据的操作过程(AOF);
RDB默认开启的,AOF需要手动开启 ;
RDB存储某个时刻的数据快照,AOF存储写命令;
RDB在配置触发状态会丢失最后一次快照以后更改所有的数据,AOF默认使用everysec,每秒保存一次;
5.Redis 删除策略
定时删除
- 创建一个定时器,当key设置有过期时间,且过期时间到达时,由定时器任务立即执行对键的删除 操作
- 优点:节约内存,到时就删除,快速释放掉不必要的内存占用
- 缺点:CPU压力很大,无论CPU此时负载量多高,均占用CPU,会影响redis服务器响应时间和指 令吞吐量
- 总结:用处理器性能换取存储空间(拿时间换空间)
惰性删除
- 数据到达过期时间,不做处理。等下次访问该数据时 如果未过期,返回数据 发现已过期,删除,返回不存在
- 优点:节约CPU性能,发现必须删除的时候才删除
- 缺点:内存压力很大,出现长期占用内存的数据
- 总结:用存储空间换取处理器性能(拿空间换时间)
定期删除
- 定期删除是对定时删除和惰性删除做了平衡,redis默认每秒运行10次对具有过期时间的key进行次扫描,但是不会扫描全部的key,因为这样会大大延长扫描时间,每次默认只会扫描20个key,同时删除这20个key中已经过期的key,如果这20个key中过期key的比例超过25%,则继续扫描
- 周期性轮询redis库中的时效性数据,采用随机抽取的策略,利用过期数据占比的方式控制删 除频度
- 优点1:CPU性能占用设置有峰值,检测频度可自定义设置?
- 优点2:内存压力不是很大,长期占用内存的冷数据会被持续清理
- 总结:周期性抽查存储空间 (随机抽查,重点抽查)
定时删除 | 节约内存,无占用 | 不分时段占用CPU资源,频度高 | 拿时间换空间 |
惰性删除 | 内存占用严重 | 延时执行,CPU利用率高 | 拿空间换时间 |
定期删除 | 内存定期随机清理 | 每秒花费固定的CPU资源维护内存 | 随机抽查,重点抽查 |
?6.Redis缓存淘汰策略
Redis的内存参数配置,在64位操作系统中,如果未设置或设置0,代表无限制,而在32位系统中,默认内存大小为3GB。但是在实际生产环境下,一般会设置物理内存的四分之三左右。当客户端执行命令添加数据时Redis会检查内存空间大小,如果超过最大内存,则会触发内存淘汰策略。淘汰策略分为以下三种八类:
1.对设置了过期时间数据淘汰:
- 设置了过期时间,且最近最久没有使用的数据进行淘汰
- 设置了过期时间,且最近最少没有使用的数据进行淘汰
- 设置了过期时间,且即将过期的数据进行淘汰
- 设置了过期时间的数据进行随机淘汰
2.对所有数据淘汰:
- 从所有数据中,删除最近最久没有被使用的数据进行淘汰
- 从所有数据中,删除最近最少没有被使用的数据进行淘汰
- 从所有的数据中,随机删除
3.不淘汰: (默认)
7.什么是缓存雪崩
缓存雪崩的情况往往是由两种情况产生:
- 情况1:由于大量key设置了相同的过期时间(数据在缓存和数据库都存在),一旦达到过期时间点,这些key集体失效,造成访问这些key的请求全部进入数据库
- 情况2:Redis实例宕机,大量请求进入数据库
解决方案:
- 情况1的解决方案
- 错开过期时间:在过期时间上加上随机值
- 服务降级:暂停非核心数据查询缓存,返回预定义信息
- 情况2的解决方案
- 事前预防:搭建高可用集群
- 构建多级缓存(实现成本较高)
- 熔断:通过监控一旦雪崩出现,暂停缓存访问待实例恢复,返回预定义信息
- 限流:通过监控一旦发现数据库访问量过阈值,限制访问数据库的请求数
8.什么是缓存击穿
缓存击穿问题也叫热点Key问题,就是一个被高并发访问并且缓存重建业务较复杂的key突然失效了,无 数的请求访问会在瞬间给数据库带来巨大的冲击。
常见的解决方案有两种:
- 使用互斥锁:当一个线程查询缓存未命中后,使用锁来阻塞其他线程对数据库的访问,直到锁被释放。这样可以避免同时有多个线程去查询数据库,从而降低数据库的访问压力。
- 逻辑过期:对于一些查询频率较高的数据,可以设置一个逻辑过期时间,当缓存过期后,先查询数据库,然后再将查询到的数据设置回缓存。这样可以保证在一段时间内只有一个线程去查询数据库,其他线程仍然可以从缓存中获取数据。
解决方案 | 优点 | 缺点 |
互斥锁 | 没有额外的内存消耗 保证一致性 实现简单 | 线程需要等待,性能受影响 可能有死锁风险 |
逻辑过期 | 线程无需等待,性能较好 | 不保证一致性 有额外内存消耗 实现复杂 |
9.什么是缓存穿透
缓存穿透是指客户端请求的数据在缓存中和数据库中都不存在,这样缓存永远不会生效,这 些请求都会打到数据库。
常见的解决方案有两种:
- 缓存空对象
- 优点:实现简单,维护方便
- 缺点: 额外的内存消耗,可能造成短期的不一致
- 布隆过滤
- 优点:内存占用较少,没有多余key
- 缺点: 实现复杂,存在误判可能
10.Redis为什么被设计成单线程
- 实现简单:单线程模型简化了Redis的代码实现,降低了维护成本,也减少了潜在的复杂性。
- 避免多线程的上下文切换和竞争条件:单线程避免了不必要的上下文切换和竞争条件,避免了CPU资源的浪费。同时,由于Redis是基于内存的操作,CPU不是Redis的瓶颈,因此单线程不会成为性能瓶颈。
- 避免死锁:在单线程情况下,不需要考虑各种锁的问题,不存在加锁、释放锁操作,也没有因为可能出现死锁而导致的性能消耗。
- 避免多进程导致的切换和消耗:采用单线程、多进程的集群方案可以避免多进程导致的切换和消耗,提高效率。
- 异步非阻塞IO:Redis使用非阻塞IO,即多路复用IO,一个线程可以服务多个IO流。传统的网络IO是阻塞式的,服务器线程会一直在监听数据传输的管道,一直阻塞在那里,直到有客户端发送数据。非阻塞IO可以提高Redis的吞吐量。
11.Redis为什么那么快
- 内存存储:Redis将所有数据存储在内存中,这使得它能够快速地读写数据。与传统的磁盘存储相比,内存存储的访问速度更快。
- 单线程架构:Redis是单线程的,Redis不需要进行上下文切换,也不需要考虑线程同步和枷锁等问题,从而避免了这些常见的多线程问题所带来的开销。
- 异步非阻塞I/O:Redis使用了事件驱动机制,并采用了异步非阻塞I/O模型,这使得Redis能够处理大量的并发连接请求,提高了系统的吞吐量。
- 基于内存的操作:Redis的所有操作都是基于内存的,这使得Redis能够在微妙级别完成大部分操作,从而提高了系统的响应速度
12.MySQL和Redis的区别
- 数据结构:MySQL是关系型数据库,支持表和行等结构化数据类型,而Redis是键值对存储系统,支持字符串、哈希、列表、集合、有序集合等非结构化数据类型。
- 数据存储方式:MySQL将数据存储在硬盘上,而Redis将数据存储在内存中。
- 数据查询:MySQL支持复杂的查询操作,可以使用SQL语言进行查询,而Redis只支持简单的键值对操作,不支持复杂的查询操作。
- 数据持久化:MySQL可以通过日志和备份文件来持久化数据,而Redis可以通过配置持久化策略来持久化数据。
使用MySQL的情况:
- 需要处理结构化数据,如表格和行。
- 需要进行复杂的查询操作,如联接、子查询等。
- 数据量较大,但不需要将所有数据都存储在内存中。
- 需要持久化数据,以确保数据不会因为系统故障而丢失。
使用Redis的情况:
- 需要处理非结构化数据,如字符串、哈希、列表、集合、有序集合等。
- 需要将所有数据都存储在内存中,以提高数据访问速度。
- 不需要进行复杂的查询操作,只需要进行简单的键值对操作。
- 不需要持久化数据,因为数据可以存储在内存中,即使系统故障也不会丢失。