redis八股个人总结
1.MySQL和Redis的区别?
1. 基本特性
MySQL
- 类型:关系型数据库(RDBMS)
- 存储方式:基于表的结构化数据存储,数据以行和列的形式存储。
- 数据一致性:遵循ACID(原子性、一致性、隔离性、持久性)原则,适合需要强一致性的场景。
- 查询语言:使用SQL进行数据操作,支持复杂的查询和事务。
Redis
- 类型:键值存储(NoSQL)
- 存储方式:基于内存的非关系型数据存储,数据以键值对的形式存储。
- 数据一致性:通常不支持ACID,主要提供最终一致性,适合对性能要求高的场景。
- 查询语言:使用Redis命令进行数据操作,支持多种数据结构,如字符串、哈希、列表、集合等。
2. 存储方式与性能
-
存储方式:
- MySQL将数据存储在硬盘中,支持复杂的查询和事务。适合需要持久化存储的场景。
- Redis将数据存储在内存中,支持持久化到硬盘但主要是为了提高读写速度。适合对性能要求较高的场景。
-
性能:
- MySQL的读写性能受限于硬盘速度,通常在数千次查询每秒(QPS)。
- Redis由于是内存操作,读写速度极快,能够达到数十万甚至百万次查询每秒(QPS)。
3. 数据结构与应用场景
-
数据结构:
- MySQL使用表、行和列的结构,支持复杂的数据关系和SQL查询。
- Redis支持多种数据结构:字符串、哈希、列表、集合、有序集合等,适合多种数据处理场景。
-
应用场景:
- MySQL:适合需要复杂查询、事务管理和数据完整性的场景,如用户信息管理、订单系统等。
- Redis:适合需要高速读写、缓存、实时数据处理和消息队列的场景,如排行榜、会话存储、实时分析等。
4. 选择原因
-
选择MySQL的原因:
- 需要强一致性和数据完整性。
- 需要支持复杂的查询和数据关系。
- 数据量较大,需要持久化存储。
-
选择Redis的原因:
- 需要极高的读写性能。
- 需要快速响应的实时应用。
- 适合临时数据存储和缓存。
5. 项目中的结合使用
在实际项目中,MySQL和Redis可以结合使用,以发挥各自的优势。例如:
-
缓存机制:
- 将频繁访问的数据(如用户信息、商品信息)缓存在Redis中,以减少对MySQL的直接查询负担,提高系统性能。
- 当数据在Redis中不存在时,再去MySQL中查询,并将结果缓存到Redis。
-
数据持久化:
- 使用MySQL作为主数据库,确保数据持久化和完整性。
- 使用Redis作为缓存层,处理高并发的读请求,提升用户体验。
-
实时数据处理:
- 在需要快速响应的功能(如在线聊天、实时通知)中使用Redis,以实现快速数据交互。
- 后台数据分析和存储使用MySQL,确保数据的持久性和可查询性。
2.Redis有什么优缺点?为什么用Redis查询会比较快
1. Redis的主要优点
1.1 速度快
- 内存存储:Redis将数据存储在内存中,读写速度非常快,通常在微秒级别。这使得其在高并发场景下能够提供极高的性能。
1.2 支持多种数据结构
- 丰富的数据类型:Redis不仅支持简单的键值对,还支持字符串、哈希、列表、集合、有序集合等多种数据结构。这使得Redis在处理不同类型的数据时非常灵活。
1.3 持久化选项
- 持久化机制:Redis提供RDB(快照)和AOF(追加文件)两种持久化方式,可以将内存中的数据持久化到磁盘,保证数据在重启后不会丢失。
1.4 高可用性
- 主从复制和分片:Redis支持主从复制,可以通过多个副本提高数据的可用性和读取性能。此外,Redis Cluster可以实现数据的分片存储,支持水平扩展。
2. Redis的缺点
2.1 内存限制
- 内存消耗:由于Redis数据存储在内存中,受限于可用内存的大小,因此存储的数据量可能受到限制。对于大规模的数据存储,可能需要更多的内存资源。
2.2 数据持久化开销
- 性能开销:虽然Redis支持持久化,但在写入和持久化数据时可能会引入性能开销。特别是在AOF模式下,每次写入都会追加到日志中,可能影响性能。
2.3 数据一致性
- 最终一致性:Redis在某些情况下可能会牺牲强一致性,特别是在使用主从复制时,可能会出现数据延迟的问题。
3. Redis查询速度快的原因
3.1 内存存储
- 内存操作:数据直接存储在内存中,内存的读写速度远高于磁盘,因此查询速度极快。
3.2 优化的数据结构
- 高效的数据结构:Redis内部使用优化过的数据结构(如跳表、压缩列表)来存储和检索数据,能够快速执行各种操作。
3.3 非阻塞I/O
- 事件驱动模型:Redis使用单线程的事件驱动模型,结合非阻塞I/O,实现高并发处理,减少上下文切换的开销。
4. Redis性能优化策略
4.1 数据结构选择
- 合理选择数据结构:根据具体场景选择最合适的数据结构。例如,使用哈希存储对象,使用列表管理队列等,以提高内存利用率和访问速度。
4.2 持久化策略
- 配置持久化参数:根据业务需求合理配置RDB和AOF的持久化策略,平衡性能和数据安全。
4.3 监控和调整
- 监控性能:使用Redis的监控工具(如Redis Monitor)监控性能指标,识别瓶颈并进行调整。
4.4 数据清理
- 定期清理无用数据:通过设置过期时间或定期清理无用数据,保持Redis中的数据量在合理范围内,避免内存消耗过高。
3.Redis的数据类型有那些?
1. 字符串(String)
- 特点:字符串是Redis中最简单的数据类型,可以存储任何数据类型的值(如文本、数字、二进制数据等),最大可以存储512MB。
- 使用场景:常用于缓存、计数器、简单的键值存储等。例如,可以用来存储用户会话信息或统计访问次数。
- 内部实现:字符串在Redis中是以简单的动态字符串(SDS)形式实现,支持快速的读写操作。
2. 哈希(Hash)
- 特点:哈希是一种键值对集合,适合存储对象的属性(如用户信息),内部结构为哈希表。
- 使用场景:适合存储较小的对象数据,如用户的基本信息(用户名、年龄、邮箱等)。可以通过字段快速访问特定值。
- 内部实现:哈希表的实现使得在对哈希进行字段操作时,时间复杂度为O(1)。
3. 列表(List)
- 特点:列表是一个有序的字符串集合,支持在两端进行快速插入和删除操作。内部实现为双向链表或压缩列表。
- 使用场景:适用于实现队列(FIFO)或栈(LIFO)结构。例如,可以用来存储消息队列或实现最近访问的记录(LRU)。
- 内部实现:当列表元素较少时,使用压缩列表;元素较多时,使用双向链表,以提高性能。
4. 集合(Set)
- 特点:集合是一组无序且唯一的字符串,支持快速的添加、删除和查找操作。内部实现为哈希表。
- 使用场景:适用于需要去重的场景,如用户的兴趣标签、好友列表等。可以快速判断某个元素是否在集合中。
- 内部实现:由于使用哈希表,集合的操作时间复杂度为O(1)。
5. 有序集合(Sorted Set)
- 特点:有序集合与集合类似,但每个元素都有一个分数(score),根据分数进行排序,支持范围查询。
- 使用场景:适合用于排行榜、评分系统等需要排序的场景。例如,游戏中的玩家得分排名。
- 内部实现:有序集合使用跳表和哈希表的组合,使得元素的插入、删除、查找操作都能在O(log(N))的时间复杂度内完成。
6. 位图(Bitmap)
- 特点:位图实际上是对字符串的一种特殊操作,允许在字符串中按位操作,适合高效地存储和处理二进制数据。
- 使用场景:常用于统计用户活跃度、签到记录等需要高效处理的场景。
- 内部实现:利用字符串的位操作,节省存储空间并提高处理效率。
7. 超日志(HyperLogLog)
- 特点:用于基数估计,能够在O(1)的空间内估算唯一元素的数量。
- 使用场景:适用于需要统计独立用户数量的场景,如网站访问量、去重统计等。
- 内部实现:使用概率算法(HyperLogLog)实现,能够在保持精确度的同时显著减少内存占用。
8. 流(Stream)
- 特点:流是一种基于时间序列的数据结构,用于处理消息和事件流。每个流的元素都有一个唯一的ID,通常是一个时间戳加上序列号。
- 使用场景:适用于实时数据处理、消息队列、事件日志等场景。例如,可以用来实现实时聊天、监控系统的数据记录等。
- 内部实现:流在Redis内部使用高效的双向链表和压缩列表实现,支持快速的插入和查询操作。流允许用户以高效的方式读取历史数据,并支持消费者组的概念,便于在分布式系统中处理消息。
4.Redis是单线程的还是多线程的,为什么?
edis最初是一个单线程的数据库,从一开始就采用了单线程模型。不过,从Redis 6.0版本开始,引入了I/O多线程,以优化性能。
1. 单线程模型
特点
- Redis使用单线程处理所有请求,即使在高并发的情况下,所有命令都是逐个执行的。
原因及优点
- 原子性操作:单线程模型确保了命令的原子性,避免了多线程环境中可能出现的竞争条件,确保数据一致性。
- 性能考虑:Redis的单线程设计简化了实现,避免了上下文切换和线程锁带来的性能开销。对于大多数操作,单线程能够提供足够的性能,因为Redis的操作主要是内存中的数据处理,速度非常快。
- 简单的编程模型:开发者和用户只需考虑请求的顺序,避免了复杂的并发编程问题。
2. Redis 6.0的多线程变化
引入I/O多线程
- Redis 6.0版本引入了I/O多线程,主要是为了改善网络I/O的性能。在这个版本中,虽然命令的处理仍然是单线程的,但网络操作(如读取和写入数据)可以通过多个线程来处理。
目的和效果
- 提升性能:多线程处理I/O操作可以显著提高Redis在高并发环境下的吞吐量,减少网络延迟。特别是在处理大量客户端请求时,多线程能够更有效地利用CPU资源。
- 更好的用户体验:引入多线程后,Redis能够更快地响应请求,提升整体性能,尤其是在高负载情况下。
5.Redis 持久化机制有哪些?
1. Redis的持久化机制
1.1 RDB(快照)
- 定义:RDB持久化是定期将Redis内存中的数据快照保存到磁盘中的一种机制。它会生成一个二进制文件,通常命名为
dump.rdb
。 - 作用:通过RDB文件,可以在Redis重启时恢复数据。
1.2 AOF(追加文件)
- 定义:AOF持久化是将Redis执行的每个写命令记录到一个日志文件中。这个日志文件通常命名为
appendonly.aof
。 - 作用:AOF可以通过重放命令的方式恢复数据,更加精确地还原到最近的状态。
2. RDB和AOF的优缺点
2.1 RDB的优缺点
- 优点:
- 性能高:RDB使用快照方式,可以在指定的时间间隔内生成数据快照,性能相对较高,适合对性能要求较高的场景。
- 文件体积小:RDB生成的文件通常比较小,因为它是数据的压缩格式。
- 缺点:
- 数据安全性较低:如果Redis在快照生成之前崩溃,则在此期间的数据可能会丢失,无法保证最新的数据安全。
- 恢复速度较慢:在重启时需要加载整个快照文件,恢复速度相对较慢。
2.2 AOF的优缺点
-
优点:
- 数据安全性高:AOF记录每个写命令,可以更精确地恢复数据,最大程度地减少数据丢失。
- 增量恢复:AOF可以逐步重放命令,恢复速度较快。
-
缺点:
- 性能开销:由于每个写操作都要写入AOF文件,可能会导致性能下降,尤其是在高频写入的场景。
- 文件体积大:随着时间的推移,AOF文件可能会变得很大,需要进行重写(rewrite)。
3. 触发持久化的方式
3.1 触发RDB的方式
- 配置文件:可以在Redis的配置文件
redis.conf
中设置save
参数,指定在多少秒内有多少次写操作后进行持久化。例如:apache
复制
save 900 1 # 900秒内至少1次写操作 save 300 10 # 300秒内至少10次写操作 save 60 10000 # 60秒内至少10000次写操作
- 命令触发:可以通过执行命令
SAVE
(阻塞方式)或BGSAVE
(非阻塞方式)来手动触发RDB持久化。
3.2 触发AOF的方式
- 配置文件:在
redis.conf
中设置appendonly
为yes
以启用AOF持久化,此外还可以设置appendfsync
策略:everysec
:每秒同步一次(性能与安全的平衡)。always
:每次写操作后同步(数据安全性最高,但性能最低)。no
:不进行同步(性能最高,但数据安全性最低)。
- 命令触发:可以通过执行
BGREWRITEAOF
命令手动触发AOF重写,以减少文件大小。
6.介绍一下Redis缓存雪崩和缓存穿透,如何解决这些问题?
1. 缓存雪崩
定义
缓存雪崩是指在某个时间点,大量缓存数据同时过期,导致大量请求直接打到数据库上,造成数据库压力骤增,可能引发系统崩溃。
原因
- 集中过期:如果多个缓存数据在同一时间过期(例如,设置的过期时间相同),就会在短时间内产生大量的请求。
- 故障或宕机:如果Redis出现故障,所有请求都无法访问缓存,直接请求数据库。
2. 缓存穿透
定义
缓存穿透是指请求的数据在缓存和数据库中都不存在,这样每次请求都会直接查询数据库,导致对数据库的压力增大。
原因
- 无效请求:用户请求的数据不存在(如查询一个错误的ID),导致每次请求都直接查询数据库。
- 恶意攻击:攻击者故意请求大量不存在的数据,消耗系统资源。
3. 解决方案
3.1 解决缓存雪崩
-
设置随机过期时间:
- 在缓存设置过期时间时,增加一定的随机值。例如,原本设置为10分钟,可以设置为9~11分钟之间的随机值,这样可以避免大量缓存同时过期。
-
预热缓存:
- 在系统启动或数据更新时,提前加载数据到缓存中,避免在高并发场景下直接请求数据库。
-
使用互斥锁:
- 对于即将过期的缓存,使用锁机制,只有第一个请求能够查询数据库并更新缓存,其他请求等待或返回旧的缓存,避免大量请求同时查询数据库。
3.2 解决缓存穿透
-
布隆过滤器:
- 在请求数据之前,先通过布隆过滤器判断该数据是否存在,如果不存在则直接返回,不查询数据库。布隆过滤器可以有效地减少无效请求。
-
缓存空值:
- 对于查询结果为空的数据,可以将空值缓存,设置一个短暂的过期时间(如5分钟)。这样,如果相同的无效请求再次到来,可以直接从缓存中返回,避免查询数据库。
7.如何保证数据库和缓存的一致性
1. 为什么要保证数据库和缓存的一致性
- 性能优化:缓存用于减少数据库的访问频率,提升数据读取的速度。
- 数据准确性:不一致的数据可能导致用户看到错误的信息,影响用户体验和业务决策。
- 系统稳定性:不一致性可能引发数据错误,导致系统出现异常,影响整体运行。
2. 数据库和缓存同步过程中可能遇到的问题
- 数据不一致:当数据库更新后,缓存未能及时更新,导致用户访问到过时数据。
- 缓存击穿:当某个数据在缓存中不存在,导致大量请求同时查询数据库,可能造成数据库负载过高。
- 缓存雪崩:大量缓存同时过期,导致大量请求直接打到数据库,造成瞬时流量激增。
- 并发更新问题:在高并发情况下,多个线程可能同时更新数据库和缓存,容易导致数据不一致。
3. 保证数据库和缓存一致性的策略
3.1 缓存失效策略
- 写操作后失效:在更新数据库时,同时删除或更新缓存中的对应数据。当数据被修改时,确保缓存中的相应条目失效。
- 适用场景:适合频繁更新的数据,如用户信息。
3.2 延迟双删策略
- 双重删除:在更新数据时,先删除缓存,再等待一段时间后再次删除缓存,以确保旧缓存已被清除。这样可以避免在更新后短时间内读取到过期数据。
- 适用场景:适合对一致性要求较高的场景,如电商商品详情。
3.3 读写分离
- 使用不同的缓存策略:在读取数据时,优先从缓存获取;如果缓存不存在,则从数据库中读取并更新缓存。在写入时,直接更新数据库并清除相应缓存。
- 适用场景:适合读取操作频繁而写入少的场景,如新闻网站。
3.4 事件驱动策略
- 使用消息队列:在更新数据库时,通过消息队列通知其他服务或系统更新缓存。这种方式可以异步处理,减少对主流程的影响。
- 适用场景:适合大型分布式系统,尤其是多服务协作的场景。
4. 根据不同业务场景选择策略
- 高频更新的场景:如用户信息、库存数量,适合使用缓存失效策略,确保数据的实时性。
- 读取频繁的场景:如商品详情页,适合使用读写分离策略,减少数据库压力。
- 复杂业务逻辑的场景:如电商系统,可以考虑使用延迟双删和事件驱动策略相结合,以确保高可用性和一致性。
总结
Redis有什么优缺点?为什么用Redis查询会比较快
(1) Redis有什么优缺点?
Redis
是一个基于内存的数据库,读写速度非常快,通常被用作缓存、消息队列、分布式锁和键值存储数据库。它支持多种数据结构,如字符串、哈希表、列表、集合、有序集合等, Redis 还提供了分布式特性,可以将数据分布在多个节点上,以提高可扩展性和可用性。但是Redis
受限于物理内存的大小,不适合存储超大量数据,并且需要大量内存,相比磁盘存储成本更高。
(2)为什么Redis查询快
- 基于内存操作: 传统的磁盘文件操作相比减少了IO,提高了操作的速度。
- 高效的数据结构:Redis专门设计了STRING、LIST、HASH等高效的数据结构,依赖各种数据结构提升了读写的效率。
- 单线程:单线程操作省去了上下文切换带来的开销和CPU的消耗,同时不存在资源竞争,避免了死锁现象的发生。
- I/O多路复用:采用I/O多路复用机制同时监听多个Socket,根据Socket上的事件来选择对应的事件处理器进行处理。
Redis的数据类型有那些?
Redis 常见的五种数据类型:String(字符串),Hash(哈希),List(列表),Set(集合)及 Zset(sorted set:有序集合)。
- 字符串
STRING
:存储字符串数据,最基本的数据类型。 - 哈希表
HASH
:存储字段和值的映射,用于存储对象。 - 列表
LIST
:存储有序的字符串元素列表。 - 集合
SET
:存储唯一的字符串元素,无序。 - 有序集合
ZSET
:类似于集合,但每个元素都关联一个分数,可以按分数进行排序。
Redis版本更新,又增加了几种数据类型,
BitMap
: 存储位的数据结构,可以用于处理一些位运算操作。HyperLogLog
:用于基数估算的数据结构,用于统计元素的唯一数量。GEO
: 存储地理位置信息的数据结构。Stream
:专门为消息队列设计的数据类型。
Redis是单线程的还是多线程的,为什么?
Redis
在其传统的实现中是单线程的(网络请求模块使用单线程进行处理,其他模块仍用多个线程),这意味着它使用单个线程来处理所有的客户端请求。这样的设计选择有几个关键原因:
- 简化模型:单线程模型简化了并发控制,避免了复杂的多线程同步问题。
- 性能优化:由于大多数操作是内存中的,单线程避免了线程间切换和锁竞争的开销。
- 原子性保证:单线程执行确保了操作的原子性,简化了事务和持久化的实现。
- 顺序执行:单线程保证了请求的顺序执行。
但是Redis的单线程模型并不意味着它在处理客户端请求时不高效。实际上,由于其操作主要在内存中进行,Redis能够提供极高的吞吐量和低延迟的响应。
此外,Redis 6.0
引入了多线程的功能,用来处理网络I/O这部分,充分利用CPU资源,减少网络I/O阻塞带来的性能损耗。
Redis持久化机制有哪些
- AOF 日志:每执行一条写操作命令,就把该命令以追加的方式写入到一个文件里;
- RDB 快照:将某一时刻的内存数据,以二进制的方式写入磁盘;
- 混合持久化方式:Redis 4.0 新增的方式,集成了 AOF 和 RBD 的优点;
缓存雪崩、击穿、穿透和解决办法
- 缓存雪崩是指在某个时间点,大量缓存同时失效,导致请求直接访问数据库或其他后端系统,增加了系统负载。
对于缓存雪崩,可以通过合理设置缓存的过期时间,分散缓存失效时间点,或者采用永不过期的策略,再结合定期更新缓存。
- 缓存击穿是指一个缓存中不存在但是数据库中存在的数据,当有大量并发请求查询这个缓存不存在的数据时,导致请求直接访问数据库,增加数据库的负载。典型的场景是当一个缓存中的数据过期或被清理,而此时有大量请求访问这个缓存中不存在的数据,导致大量请求直接访问底层存储系统。
对于缓存击穿,可以采用互斥锁(例如分布式锁)或者在查询数据库前先检查缓存是否存在,如果不存在再允许查询数据库,并将查询结果写入缓存。
- 缓存穿透是指查询一个在缓存和数据库都不存在的数据,这个数据始终无法被缓存,导致每次请求都直接访问数据库,增加数据库的负载。典型的情况是攻击者可能通过构造不存在的 key 大量访问缓存,导致对数据库的频繁查询。
对于缓存穿透,可以采用布隆过滤器等手段来过滤掉恶意请求,或者在查询数据库前先进行参数的合法性校验。
如何保证数据库和缓存的一致性
Cache Aside
- 原理:先从缓存中读取数据,如果没有就再去数据库里面读数据,然后把数据放回缓存中,如果缓存中可以找到数据就直接返回数据;更新数据的时候先把数据持久化到数据库,然后再让缓存失效。
- 问题:假如有两个操作一个更新一个查询,第一个操作先更新数据库,还没来及删除缓存,查询操作可能拿到的就是旧的数据;更新操作马上让缓存失效了,所以后续的查询可以保证数据的一致性;还有的问题就是有一个是读操作没有命中缓存,然后就到数据库中取数据,此时来了一个写操作,写完数据库后,让缓存失效,然后,之前的那个读操作再把老的数据放进去,也会造成脏数据。
- 可行性:出现上述问题的概率其实非常低,需要同时达成读缓存时缓存失效并且有并发写的操作。数据库读写要比缓存慢得多,所以读操作在写操作之前进入数据库,并且在写操作之后更新,概率比较低。
Read/Write Through
- 原理:Read/Write Through原理是把更新数据库(Repository)的操作由缓存代理,应用认为后端是一个单一的存储,而存储自己维护自己的缓存。
- Read Through:就是在查询操作中更新缓存,也就是说,当缓存失效的时候,Cache Aside策略是由调用方负责把数据加载入缓存,而Read Through则用缓存服务自己来加载,从而对调用方是透明的。
- Write Through:当有数据更新的时候,如果没有命中缓存,直接更新数据库,然后返回。如果命中了缓存,则更新缓存,然后再由缓存自己更新数据库(这是一个同步操作)。
Write Behind
- 原理:在更新数据的时候,只更新缓存,不更新数据库,而缓存会异步地批量更新数据库。这个设计的好处就是让数据的I/O操作非常快,带来的问题是,数据不是强一致性的,而且可能会丢。
- 第二步失效问题:这种可能性极小,缓存删除只是标记一下无效的软删除,可以看作不耗时间。如果会出问题,一般程序在写数据库那里就没有完成:故意在写完数据库后,休眠很长时间再来删除缓存。