一、什么是Redis
答:(1)Redis是一个开源(BSD许可)的内存数据结构存储,用作数据库、缓存、消息代理和流引擎。 (2)Redis提供数据结构,例如字符串、散列、列表、集合、带范围查询的排序结构、位图、超日志、地理空间索引和流。 (3)Redis内置了复制、Lua脚本、LRU驱逐、事务和不同级别的磁盘持久性。
Redis的主要特点:
(1)读写速度快: Redis 是一种基于内存的数据库,对数据的读写操作都是在内存中完成,因此读写速度非常快,常用于缓存,消息队列、分布式锁等场景。
(2)原子操作: Redis所有操作都是原子性的,这意味着多个客户端同时操作Redis时,Redis会保证每个操作都是完整的,不会被其他操作打断。
(3)丰富的数据类型:Redis支持多种类型的数据结构,使得开发者可以很方便在Redis中实现复杂的操作,而无需将数据转移到应用程序中处理。
(4)Redis支持发布/订阅模式,这使得Redis可以作为消息中间件使用,实现消息的发布和订阅。
(5)持久化:虽然Redis是内存数据库,但它提供了两种持久化机制,即RDB快照和AOF日志,以确保数据在断电或系统故障后不会丢失。
(6)Redis支持事务、持久化、Lua脚本、多种集群方案(主从复制模式、哨兵模式、切机群模式)、发布/订阅模式、内存淘汰机制、过期删除机制等。
(7)客户端支持:Redis支持多种编程语言的客户端库,如Python、Java、C/C++、PHP、Ruby等,使得开发者可以很方便的在自己的应用程序中使用Redis。
二、为什么用Redis作为MySQL的缓存
主要是因为Redis具备高性能和高并发的两种特性。
1. 高性能
(1)Redis 将数据存储在内存中,这使得它能够以极快的速度进行读写操作。对于需要快速响应的应用场景,如实时数据分析、高速缓存和游戏服务器等,Redis 是一个理想的选择。(2)它还采用了单线程模型,避免了多线程竞争和上下文切换带来的开销,进一步提高了性能。
2.高并发
单台设备的 Redis 的 QPS(Query Per Second,每秒钟处理完请求的次数)是 MySQL 的 10 倍;Redis 单机的 QPS 能轻松破 10w,而 MySQL 单机的 QPS 很难破 1w。
所以,直接访问 Redis 能够承受的请求是远远大于直接访问 MySQL 的,所以我们可以考虑把数据库中的部分数据转移到缓存中去,这样用户的一部分请求会直接到缓存这里而不用经过数据库。
三、Redis数据类型以及应用场景?
Redis 提供了丰富的数据类型,常见的有五种数据类型:
String(字符串),Hash(哈希),List(列表),Set(集合)、Zset(有序集合)
Redis五种数据类型的应用场景:
String 类型的应用场景:缓存对象、常规计数、分布式锁、共享 session 信息等。
List 类型的应用场景:消息队列(但是有两个问题:1.生产者需要自行实现全局唯- ID;2.不能以消费组形式消费数据)等。
Hash 类型:缓存对象、购物车等。
Set 类型:聚合计算(并集、交集、差集)场景,比如点赞、共同关注、抽奖活动等
Zset 类型:排序场景,比如排行榜、电话和姓名排序等。
四、五种常见的数据类型是怎么实现的?
1. 字符串(String)
字符串是Redis中最基本的数据类型,用于存储二进制安全的字符串。在Redis内部,字符串的底层的数据结构实现主要是简单动态字符串(SDS, Simple Dynamic Strings)。
(1)SDS不仅可以保存文本数据,还可以保存二进制数据
(2) SDS获取字符串长度的时间度是O(1)
(3) Redis 的 SDS API 是安全的,拼接字符串不会造成缓冲区溢出。
2.列表(List)
List 类型的底层数据结构是由双向链表或压缩列表实现的。
(1)如果列表的元素个数小于 512 个(默认值,可由 list-max-ziplist-entries 配置),列表每个元素的值都小于 64 字节(默认值,可由 ist-max-ziplist-value 配置),Redis 会使用压缩列表作为 List类型的底层数据结构;
(2)当列表元素不满足上述条件时,Redis会使用双向链表作为底层数据结构。
在Redis 3.2中,压缩列表数据结构已经被废弃,取而代之的是listpack数据结构,替代了双向列表和压缩列表。
3. 哈希(Hash)
Hash类型的底层数据结构是由哈希表或压缩列表实现的。
(1)如果列表的元素个数小于 512 个(默认值,可由 list-max-ziplist-entries 配置),列表每个元素的值都小于 64 字节(默认值,可由 ist-max-ziplist-value 配置),Redis 会使用压缩列表作为 Hash类型的底层数据结构;
(2)当哈希类型元素不满足上述条件时,Redis会使用哈希表作为底层数据结构。
在Redis 7.0中,压缩列表数据结构已经被废弃,取而代之的是listpack数据结构
4. 集合(Set)
Set 类型的底层数据结构是由哈希表或整数集合实现的。
(1)如果集合中的元素都是整数且元素个数小于 512(默认值,set-maxintset-entries配置)个,Redis会使用整数集合作为 Set 类型的底层数据结构;
(2)如果集合中的元素不满足上面条件,则 Redis 使用哈希表作为Set类型的底层数据结构,。
5. 有序集合(Sorted Set,ZSet)
Zset 类型的底层数据结构是由压缩列表或跳表实现的。
(1)如果有序集合的元素个数小于 128 个,并且每个元素的值小于 64 字节时,Redis 会使用压缩列表作为 Zset 类型的底层数据结构;
(2)如果有序集合的元素不满足上面的条件,Redis 会使用跳表作为 Zset 类型的底层数据结构;
在 Redis 7.0 中,压缩列表数据结构已经废弃了,交由 listpack 数据结构来实现了
五、Redis 和 Memcached 有什么区别?
1.共同点
(1)都是基于内存的数据库,一般都用来当作缓存使用
(2)都有过期策略
(3)两者性能都非常高
2.区别:
(1) Redis支持的数据类型更丰富(String、Hash、List、Set 、ZSet),而MemCached只支持最简单的key-value数据类型。
(2)Redis支持数据的持久化,可以将内存中的数据保持在磁盘中,重启的时候可以再次加载进行使用。MemCached不支持持久化,数据全部存储在内存中,MemCached一旦重启或崩溃数据将丢失。
(3)Redis原生支持集群模式,MemCached没有原生的集群模式,需要依靠客户端来实现往集群中分片写入数据。
(4)Redis支持事务、发布/订阅模式、Lua脚本等功能,而MemCached不支持。
六、Redis持久化
1.Redis 的持久化是指将内存中的数据保存到硬盘中,以便在 Redis 服务器重启后能够恢复数据,Redis 提供了两种主要的持久化方式RDB、AOF。
(1)将当前数据状态进行保存,快照形式,存储数据结果,存储格式简单,关注点在数据 (RDB)
(2)将数据的操作过程进行保存,日志形式,存储操作过程,关注点在数据的操作过程(AOF)
2.总结:官方推荐两个都启用,如果对数据不敏感,可以选单独用RDB,不建议单独用 AOF,因为可能会出现 Bug 如果只是做纯内存缓存,可以都不用。
(1)RDB优缺点
- 优点:恢复速度快、紧凑的文件格式、适用于数据备份、节省磁盘空间
- 缺点:数据可能丢失、子进程开销、资源消耗大
(2)AOF优缺点
- 优点:数据安全性高、可理解性强、支持不同的同步策略
- 缺点:文件体积大、恢复速度慢、可能会出现 AOF 文件损坏的情况
七、Redis删除策略
1. 数据删除策略的目标
在内存占用与CPU占用之间寻找一种平衡,顾此失彼都会造成整体redis性能的下降,甚至引发服务器宕机或内存泄露
- 定时删除
- 惰性删除
- 定期删除
2.三种删除策略比较
(1)定时删除 节约内存,无占用 不分时段占用CPU资源,频度高 拿时间换空间
(2)惰性删除 内存占用严重 延时执行,CPU利用率高 拿空间换时间
(3)定期删除 内存定期随机清理 每秒花费固定的CPU资源维护内存 随机抽查,重点抽查
清理策略 | 内存使用情况 | CPU资源使用情况 | 特性描述 |
---|---|---|---|
定时删除 | 节约内存,无占用 | 不分时段占用CPU资源,频度高 | 拿时间换空间,通过预设时间间隔进行清理,减少内存占用,但可能导致CPU资源在清理时频繁使用 |
惰性删除 | 内存占用严重 | 延时执行,CPU利用率高 | 拿空间换时间,仅在需要时才进行清理,减少CPU的即时负担,但可能导致内存占用较高 |
定期删除 | 内存定期随机清理 | 每秒花费固定的CPU资源维护内存 | 随机抽查,重点抽查,通过固定的时间周期进行内存清理,同时每秒分配一定的CPU资源来维护内存状态,以达到平衡内存和CPU使用的目的 |
八、企业级解决方案
1.缓存雪崩
缓存雪崩是指在同一时段大量的缓存key同时失效或者Redis服务宕机,导致大量请求到达数据库,带来巨大压力。
解决方案:
- 给不同的Key的TTL添加随机值
- 利用Redis集群提高服务的可用性
- 给缓存业务添加降级限流策略
- 给业务添加多级缓存
2.缓存击穿
缓存击穿(热点 Key 问题)是指一个高并发访问且缓存重建复杂的 key 突然失效,导致无数请求瞬间冲击数据库
解决方案:
- 互斥锁
- 逻辑过期
3.缓存穿透
缓存穿透是客户端请求的数据既不在缓存中也不在数据库中,使得请求直接打到数据库,导致缓存无法生效。
解决方案:
- 缓存空对象
优点:实现简单,维护方便
缺点: 额外的内存消耗 可能造成短期的不一致
- 布隆过滤
优点:内存占用较少,没有多余key
缺点: 实现复杂 存在误判可能