当前位置: 首页 > article >正文

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中设置appendonlyyes以启用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:有序集合)

  1. 字符串STRING:存储字符串数据,最基本的数据类型。
  2. 哈希表HASH:存储字段和值的映射,用于存储对象。
  3. 列表LIST:存储有序的字符串元素列表。
  4. 集合SET:存储唯一的字符串元素,无序。
  5. 有序集合ZSET:类似于集合,但每个元素都关联一个分数,可以按分数进行排序。

Redis版本更新,又增加了几种数据类型,

  • BitMap: 存储位的数据结构,可以用于处理一些位运算操作。
  • HyperLogLog:用于基数估算的数据结构,用于统计元素的唯一数量。
  • GEO: 存储地理位置信息的数据结构。
  • Stream:专门为消息队列设计的数据类型。

Redis是单线程的还是多线程的,为什么?

Redis在其传统的实现中是单线程的(网络请求模块使用单线程进行处理,其他模块仍用多个线程),这意味着它使用单个线程来处理所有的客户端请求。这样的设计选择有几个关键原因:

  1. 简化模型:单线程模型简化了并发控制,避免了复杂的多线程同步问题。
  2. 性能优化:由于大多数操作是内存中的,单线程避免了线程间切换和锁竞争的开销。
  3. 原子性保证:单线程执行确保了操作的原子性,简化了事务和持久化的实现。
  4. 顺序执行:单线程保证了请求的顺序执行。

但是Redis的单线程模型并不意味着它在处理客户端请求时不高效。实际上,由于其操作主要在内存中进行,Redis能够提供极高的吞吐量和低延迟的响应。

此外,Redis 6.0 引入了多线程的功能,用来处理网络I/O这部分,充分利用CPU资源,减少网络I/O阻塞带来的性能损耗。

Redis持久化机制有哪些

  • AOF 日志:每执行一条写操作命令,就把该命令以追加的方式写入到一个文件里;
  • RDB 快照:将某一时刻的内存数据,以二进制的方式写入磁盘;
  • 混合持久化方式:Redis 4.0 新增的方式,集成了 AOF 和 RBD 的优点;

缓存雪崩、击穿、穿透和解决办法

  1. 缓存雪崩是指在某个时间点,大量缓存同时失效,导致请求直接访问数据库或其他后端系统,增加了系统负载。

对于缓存雪崩,可以通过合理设置缓存的过期时间,分散缓存失效时间点,或者采用永不过期的策略,再结合定期更新缓存。

  1. 缓存击穿是指一个缓存中不存在但是数据库中存在的数据,当有大量并发请求查询这个缓存不存在的数据时,导致请求直接访问数据库,增加数据库的负载。典型的场景是当一个缓存中的数据过期或被清理,而此时有大量请求访问这个缓存中不存在的数据,导致大量请求直接访问底层存储系统。

对于缓存击穿,可以采用互斥锁(例如分布式锁)或者在查询数据库前先检查缓存是否存在,如果不存在再允许查询数据库,并将查询结果写入缓存。

  1. 缓存穿透是指查询一个在缓存和数据库都不存在的数据,这个数据始终无法被缓存,导致每次请求都直接访问数据库,增加数据库的负载。典型的情况是攻击者可能通过构造不存在的 key 大量访问缓存,导致对数据库的频繁查询。

对于缓存穿透,可以采用布隆过滤器等手段来过滤掉恶意请求,或者在查询数据库前先进行参数的合法性校验。

如何保证数据库和缓存的一致性

Cache Aside

  • 原理:先从缓存中读取数据,如果没有就再去数据库里面读数据,然后把数据放回缓存中,如果缓存中可以找到数据就直接返回数据;更新数据的时候先把数据持久化到数据库,然后再让缓存失效。
  • 问题:假如有两个操作一个更新一个查询,第一个操作先更新数据库,还没来及删除缓存,查询操作可能拿到的就是旧的数据;更新操作马上让缓存失效了,所以后续的查询可以保证数据的一致性;还有的问题就是有一个是读操作没有命中缓存,然后就到数据库中取数据,此时来了一个写操作,写完数据库后,让缓存失效,然后,之前的那个读操作再把老的数据放进去,也会造成脏数据。
  • 可行性:出现上述问题的概率其实非常低,需要同时达成读缓存时缓存失效并且有并发写的操作。数据库读写要比缓存慢得多,所以读操作在写操作之前进入数据库,并且在写操作之后更新,概率比较低。

Read/Write Through

  • 原理:Read/Write Through原理是把更新数据库(Repository)的操作由缓存代理,应用认为后端是一个单一的存储,而存储自己维护自己的缓存。
  • Read Through:就是在查询操作中更新缓存,也就是说,当缓存失效的时候,Cache Aside策略是由调用方负责把数据加载入缓存,而Read Through则用缓存服务自己来加载,从而对调用方是透明的。
  • Write Through:当有数据更新的时候,如果没有命中缓存,直接更新数据库,然后返回。如果命中了缓存,则更新缓存,然后再由缓存自己更新数据库(这是一个同步操作)。

Write Behind

  • 原理:在更新数据的时候,只更新缓存,不更新数据库,而缓存会异步地批量更新数据库。这个设计的好处就是让数据的I/O操作非常快,带来的问题是,数据不是强一致性的,而且可能会丢。
  • 第二步失效问题:这种可能性极小,缓存删除只是标记一下无效的软删除,可以看作不耗时间。如果会出问题,一般程序在写数据库那里就没有完成:故意在写完数据库后,休眠很长时间再来删除缓存。

http://www.kler.cn/a/573256.html

相关文章:

  • 【C++设计模式】第一篇:单例模式(Singleton)​
  • 可视挖耳勺使用技巧:如何为儿童清洁耳道更安全
  • 从文件到块: 提高 Hugging Face 存储效率
  • 备份docker的数据库文件信息
  • Android创建DeepSeek聊天对话
  • Xcode 无限循环闪退解决方案
  • web前端可以获取客户端的接入互联网的真实地址吗
  • 烟花燃放安全管控:智能分析网关V4烟火检测技术保障安全
  • 【玩转正则表达式】替换与正则表达式的结合
  • “RStudio UI“快速指南
  • 运维SaltStack面试题及参考答案
  • 神经网络|(十三)|SOM神经网络
  • C++ 将jpg图片变成16位565bmp图片
  • C++并发以及多线程的秘密
  • 为解决局域网IP、DNS切换的Windows BAT脚本
  • Hive-03之传参、常用函数、explode、lateral view、行专列、列转行、UDF
  • 【Stable Diffusion】SD迎来动画革命,AnimateDiff快速出图
  • Linux的系统ip管理
  • maven高级-01.分模块设计与开发
  • C 语 言 --- 猜 数 字 游 戏