关于java:揭秘一线大厂Redis面试高频考点3万字长文吐血整理

58次阅读

共计 29695 个字符,预计需要花费 75 分钟才能阅读完成。

3 万 + 长文揭秘一线大厂 Redis 面试高频考点,整顿不易,求一键三连:点赞、分享、珍藏
本文,已收录于,我的技术网站 aijiangsir.com,有大厂残缺面经,工作技术,架构师成长之路,等教训分享

1、说说什么是 Redis?

Redis 是一个开源的、基于内存的高性能键值对数据库,反对多种类型的数据结构,如字符串(strings)、列表(lists)、汇合(sets)、有序汇合(sorted sets)、哈希表(hashes)、位图(bitmaps)、超日志(hyperloglogs)和天文空间索引(geospatial indexes)。因为它的数据是寄存在内存中的,这使得 Redis 可能提供极高的数据读写速度,通常可能达到每秒数十万次的读写操作。Redis 还反对数据的长久化,能够将内存中的数据保留到硬盘中,保证数据的安全性。
Redis 的次要特点包含:

  1. 性能极高:Redis 可能反对超高的每秒读写操作次数,这得益于它的内存存储个性和高效的数据结构设计。
  2. 丰盛的数据类型:Redis 反对多种数据类型,使得它能够用于多种场景,如缓存、音讯队列、应用程序的会话状态存储等。
  3. 反对数据长久化:Redis 提供了两种数据长久化的形式,RDB(快照存储)和 AOF(追加文件存储),能够依据须要抉择最合适的长久化策略。
  4. 个性丰盛:Redis 还反对事务、管道(pipelining)、公布 / 订阅(pub/sub)模式等高级性能。
  5. 主从复制:Redis 反对主从复制,即主动将数据从一个 Redis 服务器复制到一个或多个从服务器,用于数据备份或读写拆散。
  6. 高可用和分布式:通过 Redis Sentinel 来实现高可用性的监控和故障转移,以及通过 Redis Cluster 来实现数据的主动分片和治理。

    2、Redis 的优缺点

    Redis 作为一个高性能的内存键值存储系统,在泛滥场景下被广泛应用,既有其显著的长处,也存在一些限度和毛病。

    Redis 的长处

  7. 高性能:Redis 将所有数据存储在内存中,访问速度快,可能反对高达每秒数十万次的读写操作,非常适合须要疾速读写访问的场景。
  8. 丰盛的数据类型:Redis 不仅仅是一个简略的键值对存储系统,它反对字符串、列表、汇合、有序汇合、哈希表等数据类型,使得 Redis 能够很容易地解决各种简单的利用场景。
  9. 数据长久化:Redis 反对 RDB 和 AOF 两种长久化形式,能够将内存中的数据保留到磁盘中,确保数据的安全性。
  10. 反对事务:Redis 通过 MULTI、EXEC、DISCARD 和 WATCH 命令反对事务,能够执行一组命令,并保障原子性和一致性。
  11. 高可用和分布式反对:通过 Redis Sentinel 来实现高可用的架构,以及通过 Redis Cluster 来实现主动分片和数据的分布式存储。
  12. 公布 / 订阅音讯零碎:Redis 反对公布 / 订阅模式,能够用作音讯队列零碎,进行音讯的公布和订阅。
  13. 简略易用:Redis 有着简洁高效的设计,易于装置和应用,同时社区提供了丰盛的客户端反对,笼罩了简直所有支流的编程语言。

    ### Redis 的毛病

  14. 数据集大小受限于物理内存:因为 Redis 是基于内存的存储系统,其数据集的大小受限于服务器的物理内存大小,对于大规模数据处理可能须要较高的老本。
  15. 长久化可能影响性能:尽管 Redis 提供数据长久化的能力,但在某些配置下(如应用 AOF 的每次写入模式),长久化操作可能会对性能产生影响。
  16. 单线程模型限度:Redis 应用单线程模型来解决命令,尽管这简化了设计并有助于客户端以确定的程序执行命令,但也意味着在多核服务器上不能无效利用多核 CPU 的劣势。
  17. 数据安全和隐衷问题:因为数据存储在内存中,如果服务器被侵入,数据可能会被轻易拜访。尽管 Redis 提供了一些平安个性(如密码保护和 SSL 加密),但默认配置下这些个性并未启用。
  18. 内存治理挑战:在应用 Redis 时,开发者须要认真治理内存,比方定期删除不必的键,应用适合的数据结构等,以防止内存收缩。

只管存在这些毛病,Redis 凭借其杰出的性能和灵活性,依然是许多高负载利用和服务的首选解决方案。正确的应用和适当的架构设计能够帮忙最大限度地施展其劣势,同时缓解一些潜在的毛病。

3、Redis 为什么这么快

Redis 之所以可能提供如此高速的性能,次要是因为以下几个关键因素的联合:

  1. 齐全基于内存:Redis 是一个内存数据库,所有的数据读写操作都是间接对内存进行,防止了磁盘 IO 的提早。内存的访问速度远远快于任何模式的磁盘存储,这是 Redis 高性能的最根本保障。
  2. 数据结构简略且高效:Redis 反对的数据结构十分高效,如字符串、列表、汇合、哈希表等,都是为快速访问和操作而优化的。Redis 外部对这些数据结构进行了高度优化,使得数据操作尽可能地疾速和高效。
  3. 单线程模型:Redis 采纳单线程模型解决命令,防止了多线程的上下文切换和竞争条件,这使得 Redis 在解决每个命令时简直没有任何性能损耗。尽管是单线程,但因为是基于内存操作,处理速度极快,足以应答大多数高并发场景。
  4. 非阻塞 IO:Redis 应用非阻塞 IO 模型,采纳多路复用技术。这意味着 Redis 服务器能够同时解决多个客户端的申请,而不是一次解决一个申请,极大进步了网络通信的效率。
  5. 高效的键值存储模型:Redis 的键值对存储模型非常简单,使得数据的查找和拜访十分疾速。对于大多数操作,Redis 可能以常数工夫复杂度进行解决,即 O(1)。
  6. 优化的长久化策略:Redis 提供了灵便的数据长久化选项(如 RDB 和 AOF),能够依据须要进行配置以均衡性能和数据安全性。即便在执行长久化操作时,Redis 也尽量减少对性能的影响。
  7. 精心设计的协定:Redis 协定简洁且易于解析,客户端和服务器之间的通信十分高效,缩小了网络通信的开销。
  8. 防止简单的计算:Redis 设计之初就是为了高速存取数据,它防止了简单的查问和事务处理,每个操作都尽可能地简略和疾速。

通过这些设计和实现上的优化,Redis 可能提供极高的性能,满足高并发、低提早的利用场景需要。这也是 Redis 在缓存、音讯队列、实时剖析等多种场景中被宽泛应用的起因。

4、Redis 那么快,为什么不必它做主数据库,只用它做缓存?

Redis 尽管以其高性能而闻名,特地是在解决大量数据时提供极低的提早和高吞吐量,但将其作为主数据库应用而不仅仅是缓存,须要思考以下几个方面的限度和挑战:

  1. 内存老本:Redis 是基于内存的存储系统,而内存的老本相比于硬盘等其余存储介质要高得多。随着数据量的减少,依赖 Redis 作为主数据库的老本会迅速减少,特地是对于存储大量数据的利用来说,这可能是一个显著的老本因素。
  2. 数据持久性:尽管 Redis 提供了数据长久化的性能,如 RDB 和 AOF,以保障数据安全,但这些机制在产生系统故障时依然可能面临数据失落的危险,尤其是在极其状况下。对于须要严格数据一致性和完整性保障的利用,依赖于内存的数据库可能不是最佳抉择。
  3. 数据安全和隐衷问题:因为 Redis 设计为高性能的存储系统,其平安个性可能不如专门设计用于长久存储的数据库系统。尽管能够通过配置和应用 SSL 等伎俩加强安全性,但对于须要高级平安保障的利用,可能须要更业余的解决方案。
  4. 简单查问的限度:Redis 尽管反对多种数据结构,但它不像关系数据库那样反对 SQL 查询语言和简单的查问操作。对于须要执行简单查问、联结操作或事务处理的利用,Redis 可能不能满足需要。
  5. 单线程模型的限度:Redis 的单线程模型尽管简化了操作并保障了高性能,但也意味着在多核处理器上无奈充分利用硬件资源。对于计算密集型的场景,这可能成为性能的瓶颈。
  6. 事务处理:Redis 只反对简略的事务处理,对于简单的事务无能为力,比方跨多个键的事务处理。

因而,尽管 Redis 以其杰出的性能和灵便的数据结构实用于许多场景,如缓存、音讯队列、会话存储等,但将其作为主数据库应用时,上述限度可能会导致它不适宜所有利用。通常,开发者会联合应用 Redis 和其余数据库系统(如 MySQL、PostgreSQL 或 MongoDB 等),利用各自的劣势,以实现更加全面和高效的数据管理和存储解决方案。

5、讲讲 Redis 的线程模型?

Redis 的线程模型是其性能高效的关键因素之一。传统上,Redis 应用单线程模型来解决客户端的申请,但这并不意味着 Redis 服务器只有一个线程在运行。上面具体解释 Redis 的线程模型及其如何工作:

单线程架构

在 Redis 6 之前,Redis 次要应用单个线程来解决所有的命令申请,这意味着在任意时刻,只有一个命令在被执行。这种设计的长处是防止了多线程编程中常见的并发问题,如数据竞争、锁的开销等,使得 Redis 可能以十分高的效率执行操作。

  • 高效的数据结构:Redis 外部应用高效的数据结构,如跳跃表(用于有序汇合)和压缩列表(用于小列表和哈希),这些构造在单线程模型中体现得十分高效。
  • 事件驱动模型:Redis 应用基于事件的模型,通过非阻塞 IO 和多路复用技术来监听和解决客户端连贯,这容许单线程高效地解决多个并发连贯。

    多线程 IO 解决(Redis 6 及以上)

    从 Redis 6 开始,引入了 IO 多线程模型,用于改善网络 IO 的解决效率。须要留神的是,这个多线程模型仅用于网络 IO 的读写操作,而不是命令的执行。命令执行依然是单线程的,放弃了 Redis 操作的原子性和一致性。

  • IO 线程:能够配置多个 IO 线程来并行处理客户端申请的读写操作。这些线程次要负责将命令从网络读取到内存中,以及将响应从内存写回到网络,不波及命令的理论执行。
  • 主线程:只管引入了 IO 线程,Redis 的命令解决逻辑依然在单个主线程中执行。这意味着数据的读取、写入、操作等都是由单个线程平安地执行,防止了并发拜访的问题。

    线程模型的优化

  • 合理配置 IO 线程:在多核处理器上,通过合理配置 IO 线程的数量,能够显著进步 Redis 解决大量并发连贯的能力,而不影响命令执行的性能。
  • 利用异步操作:Redis 反对异步操作,如异步写入(AOF 重写)和异步删除(惰性删除),这些操作能够在后盾线程中实现,缩小对主线程解决能力的影响。

Redis 的线程模型优化了性能和并发解决能力,同时放弃了简略和高效的特点。通过将命令执行与网络 IO 拆散,Redis 可能在保障操作安全性的同时,充分利用古代多核 CPU 的性能,提供高吞吐量和低提早的数据服务。

6、Redis 能够用来干什么?

Redis 作为一个高性能的键值存储系统,因其杰出的读写速度和灵便的数据结构,被广泛应用于多种场景中。以下是 Redis 的一些典型利用场景:

  1. 缓存零碎:这是 Redis 最常见的用处之一。利用其高速的读写性能,能够将热点数据存储在 Redis 中,加重后端数据库的压力,放慢数据的读取速度,进步整体的零碎响应速度。
  2. 会话存储(Session Store):Redis 能够用来存储用户会话信息,尤其实用于分布式系统中的会话共享。因为 Redis 提供长久化性能,即便零碎重启,用户的会话信息也不会失落。
  3. 音讯队列零碎:利用 Redis 的公布 / 订阅模式,能够实现音讯队列的性能,反对高并发的消息传递。此外,利用列表(List)数据结构,也能够实现简略的音讯队列。
  4. 实时剖析:Redis 的高性能读写能力使其非常适合须要实时剖析解决的场景,如计数器、实时系统监控、实时交易剖析等。
  5. 排行榜 / 计数器:Redis 的有序汇合(Sorted Set)数据结构非常适合实现排行榜零碎,能够疾速增加、删除、更新元素,并可能实时获取排名信息。
  6. 天文空间数据处理:Redis 的天文空间索引(Geo)性能能够用来存储地理位置信息,并进行地理位置查问,适宜开发地理位置服务,如查找左近的人或地点。
  7. 分布式锁:Redis 能够实现分布式锁的性能,用于多个过程或零碎之间的同步访问控制。通过 SET 命令的 NX(Not Exists)选项,能够确保只有一个客户端可能取得锁。
  8. 数据过期解决:Redis 反对设置键的生命周期,能够用于须要过期解决的场景,如长期拜访令牌的存储、缓存数据的主动清理等。
  9. 全页缓存(FPC):对于动态网页或者页面输入后果不常常变动的场景,能够将页面 HTML 存储在 Redis 中,实现疾速的页面加载。
  10. 轻量级社交网络性能:利用 Redis 的数据结构和操作命令,能够实现社交网络中的某些性能,如好友关系、共享状态更新、工夫线等。

    ## 7、Memcached 和 Redis 的区别?

    Memcached 和 Redis 都是高性能的分布式缓存零碎,宽泛用于晋升大型动静 Web 利用的速度,缩小数据库负载。只管它们在某些场景下能够调换应用,但两者之间还是存在一些要害的区别:

    ### 数据模型和数据类型

  11. Memcached:提供一个简略的键值存储解决方案,次要反对字符串类型的数据。这意味着它在解决只须要缓存简略数据的场景中十分无效。
  • Redis:反对更丰盛的数据类型,包含字符串(Strings)、列表(Lists)、汇合(Sets)、有序汇合(Sorted Sets)、哈希表(Hashes)、位图(Bitmaps)、超日志(HyperLogLogs)和天文空间索引(Geospatial Indexes)。这种多样性使得 Redis 可能实用于更简单的利用场景。

    持久性

  • Memcached:次要设计为一个纯缓存零碎,没有提供数据长久化性能,一旦缓存服务器重启,所有的数据都会失落。
  • Redis:提供多种数据长久化选项,如 RDB(周期性快照)和 AOF(Append Only File,追加写文件)。这使得 Redis 既能够用作缓存零碎,也能够用作长久化的 NoSQL 数据库。

    分布式反对

  • Memcached:须要内部工具或客户端反对来实现分布式缓存环境,自身不提供数据分片或集群性能。
  • Redis:自 Redis 3.0 起,官网反对集群模式,提供数据分片(Sharding)、主动分区和高可用性等个性。

    高可用和集群

  • Memcached:尽管能够通过一些客户端库实现简略的高可用计划,但 Memcached 自身不提供内建的高可用或复制个性。
  • Redis:反对主从复制(Replication)、哨兵零碎(Sentinel)和主动分区的集群,为构建高可用的分布式缓存环境提供了更多的可能性。

    原子操作

  • MemcachedRedis 都反对原子操作,但因为 Redis 反对更多的数据类型,因而 Redis 在这方面提供了更丰盛的原子操作命令。

    其余个性

  • Redis还提供了许多 Memcached 不具备的个性,如公布 / 订阅音讯零碎、Lua 脚本反对、事务以及天文空间反对等。

    应用场景

  • Memcached实用于简略的缓存场景,特地是当须要疾速缓存大量数据时。
  • Redis不仅实用于缓存场景,还能够用于须要简单数据结构和长久化需要的利用,比方音讯队列、实时剖析、天文空间数据处理等。

    8、为什么要用 Redis 而不必 map/guava 做缓存?

    应用 Redis 而不是 map 或 Guava 做缓存,通常是出于以下几个思考:

    1. 分布式环境反对

  • Redis是一个独立的服务器过程,可能反对多个利用实例共享缓存数据,非常适合分布式环境。这意味着无论是扩大利用实例还是实现高可用性,Redis 都可能提供统一的服务。
  • Map/Guava缓存通常只能在单个 JVM 实例中应用,不适宜分布式环境,因为每个利用实例都会保护本人的缓存正本,这不仅减少了内存耗费,也使得缓存数据难以保持一致。

    2. 长久化能力

  • Redis提供了数据长久化的能力,能够将内存中的数据保留到硬盘中,这对于须要保证数据不会因为过程退出或服务器重启而失落的场景十分重要。
  • Map/Guava缓存通常只存在于内存中,一旦利用重启,所有的缓存数据都会失落。

    3. 高级数据结构和操作

  • Redis提供了丰盛的数据结构(如列表、汇合、有序汇合等)和相应的操作,这些数据结构和操作对于实现简单的缓存策略和性能十分有用。
  • Map/Guava缓存通常提供较为根本的数据结构和操作,可能无奈满足某些简单利用场景的需要。

    4. 缓存淘汰策略

  • Redis内置了多种缓存淘汰策略,如 LRU(最近起码应用)、LFU(最不常常应用)等,这些策略能够帮忙主动治理缓存空间,移除不再须要的缓存项。
  • Map/Guava缓存尽管也提供了一些缓存淘汰策略,但相比 Redis 来说可能不那么灵便或弱小。

    5. 网络拜访和可伸缩性

  • Redis作为一个网络服务,能够被应用程序通过网络拜访,这使得它能够很容易地程度扩大,满足一直增长的数据和访问量。
  • Map/Guava缓存是在应用程序的同一过程内拜访,不反对网络拜访,限度了其在大型分布式系统中的可伸缩性。

    6. 工具和社区反对

  • Redis领有一个沉闷的社区和丰盛的工具生态,提供了大量的客户端库、监控工具和管理工具等。
  • Map/Guava尽管也是宽泛应用的 Java 库,但在分布式缓存方面的工具和社区反对可能不如 Redis 丰盛。

    9、Redis 数据类型有哪些?

    Redis 反对多种数据类型,使其可能应答不同的数据存储需要。上面是 Redis 反对的次要数据类型:

  • 字符串(String)

    • 最根本的类型,能够存储任何模式的字符串,包含文本或二进制数据。
    • 用处宽泛,如缓存文本、存储各种计数器或共享状态等。
  • 列表(List)

    • 一个字符串列表,依照插入程序排序。
    • 能够在列表的头部或尾部增加元素,实现栈(Stack)或队列(Queue)。
    • 适宜用于音讯队列、文章的评论列表等场景。
  • 汇合(Set)

    • 一个无序且元素惟一的字符串汇合。
    • 反对增加、删除、查问操作以及判断某个成员是否存在于汇合中。
    • 实用于标签零碎、社交网络中的好友关系等。
  • 有序汇合(Sorted Set)

    • 不仅每个元素都是惟一的,而且每个元素都会关联一个双精度的分数,Redis 正是通过分数来为汇合中的成员进行从小到大的排序。
    • 反对依照分数范畴或成员查问,非常适合排行榜、带有优先级的工作队列等。
  • 哈希(Hash)

    • 相似于程序语言中的哈希表,能够存储键值对汇合。
    • 键和值都是字符串类型,适宜存储对象或多个字段的聚合数据,如用户的属性信息等。
  • 位图(Bitmap)

    • 实际上是在字符串类型根底上的一种逻辑示意,能够看作是由 0 和 1 组成的数组。
    • 通过位操作能够高效地进行计数和标记,实用于在线用户统计、特色标记等。
  • 超日志(HyperLogLog)

    • 一种基于概率的数据结构,用于高效地进行基数统计的近似计算,如统计独立访客数量。
    • 占用内存十分小,无论统计多少元素,只须要 12KB 内存。
  • 天文空间索引(Geospatial)

    • 能够存储地理位置信息,并进行范畴查问、间隔计算等天文空间相干的操作。
    • 实用于地理位置服务,如查找左近的人或地点。

10、SortedSet 和 List 异同点?

Redis 中的 Sorted Set(有序汇合)和 List(列表)是两种不同的数据结构,它们在应用场景和操作上各有特点。以下是它们的异同点:

相同点

  1. 动静容器:Sorted Set 和 List 都是能够动静增长和缩减的容器,不须要当时申明容器大小。
  2. 存储字符串:两者都能够存储字符串作为元素。
  3. 实用于汇合操作:它们都能够进行增加、删除和获取元素等根本汇合操作。

    不同点

  4. 排序

    • Sorted Set:元素依据分数(score)进行主动排序,每个元素关联一个双精度的分数,Redis 正是通过分数来为汇合中的成员进行从小到大的排序。这意味着即便你增加元素的程序扭转,元素的排列程序也总是依照分数来确定。
    • List:元素依照插入程序排序,反对在列表的头部或尾部增加元素,相似于 Java 中的 LinkedList。列表放弃了元素被增加的程序。
  5. 元素唯一性

    • Sorted Set:汇合中的每个元素必须是惟一的,但分数 (score) 能够反复。
    • List:容许反复元素,即同一个值能够呈现屡次。
  6. 性能

    • Sorted Set:增加、删除、查找操作的复杂度大抵为 O(logN)(N 为汇合的元素数量),这是因为 Redis 外部应用跳跃表(skiplist)或其余均衡树结构来实现 Sorted Set,保障了即便数据量大时操作依然高效。
    • List:在列表的头部(left)或尾部(right)增加、删除操作的复杂度为 O(1),然而如果对列表两头的元素进行操作,复杂度可能会达到 O(N)。
  7. 应用场景

    • Sorted Set:适宜须要对元素排序的场景,如排行榜、带有优先级的工作队列等。
    • List:适宜实现队列或栈这样的数据结构,如音讯队列等。

      11、Redis 的内存用完了会怎么?

      当 Redis 的内存用完时,它的行为取决于配置的内存回收策略和最大内存限度。Redis 提供了几种内存管理机制来解决内存不足的状况:

      1. 内存回收策略(驱赶策略)

      Redis 容许通过 maxmemory-policy 配置项来设置内存回收策略,当内存应用达到 maxmemory 限度时,Redis 会依据设置的策略来回收内存。常见的回收策略包含:

  8. noeviction:不回收任何键,对写操作返回谬误(但容许删除操作和某些非凡状况下的写操作,如对现有键的 SET 操作)。
  • allkeys-lru:尝试回收最近起码应用(Least Recently Used, LRU)的键,不管键有无过期设置。
  • volatile-lru:只从已设置过期工夫的键中,回收最近起码应用的键。
  • allkeys-random:从所有键中随机回收。
  • volatile-random:从已设置过期工夫的键中随机回收。
  • volatile-ttl:回收残余生存工夫(Time To Live, TTL)最短的键。

    2. 达到最大内存限度时的行为

  • 写操作受限 :如果配置了noeviction 策略,当内存用尽时,对于新的写操作,Redis 会返回谬误(错误码 OOM,Out of Memory)。这种状况下,只有对现有键的某些写操作(如笼罩已有键的值)才被容许。
  • 性能影响:即便配置了主动回收策略,当频繁达到内存限度并触发回收机制时,Redis 的性能可能会受到影响,因为须要一直地抉择并移除键。
  • 数据失落:采纳回收策略尽管能够持续进行写操作,但回收旧数据可能导致数据失落。

    3. 避免内存用尽的策略

  • 合理配置 :依据利用场景正当设置maxmemory 值和maxmemory-policy,确保零碎稳固运行。
  • 监控:定期监控 Redis 的内存应用状况,及时调整策略或减少资源。
  • 数据分片:在多个 Redis 实例间调配数据,扩散内存压力。
  • 应用 Redis 集群:通过搭建 Redis 集群,实现数据的主动分片和负载平衡,进步零碎的可扩展性和可用性。

    12、Redis 如何做内存优化?

    Redis 作为内存数据库,其性能强依赖于内存的治理和优化。以下是一些 Redis 内存优化的策略:

    1. 合理配置内存回收策略

    通过 maxmemory-policy 配置适合的内存回收策略,依据理论利用场景抉择最合适的策略,如 volatile-lruallkeys-lruvolatile-ttl 等,以优化内存应用。

    2. 应用适当的数据类型

    正当应用 Redis 反对的数据类型,比方应用哈希(Hash)类型存储对象来节俭空间,因为当存储多个字段的小对象时,哈希类型比独立的字符串类型更节俭内存。

    3. 防止大键和大值

  • 尽量避免存储大键(key)和大值(value),特地是列表、汇合、哈希和有序汇合等数据类型,大的数据结构会显著减少内存的应用。
  • 对于大的列表或汇合,思考分片到多个小对象中。

    4. 利用小对象压缩编码

    Redis 针对小对象提供了压缩编码(如 ziplist 和 intset),这能够显著缩小内存应用。这些优化通常是主动进行的,但理解它们的存在能够帮忙咱们更好地布局数据结构。

    5. 定期删除不必的键

    应用 EXPIRE 命令为键设置生存工夫(TTL),让 Redis 主动删除过期的数据,开释内存。

    6. 应用 SCAN 命令代替 KEYS 命令

    当须要查找合乎特定模式的键时,应用 SCAN 命令代替 KEYS 命令,因为 KEYS 命令会一次性加载所有匹配的键,对内存和 CPU 资源耗费较大。

    7. 内存碎片整顿

    监控内存碎片率(通过 INFO memory 命令查看 mem_fragmentation_ratio 指标),如果内存碎片率过高,能够通过重启 Redis 服务或应用 MEMORY PURGE 命令(在 Redis 4.0 以上版本可用)来缩小内存碎片。

    8. 应用 Redis 6 的客户端缓存性能

    Redis 6 引入了客户端缓存能力,通过将热点数据缓存在客户端来加重服务器端的内存压力。

    9. 监控和剖析内存应用

    定期应用 INFO memory 命令监控内存应用状况,应用 MEMORY USAGE 命令剖析特定键的内存应用,帮忙辨认和优化内存应用热点。

    10. 适时应用长久化

    合理配置 RDB 和 AOF 长久化策略,尽管次要是为了数据安全,但适时的数据长久化和加载也能够帮忙治理内存应用,特地是在须要重启 Redis 开释内存碎片时。

13、keys 命令存在的问题?

Redis 的 KEYS 命令用于查找所有合乎给定模式的键。只管它在某些场景下十分有用,但在生产环境中应用时存在一些显著的问题:

1. 性能问题

  • 阻塞性能 KEYS 命令在执行时会遍历整个数据库的所有键,这是一个阻塞操作。在领有大量键的数据库中,这会导致长时间的阻塞,期间 Redis 不能解决其余命令,影响 Redis 服务器的响应性能。
  • CPU 资源耗费:大规模的键遍历会耗费大量的 CPU 资源,对系统性能产生负面影响,特地是在高流量的生产环境中。

    2. 可伸缩性问题

  • 随着数据量的减少,KEYS命令执行所需的工夫和资源耗费将成指数级增长,这限度了其在大型数据库中的可用性。

    3. 安全性问题

  • 在生产环境中,误用 KEYS 命令可能导致服务临时不可用,影响利用的稳定性和用户体验。

    解决方案

    为了防止这些问题,举荐应用以下办法代替 KEYS 命令:

  • 应用 SCAN 命令 SCAN 命令是为了代替 KEYS 命令而设计的。它提供了一种形式来增量地遍历键空间,容许你每次只获取局部匹配的键。这样,即便在解决大量数据时,也不会阻塞服务器,因为你能够管制每次扫描返回的后果数量。SCAN命令提供了一个游标,每次调用后都会返回一个新游标,你能够在下次迭代时应用这个新游标,直到游标返回 0,示意遍历完结。
  • 保护索引:对于须要频繁查问的键,能够思考在更新数据的同时,将这些键的索引存储在特定的数据结构(如汇合)中。这样,当你须要查问这些键时,能够间接查问索引汇合,而不是遍历整个键空间。

通过应用 SCAN 命令或者保护索引,能够在不就义性能的状况下,无效地查问和治理 Redis 中的键,从而防止 KEYS 命令带来的问题。

14、Redis 事务

Redis 事务提供了一种将多个命令打包,而后按程序执行的机制,确保事务内的命令序列能够间断执行,两头不被其余命令申请所打断。Redis 的事务通过以下几个要害命令来实现:

1. MULTI

标记一个事务块的开始。之后的所有命令都会被退出到队列中,并不会立刻执行。

2. EXEC

执行所有在 MULTI 之后退出队列的命令。当执行 EXEC 时,队列中的所有命令会被间断执行,期间不会插入其余客户端的命令。

3. DISCARD

勾销事务,放弃执行所有曾经被退出队列的命令。

4. WATCH

监督一个或多个键,如果在执行事务之前这些键被其余命令扭转了,那么事务将被打断。WATCH命令能够用来实现乐观锁。

5. UNWATCH

勾销 WATCH 命令对所有键的监督。

Redis 事务的特点:

  • 原子性:Redis 的事务尽管保障了事务内的命令序列间断执行,但它与传统数据库的事务不同,Redis 的事务不反对回滚。如果事务队列中的某个命令执行失败,后续的命令仍会被执行,而不是终止事务。
  • 没有隔离级别的概念:在 Redis 事务执行过程中,不可能有其余客户端插入命令。
  • 乐观锁 :通过WATCH 命令实现乐观锁,能够监督一个或多个键,如果在事务执行之前这些键的值产生了变动,那么事务将不会执行。

    示例

    一个 Redis 事务的简略示例:

    WATCH mykey
    MULTI
    INCR mykey
    INCR mykey
    EXEC

    这个事务尝试对键 mykey 的值进行两次减少。如果在执行事务之前 mykey 的值被其余客户端扭转了,那么这个事务将不会执行。

    注意事项

  • 应用事务时,须要特地留神监督的键。如果事务执行期间,任何一个被监督的键被其余命令所扭转,那么整个事务都将不会执行。
  • Redis 事务不反对回滚,一旦事务开始执行,即便有命令失败,后续的命令也会继续执行。因而,在设计事务时,须要思考到这一点,确保事务中的每个命令都不会失败。

Redis 事务尽管提供了一种执行多个命令的办法,但它的机制与传统数据库的事务有所不同,应用时须要对其个性和限度有充沛的理解。

15、Redis 长久化机制

Redis 提供了两种次要的数据长久化机制来保证数据的安全性:RDB(Redis Database)和 AOF(Append Only File)。这两种机制能够独自应用,也能够同时应用,以达到最佳的数据安全性。上面是对这两种长久化机制的具体介绍:

RDB 长久化

RDB 长久化是通过快照(snapshotting)来实现的,它会在特定的工夫距离保留那一刻的数据快照。

  • 长处

    • RDB 是一个十分紧凑(compact)的文件,它保留了 Redis 在某一时刻的数据。这使得 Redis 重启的时候加载 RDB 文件十分快。
    • RDB 非常适合用于备份,因为每个 RDB 文件都是数据的残缺备份。
    • 应用 RDB 进行长久化能够最大化 Redis 的性能,因为 Redis 在主线程中不须要做任何磁盘 I / O 操作,磁盘 I / O 由独自的子过程负责,这样能够确保性能的最优化。
  • 毛病

    • 如果须要尽可能少地失落数据(比方,在 Redis 解体的状况下),RDB 可能不是最佳抉择,因为你会失落最初一次快照之后的所有批改。
    • 在保留快照的过程中,如果数据集很大,可能会对系统性能产生影响。

      AOF 长久化

      AOF 长久化通过记录每个写操作命令来保留数据状态,这些命令会被追加到 AOF 文件的开端。

  • 长处

    • AOF 能够提供更好的数据安全性,通过配置,你能够控制数据写入磁盘的频率,比方每秒钟同步一次或每次写入都同步。
    • AOF 文件是一个只追加文件,即便在写入过程中零碎解体,也不会像 RDB 那样有文件损坏的危险。
    • AOF 提供了一种更加丰盛的数据恢复策略,因为你能够决定从 AOF 文件的哪个点开始复原数据。
  • 毛病

    • 对于雷同数量的数据变更,AOF 文件的大小通常比 RDB 文件大。
    • 依据 AOF 的配置(尤其是同步策略),AOF 可能会比 RDB 慢,因为 AOF 须要在每次写入时进行磁盘 I / O 操作。

      混合应用 RDB 和 AOF

      Redis 还容许同时应用 RDB 和 AOF,联合两者的长处。在这种配置下,Redis 能够从 AOF 文件中重建状态,以确保操作的完整性,同时也能够定期生成 RDB 快照,用于疾速重启和数据备份。

16、RDB 和 AOF 如何抉择?

在抉择 Redis 的 RDB 和 AOF 长久化机制时,须要依据利用的具体需要来决定。上面是一些思考因素,帮忙你做出抉择:

RDB 长久化

长处

  • 性能:RDB 能够提供更高的性能。快照操作在子过程中进行,对主过程的影响较小。
  • 数据压缩:RDB 文件是压缩过的二进制文件,占用空间较小。
  • 疾速复原:应用 RDB 进行数据恢复比 AOF 快,特地是在解决大数据集时。

实用场景

  • 数据备份。
  • 疾速复原需要较高的场景。
  • 对数据完整性要求不是十分高的场景(能够容忍几分钟内的数据失落)。

毛病

  • 在产生故障时,可能会失落最初一次快照之后的数据。
  • 数据集十分大时,保留快照可能会影响性能。

    AOF 长久化

    长处

  • 数据安全:AOF 提供了更好的数据安全性,能够配置为每秒同步一次或每个命令同步,缩小数据失落的危险。
  • 容错性强 :因为 AOF 采纳追加写的形式,即便在追加过程中零碎解体,也不会毁坏整个文件,且能够通过redis-check-aof 工具修复损坏的 AOF 文件。

实用场景

  • 对数据完整性要求十分高的场景。
  • 能够承受绝对较慢的复原速度或有能力解决较大的 AOF 文件。

毛病

  • 文件大小:AOF 文件通常比 RDB 文件大,须要更多的磁盘空间。
  • 复原速度:AOF 复原速度通常比 RDB 慢。

    综合应用 RDB 和 AOF

    对于大多数生产环境,举荐同时启用 RDB 和 AOF,以联合两者的长处:

  • 应用 RDB 进行疾速的劫难复原。
  • 应用 AOF 保障更高的数据完整性和安全性。

通过合理配置,如调整 AOF 的重写策略和频率,以及定期生成 RDB 快照,能够最大限度地进步数据的安全性,同时确保零碎的性能。

17、Redis 有哪些部署计划?

1. 单机部署

概述 :单机部署是最简略的部署形式,只波及到一个 Redis 服务器实例。
实用场景

  • 开发和测试环境。
  • 小型利用或负载较低的场景。
  • 作为缓存零碎,不波及数据长久化或数据失落危险可控的场景。

长处

  • 部署简略,治理不便。
  • 资源耗费绝对较低。

毛病

  • 高可用性和数据长久化保障较弱。
  • 零碎的扩展性受限。

    2. 主从复制

    概述 :主从复制模式波及一个主服务器和一个或多个从服务器。数据更新操作在主服务器上执行,而后数据的改变会同步到所有的从服务器。
    主从复制的原理?

  • 当启动一个从节点时,它会发送一个 PSYNC 命令给主节点;
  • 如果是从节点首次连贯到主节点,那么会触发一次全量复制。此时主节点会启动一个后盾线程,开始生成一份 RDB 快照文件;
  • 同时还会将从客户端 client 新收到的所有写命令缓存在内存中。RDB 文件生成结束后,主节点会将 RDB 文件发送给从节点,从节点会先将 RDB 文件 写入本地磁盘,而后再从本地磁盘加载到内存中
  • 接着主节点会将内存中缓存的写命令发送到从节点,从节点同步这些数据;
  • 如果从节点跟主节点之间网络呈现故障,连贯断开了,会主动重连,连贯之后主节点仅会将局部缺失的数据同步给从节点。

实用场景

  • 数据备份。
  • 读写拆散,进步读操作的扩展性。

长处

  • 数据有备份,进步了数据安全性。
  • 反对读写拆散,能够通过减少从服务器来进步读操作的并发能力。

毛病

  • 主服务器如果产生故障,须要手动切换到从服务器,高可用性不如哨兵和集群模式。

    3. 哨兵零碎

    概述:哨兵(Sentinel)零碎是基于主从复制模式的主动故障转移解决方案。哨兵负责监控所有 Redis 服务器,并在主服务器故障时主动将一个从服务器降级为新的主服务器。

    工作原理

  • 每个 Sentinel 以每秒钟一次的频率向它所晓得的 Master,Slave 以及其余 Sentinel 实例发送一个 PING 命令。
  • 如果一个实例间隔最初一次无效回复 PING 命令的工夫超过指定值,则这个实例会被 Sentine 标记为主观下线。
  • 如果一个 Master 被标记为主观下线,则正在监督这个 Master 的所有 Sentinel 要以每秒一次的频率确认 Master 是否真正进入主观下线状态。
  • 当有足够数量的 Sentinel(大于等于配置文件指定值)在指定的工夫范畴内确认 Master 确实进入了主观下线状态,则 Master 会被标记为主观下线。若没有足够数量的 Sentinel 批准 Master 曾经下线,Master 的主观下线状态就会被解除。若 Master 从新向 Sentinel 的 PING 命令返回无效回复,Master 的主观下线状态就会被移除。
  • 哨兵节点会选举出哨兵 leader,负责故障转移的工作。
  • 哨兵 leader 会推选出某个体现良好的从节点成为新的主节点,而后告诉其余从节点更新主节点信息。

实用场景

  • 对高可用性要求较高的生产环境。

长处

  • 实现主动故障转移和主从切换,进步零碎的高可用性。
  • 反对服务发现,客户端能够查问哨兵获取以后的主服务器地址。

毛病

  • 部署和配置绝对简单。

    4. 集群模式

    概述:Redis 集群通过分片(Sharding)将数据分布在多个 Redis 节点上,每个节点存储不同的数据片段。集群模式反对主动分区、数据复制和故障转移。

    工作原理:

  • 通过哈希的形式,将数据分片,每个节点均分存储肯定哈希槽 (哈希值) 区间的数据,默认调配了 16384 个槽位
  • 每份数据分片会存储在多个互为主从的多节点上
  • 数据写入先写主节点,再同步到从节点(反对配置为阻塞同步)
  • 同一分片多个节点间的数据不放弃一致性
  • 读取数据时,当客户端操作的 key 没有调配在该节点上时,redis 会返回转向指令,指向正确的节点
  • 扩容时时须要须要把旧节点的数据迁徙一部分到新节点

在 redis cluster 架构下,每个 redis 要放开两个端口号,比方一个是 6379,另外一个就是 加 1w 的端口号,比方 16379。
16379 端口号是用来进行节点间通信的,也就是 cluster bus 的货色,cluster bus 的通信,用来进行故障检测、配置更新、故障转移受权。cluster bus 用了另外一种二进制的协定,gossip 协定,用于节点间进行高效的数据交换,占用更少的网络带宽和解决工夫。
实用场景

  • 大规模数据存储和高并发拜访。
  • 对系统扩展性和高可用性要求很高的场景。

长处

  • 进步了数据的可用性和分布式拜访的性能。
  • 反对线性扩大,能够通过减少更多节点来晋升零碎容量和性能。

毛病

  • 部署和治理较为简单,须要解决节点间的数据路由、负载平衡等问题。

总的来说,抉择哪种部署计划须要依据利用的具体需要、估算以及保护的复杂度等因素综合思考。对于初学者或小型我的项目,能够从单机部署开始;对于须要高可用性和扩展性的生产环境,则应思考应用哨兵零碎或集群模式。

18、Redis 过期键的删除策略?

Redis 解决过期键(expired keys)的机制次要基于两种策略:惰性删除(Lazy Expiration)和定期删除(Periodic Expiration)。这两种策略独特确保了内存的无效治理,同时防止了单个策略可能带来的性能问题。

1. 惰性删除(Lazy Expiration)

  • 机制:当客户端尝试拜访一个键时,Redis 会查看该键是否曾经过期。如果曾经过期,Redis 会在返回后果之前将其删除,确保不会返回过期的数据。
  • 长处:这种办法能够确保只有被拜访的键会被检查和删除,防止了不必要的性能开销。
  • 毛病:如果过期的键永远不被拜访,它们将不会被主动删除,这可能会导致内存的节约。

    2. 定期删除(Periodic Expiration)

  • 机制:Redis 会定期随机查看一些键,如果发现有过期的键就将其删除。这个查看是在 Redis 的主循环中周期性执行的。
  • 长处:通过定期删除,Redis 能够逐步清理掉过期的键,缩小内存的节约。
  • 毛病:这种办法不能保障所有的过期键都能被及时删除,依然有可能呈现过期键临时仍占用内存的状况。同时,频繁的查看操作可能会耗费肯定的计算资源。

    3. 过期键的内存回收

  • 被动清理:在 Redis 进行某些外部操作时,比方保留 RDB 文件或者 AOF 文件重写时,会进行一次全库的过期键扫描,以缩小长久化文件的大小。
  • 配置影响 :能够通过调整 Redis 配置文件中的hz 配置项(管制后台任务的执行频率,包含过期键的查看频率)和maxmemory-policy(当内存达到限度时,决定哪种类型的键会被优先删除)来影响过期键解决的行为。

    19、Redis 的内存淘汰策略有哪些?

    当 Redis 用作缓存时,常常须要解决内存不足的状况。为了解决这个问题,Redis 提供了多种内存淘汰策略,容许在达到内存下限时主动删除一些键。这些策略能够通过配置 maxmemory-policy 设置。以下是 Redis 反对的一些次要内存淘汰策略:

    1. noeviction

  • 不进行任何淘汰,当内存应用达到限度时,对于写操作会返回错误信息。这是默认策略,实用于不容许淘汰任何数据的场景。

    2. allkeys-lru

  • 从所有键中应用 LRU(最近起码应用)算法淘汰数据,不管键是否设置了过期工夫。

    3. volatile-lru

  • 仅从设置了过期工夫的键中应用 LRU 算法淘汰数据。如果没有足够的过期键可淘汰,写操作会返回错误信息。

    4. allkeys-random

  • 从所有键中随机淘汰数据,不管键是否设置了过期工夫。

    5. volatile-random

  • 仅从设置了过期工夫的键中随机淘汰数据。如果没有足够的过期键可淘汰,写操作会返回错误信息。

    6. volatile-ttl

  • 从设置了过期工夫的键中抉择行将过期的键进行淘汰。这种策略会优先淘汰生存工夫(TTL)较短的键。

    7. volatile-lfu (Redis 4.0 及以上版本)

  • 从设置了过期工夫的键中应用 LFU(最不常常应用)算法淘汰数据。LFU 算法会思考键被拜访的频率。

    8. allkeys-lfu (Redis 4.0 及以上版本)

  • 从所有键中应用 LFU 算法淘汰数据,不管键是否设置了过期工夫。

    抉择适合的淘汰策略

    抉择哪种内存淘汰策略取决于具体的利用场景:

  • 如果心愿缓存尽可能多的数据,并且能够承受随机淘汰,则能够抉择 allkeys-randomvolatile-random
  • 如果心愿保留最近或频繁应用的数据,则应该应用 allkeys-lruvolatile-lru策略。
  • 对于心愿依据拜访频率而非最初拜访工夫来淘汰数据的场景,能够应用 allkeys-lfuvolatile-lfu策略。

    20、MySQL 与 Redis 如何保证数据一致性

    在将 MySQL 与 Redis 联合应用时,确保数据一致性是一个常见的挑战。MySQL 作为关系数据库,通常用于长久化存储,而 Redis 作为内存数据库,罕用于缓存。数据一致性问题次要产生在数据更新时,须要同步更新 MySQL 和 Redis 中的数据,以防止脏读(读到旧数据)的状况。以下是一些罕用的策略来保障 MySQL 与 Redis 之间的数据一致性:

    1. 缓存穿透策略

  • 读操作流程:先查问 Redis,如果缓存命中,则间接返回数据;如果缓存未命中,则查问 MySQL,将后果写入 Redis,并返回给客户端。
  • 写操作流程:先更新 MySQL,更新胜利后,再删除 Redis 中对应的键。下一次读申请时,因为 Redis 中没有数据,将从新从 MySQL 加载数据到 Redis。

    2. 提早双删策略

    为了解决在缓存删除和数据库更新之间可能产生的并发申请,能够采纳提早双删策略:

  • 写操作流程

    1. 先删除 Redis 中的缓存数据。
    2. 更新 MySQL 中的数据。
    3. 提早一小段时间(例如,几百毫秒),再次删除 Redis 中的缓存数据。

提早的目标是为了解决在这个短暂的工夫窗口内可能达到的并发读申请,这些申请可能会再次将旧数据加载到缓存中。

3. 应用事务或数据库锁(慎用)

如果利用场景对数据一致性的要求十分高,能够思考在数据库层面应用事务或锁来确保操作的原子性。例如,在更新 MySQL 数据前获取一个分布式锁,直到 Redis 缓存也更新实现后才开释锁。这种办法尽管能够进步数据一致性,但会大大降低零碎的性能和吞吐量。

4. 音讯队列

  • 在某些场景下,能够通过音讯队列来保障 MySQL 和 Redis 的数据更新操作的程序性。操作流程如下:

    1. 将数据更新操作封装成音讯,发送到音讯队列。
    2. 消费者按程序生产音讯,先更新 MySQL,再更新 Redis。

这种办法能够异步地解决数据更新,缩小间接操作数据库和缓存可能带来的提早,但须要解决音讯队列的可靠性和生产程序问题。

5. 读写拆散与数据同步

  • 对于简单的零碎,能够将读写操作拆散。写操作间接操作数据库,并通过某种机制(如定时工作、数据库触发器、日志订阅等)异步更新到 Redis。这种形式实用于读多写少,对实时性要求不高的场景。

    21、Redis 中缓存常见问题有哪些?如何解决

    Redis 缓存在进步零碎性能、缩小数据库压力方面施展着重要作用,但在应用过程中也可能遇到一些常见问题,如缓存穿透、缓存雪崩和缓存击穿等。

    缓存穿透

    问题形容 :缓存穿透是指查问不存在的数据导致申请间接落到数据库上,缓存无奈命中,如果歹意攻打或频繁拜访这类不存在的数据,将给数据库带来很大压力。
    解决策略

  • 空对象缓存:即便数据不存在,也将空后果缓存起来,并设置较短的过期工夫。
  • 布隆过滤器:在缓存层之前应用布隆过滤器,将所有可能存在的数据哈希到一个足够大的位数组中,查问时先通过布隆过滤器判断,如果数据相对不存在,则间接返回,不再拜访数据库。

    缓存雪崩

    问题形容 :缓存雪崩是指在某一个工夫点,缓存中大量的或者全副数据都过期生效,导致所有的申请都落到数据库上,造成刹时数据库拜访压力过大,甚至引起数据库解体。
    解决策略

  • 设置不同的过期工夫:为缓存数据设置不同的过期工夫,防止大量数据同时过期。
  • 应用长久化:利用 Redis 的长久化性能,即便缓存服务重启,也能从磁盘中复原数据。
  • 设置缓存永不过期:对于某些热点数据,能够设置为永不过期,通过程序定期更新缓存内容。

    缓存击穿

    问题形容 :缓存击穿是指对于某个热点 key(大量并发拜访),当这个 key 在缓存中过期的霎时,继续的大量申请就间接落到数据库上,导致数据库刹时压力骤增。
    解决策略

  • 设置热点数据永不过期:对于热点数据,能够设置为永不过期,通过后盾更新缓存来刷新数据。
  • 加锁或队列:当缓存生效时,不是所有的申请都去数据库加载数据,而是用锁或队列的形式,保障只有一个申请去数据库取数据并回填到缓存,其余申请期待缓存回填后再拜访缓存。

    综合策略

    在实践中,常常须要联合多种策略来解决缓存相干问题,比方对热点数据采纳加锁或队列的形式避免缓存击穿,对可能不存在的数据采纳布隆过滤器预防缓存穿透,同时通过设置正当的过期工夫和应用 Redis 长久化性能来避免缓存雪崩。正确的缓存策略和粗疏的零碎设计能够显著晋升零碎的健壮性和稳定性。

    22、Redis 怎么实现音讯队列?

    Redis 能够利用其内置的数据结构和命令实现简略的音讯队列性能,次要通过列表(List)、公布 / 订阅(Pub/Sub)机制,以及流(Streams)来实现。

    1. 利用列表(List)实现音讯队列

    Redis 的列表数据结构提供了 LPUSH/RPUSH 命令用于生产音讯(向列表中增加元素),以及 BLPOP/BRPOP 命令用于生产音讯(从列表中移除并获取元素)。这种办法简略易用,适宜实现根本的音讯队列。
    生产者示例

    LPUSH myqueue message1
  • 这条命令将 message1 增加到名为 myqueue 的列表头部。

消费者示例

BRPOP myqueue 30
  • 这条命令从 myqueue 的尾部移除并获取一个元素,如果列表为空,则期待最多 30 秒直到有元素能够移除。

    2. 利用公布 / 订阅(Pub/Sub)实现音讯队列

    Redis 的公布 / 订阅模式提供了一种音讯播送的机制,容许发布者向一个频道(channel)公布音讯,而所有订阅了该频道的订阅者都能接管到这个音讯。这种形式实用于须要音讯播送的场景。
    发布者示例

    PUBLISH mychannel "Hello, Redis!"
  • 这条命令向 mychannel 频道公布音讯“Hello, Redis!”

订阅者示例

SUBSCRIBE mychannel
  • 这条命令订阅 mychannel 频道,订阅者将接管到通过该频道公布的所有音讯。

    3. 利用流(Streams)实现音讯队列

    Redis 5.0 引入了流(Streams)数据类型,提供了更简单的音讯队列性能,反对长久化、消费者组(Consumer Groups)、音讯确认等高级个性。Streams 是 Redis 对音讯队列和日志数据结构的实现,非常适合构建简单的音讯队列和流解决零碎。
    生产者示例

    XADD mystream * field1 value1 field2 value2
  • 这条命令向名为 mystream 的流中增加一个蕴含 field1field2的音讯。

消费者示例(应用消费者组):

XGROUP CREATE mystream mygroup $ MKSTREAM
XREADGROUP GROUP mygroup myconsumer COUNT 1 BLOCK 1000 STREAMS mystream >
  • 第一条命令创立一个名为 mygroup 的消费者组,关联到 mystream 流。
  • 第二条命令以阻塞模式从 mystream 流中读取音讯,作为消费者组 mygroup 中的 myconsumer 消费者。

通过上述三种形式,Redis 能够灵便地实现音讯队列的性能,满足不同场景下的需要。抉择哪种形式取决于具体的利用场景和对音讯队列性能的需要。

23、Redis 怎么实现延时队列

Redis 能够通过几种不同的形式实现延时队列,这些形式各有特点,实用于不同的场景。以下是几种常见的实现办法:

1. 利用 ZSET(有序汇合)实现延时队列

在这种办法中,能够利用 Redis 的有序汇合(ZSET)来实现延时队列。将音讯以成员(member)的模式存储在 ZSET 中,应用音讯的执行工夫作为分数(score)。通过定期轮询 ZSET,取出已到执行工夫的音讯进行解决。
生产音讯示例

ZADD mydelayqueue <timestamp> "message"
  • <timestamp>代表音讯的执行工夫(Unix 工夫戳),“message”是要延时执行的音讯内容。这条命令将音讯退出到名为 mydelayqueue 的有序汇合中,应用执行工夫作为分数。

生产音讯示例

ZRANGEBYSCORE mydelayqueue 0 <current_timestamp> WITHSCORES LIMIT 0 1
ZREM mydelayqueue "message"
  • 第一条命令获取已到执行工夫(以后工夫戳之前)的音讯,WITHSCORES选项示意同时返回音讯的分数(即执行工夫),LIMIT 0 1示意每次只取一个。
  • 第二条命令从汇合中移除已解决的音讯。

    2. 利用 LIST 和 BRPOPLPUSH 实现延时队列

    这种办法联合应用了列表(LIST)和 BRPOPLPUSH 命令。首先将音讯存储在一个列表中,而后应用 BRPOPLPUSH 命令将音讯从一个列表转移到另一个列表,并设置超时工夫。如果超时工夫到了,音讯就会被转移,这时就能够解决这个音讯了。
    生产音讯示例

    LPUSH myqueue "message"
  • 这条命令将音讯 “message” 增加到 myqueue 列表的头部。

生产音讯示例

BRPOPLPUSH myqueue myprocessingqueue <timeout>
  • 这条命令尝试从 myqueue 列表的尾部移除一个元素,并将其推入 myprocessingqueue 列表的头部,如果 myqueue 为空,命令将阻塞,直到期待超时或发现新的元素能够挪动。<timeout>是超时工夫,单位为秒。

    3. 应用 Redis 的 Keyspace 告诉实现延时队列

    Redis 的 Keyspace 告诉性能能够用来实现另一种类型的延时队列。通过为每个音讯设置一个具备 TTL(Time-To-Live)的 key,当 key 过期时,Redis 会生成一个过期事件。通过订阅这些事件,能够实现延时工作的触发。
    首先,须要开启 Redis 的 Keyspace 告诉性能,在 redis.conf 配置文件中设置:

    notify-keyspace-events Ex

    生产音讯示例

    SETEX message:<message_id> <delay> "message content"
  • 这条命令创立一个 key,例如 message:123,设置其 TTL 为<delay> 秒,值为 “message content”<message_id> 是音讯的惟一标识。

生产音讯示例

  • 须要一个内部的订阅者订阅 Redis 的过期事件,而后依据事件处理音讯。

    24、Redis 中 Pipeline 的作用?

    Redis 中的 Pipeline(管道)是一种将多个命令打包,而后一次性发送给 Redis 服务器执行的技术。应用 Pipeline 能够显著进步 Redis 操作的效率,特地是在须要执行大量独立命令时。它的次要作用和长处包含:

    缩小网络开销

    在没有应用 Pipeline 的状况下,每执行一个 Redis 命令,客户端都须要发送一个申请到服务器,而后期待服务器响应。这种“申请 - 响应”模式在网络提早较高或须要执行大量操作时会十分低效,因为每个命令的执行都会受到网络提早的影响。应用 Pipeline 后,能够一次性发送多个命令到服务器,而后再一次性接管所有命令的执行后果,这样能够显著缩小网络传输造成的提早。

    进步命令吞吐量

    通过 Pipeline 技术,多个命令能够在 Redis 服务器上间断执行,而不须要每执行一个命令就期待客户端的下一个申请,这样能够更无效地利用服务器资源,进步命令解决的吞吐量。

    应用场景

  • 批量插入或更新数据:当须要一次性插入或更新大量数据时,应用 Pipeline 能够缩小命令传输工夫,疾速实现数据操作。
  • 获取多个键的值:如果利用须要一次性获取多个键的值,应用 Pipeline 能够防止屡次往返的网络提早。

    示例

    假如须要将多个键值对设置到 Redis 中,不应用 Pipeline 的形式可能须要这样:

    SET key1 value1
    SET key2 value2
    SET key3 value3

    每执行一个 SET 命令,都须要期待服务器的响应。而应用 Pipeline 后,这些命令能够打包发送:

    # 伪代码,应用 Python 的 redis 客户端
    pipe = redis.pipeline()
    pipe.set('key1', 'value1')
    pipe.set('key2', 'value2')
    pipe.set('key3', 'value3')
    pipe.execute()

    注意事项

    尽管 Pipeline 进步了效率,但也有一些须要留神的中央:

  • Pipeline 会将所有命令的后果存储在内存中,直到执行 execute() 命令。因而,如果 Pipeline 中蕴含大量命令,须要留神内存的应用状况。
  • Pipeline 不是原子操作,Pipeline 中的命令依然是一一执行的。如果须要原子性操作,应该应用 Redis 的事务(MULTI/EXEC命令)。

总的来说,Pipeline 是优化 Redis 性能的无效伎俩,特地实用于须要大量独立 Redis 操作的场景

25、Redis 中的 lua 脚本有什么作用?

Redis 中的 Lua 脚本性能是一个弱小的个性,它容许在 Redis 服务器上原子性地执行多个命令。这意味着能够把一系列操作写成一个 Lua 脚本,而后作为一个整体执行,而不是客户端和 Redis 服务器之间屡次往返通信执行多个命令。

1. 原子性操作

Lua 脚本在执行过程中不会被其余命令打断,整个脚本作为一个原子操作执行。这对于须要多个步骤实现的操作十分重要,确保数据的一致性和完整性,无需放心中途发生变化。

2. 缩小网络开销

将多个命令封装在一个 Lua 脚本中执行,缩小了客户端与 Redis 服务器之间的网络往返次数,进步了效率,尤其是在高提早网络环境中。

3. 代码复用和逻辑封装

Lua 脚本反对将简单的逻辑封装在服务器端,客户端只须要调用执行脚本即可。这样能够在不同的利用和客户端之间复用这些逻辑,缩小了客户端的开发工作量,同时也简化了应用逻辑。

4. 进步性能

对于简单的数据处理逻辑,应用 Lua 脚本能够在 Redis 服务器外部实现,防止了将数据在网络中传输到客户端进行解决的须要,从而进步了整体性能。

5. 服务器端计算

Lua 脚本使得能够在 Redis 服务器上间接进行数据处理和计算,而不是在客户端进行。这对于数据聚合、过滤或转换等操作特地有用。

示例

一个简略的 Lua 脚本示例,实现了原子性地递增键的值并返回新值:

local value = redis.call('INCR', KEYS[1])
return value

这个脚本应用 redis.call 函数执行 INCR 命令,递增指定键的值,并返回新的值。在客户端,只须要发送这个脚本到 Redis 执行即可,例如应用 EVAL 命令。

注意事项

尽管 Lua 脚本在 Redis 中十分有用,但也须要留神一些事项:

  • 性能影响:尽管 Lua 脚本执行是原子性的,但简单的脚本或大量的数据处理仍可能影响 Redis 服务器的性能。
  • 调试艰难:相比于客户端代码,服务器端的 Lua 脚本更难调试和测试。
  • 安全性:须要确保 Lua 脚本不会执行歹意操作,尤其是在执行用户提供的脚本时。

总体而言,Lua 脚本为 Redis 提供了弱小的服务器端逻辑解决能力,使得数据处理更加灵便和高效。

26、什么是 RedLock(红锁)?

RedLock 是一种分布式锁的实现算法,由 Redis 的创造者 Antirez(Salvatore Sanfilippo)提出。这种算法旨在解决在分布式系统中平安地获取锁的问题,特地是在基于 Redis 这种内存数据结构服务器环境下。RedLock 提供了一种办法,用于在没有中心化锁服务的状况下,across 多个 Redis 实例平安地协调锁。

RedLock 算法的工作原理

RedLock 算法的根本思维是应用多个独立的 Redis 实例来防止单点故障问题,算法的步骤如下:

  1. 获取锁 :当客户端尝试获取分布式锁时,它会向 N 个 Redis 实例尝试获取锁,在这个过程中,客户端会生成一个随机的锁 ID(通常是一个随机的字符串),用于标识这个锁的唯一性。对于每一个 Redis 实例,客户端都会尝试应用雷同的 key 和惟一的锁 ID 调用SETNX 命令(或 SET 命令的一个变体,确保原子性,例如SET key value NX PX 10000)。
  2. 锁的工夫限度:在尝试获取锁时,客户端会为每个锁设置一个过期工夫,确保即便产生故障,锁也会主动开释,防止死锁问题。
  3. 少数规定:客户端须要在大多数(N/2+1)的 Redis 实例上胜利获取锁,才算胜利获取分布式锁。
  4. 锁的无效工夫计算:如果客户端在大多数 Redis 实例上胜利获取锁,它将计算锁的无效工夫,即原始无效工夫减去获取锁所破费的工夫。
  5. 开释锁:当客户端实现其操作后,会向所有 Redis 实例发送开释锁的命令,无论它是否在该实例上胜利获取了锁。

    RedLock 的长处

  6. 容错性:因为 RedLock 算法在多个 Redis 实例上操作,即便其中一些实例不可用,只有满足大多数规定,客户端依然能够平安地获取和开释锁。
  • 无中心化:RedLock 不依赖于单个中心化的锁服务,缩小了单点故障的危险。

    注意事项

  • 性能思考:RedLock 算法须要与多个 Redis 实例通信,相比于单个 Redis 实例的锁,可能会有更高的提早。
  • 工夫同步:RedLock 算法的安全性局部依赖于参加的 Redis 实例之间的工夫同步。时钟偏差可能会影响锁的安全性。

    27、Redis 大 key 怎么解决?

    在 Redis 中,大 key 是指那些存储了大量数据的键,如一个蕴含数百万个元素的列表、汇合、哈希表或有序汇合。大 key 在应用过程中会导致多种问题,包含但不限于内存应用高、操作提早减少、阻塞 Redis 服务器等。因而,正当解决大 key 是优化 Redis 性能和稳定性的重要一环。以下是解决大 key 的一些策略:

    1. 发现大 key

    在解决大 key 之前,首先须要辨认它们。能够应用 Redis 命令或工具来帮忙辨认:

  • 应用 redis-cli –bigkeys 命令疾速扫描并报告每种类型的最大 key。
  • 应用 MEMORY USAGE <key> 命令查看特定 key 的内存占用。
  • 应用 SCAN 命令配合 TYPEHLEN/LLEN/SCARD/ZCARD等命令来迭代查问并查看各个 key 的大小。

    2. 宰割大 key

    一旦辨认出大 key,能够通过宰割的形式来解决。依据 key 的类型,采取不同的宰割策略:

  • 列表、汇合和有序汇合:能够将一个大的列表、汇合或有序汇合宰割成多个小的列表、汇合或有序汇合。例如,依据范畴(如时间段)或某些业务逻辑来宰割。
  • 哈希表:对于大的哈希表,能够依据哈希字段的前缀或其余业务逻辑进行宰割。

    3. 渐进式删除大 key

    间接删除一个大 key 可能会导致 Redis 服务器阻塞,影响服务的响应工夫。因而,举荐应用渐进式删除办法:

  • 对于列表、汇合、有序汇合,能够应用 LTRIMSPOP 带数量参数、ZREMRANGEBYRANK等命令,每次删除一部分元素。
  • 对于哈希表,能够应用 HDEL 命令配合 HSCAN 迭代地删除字段。
  • 应用 UNLINK 命令代替 DEL 命令删除 key,UNLINK命令会在后盾异步删除 key,缩小阻塞工夫。

    4. 优化数据结构

  • 评估是否所有数据都须要存储在 Redis 中,对于不常常拜访的数据,思考迁徙到其余存储系统。
  • 应用更内存高效的数据类型,例如,利用 Redis 5 引入的 Streams 代替某些场景下的列表。

    5. 监控和预警

  • 设置监控和预警机制,实时监控 Redis 的内存应用状况和操作提早,及时发现潜在的大 key 问题。
  • 定期审查和优化数据模型,防止将来产生新的大 key。

解决大 key 须要综合思考数据的应用模式、业务需要和 Redis 的性能特点,采取适当的策略来优化。正确治理大 key 对于保护 Redis 实例的高性能和稳定性至关重要。

28、Redis 常见性能问题和解决方案?

Redis 作为一个高性能的内存键值数据库,其性能问题通常与内存治理、数据结构抉择、配置设置以及客户端应用模式无关。上面是一些常见的性能问题及其解决方案:

1. 内存应用过多

问题形容 :Redis 占用的内存超过了物理内存的大小,导致系统应用替换空间,从而影响性能。
解决方案

  • 优化数据结构:应用更加内存高效的数据类型,例如应用哈希类型存储小对象汇合。
  • 数据分片:将数据分布到多个 Redis 实例,防止单个实例内存应用过多。
  • 应用内存淘汰策略:通过配置 maxmemory-policy 来决定当内存达到下限时的数据淘汰策略。
  • 定期清理:应用 EXPIRE 设置键的生存工夫,主动清理不再须要的数据。

    2. 大 key 操作导致的提早

    问题形容 :对蕴含大量元素的键进行操作(如删除一个大列表)可能会阻塞 Redis,导致提早减少。
    解决方案

  • 渐进式删除:对于大 key,应用渐进式删除策略,例如分批次删除元素,防止一次性操作导致的长时间阻塞。
  • 宰割大 key:事后布局,防止单个 key 存储过多的元素,如将大列表宰割成多个小列表。

    3. 谬误的数据类型抉择

    问题形容 :不合理的数据类型抉择会导致内存节约或性能降落。
    解决方案

  • 依据理论应用场景抉择适合的数据类型,例如利用汇合(Set)而不是列表(List)存储惟一元素汇合。
  • 对于频繁批改的小对象,应用哈希(Hash)类型而非字符串(String)类型。

    4. 网络瓶颈

    问题形容 :客户端和 Redis 服务器之间的大量网络往返导致性能降落。
    解决方案

  • 应用 Pipeline 缩小网络往返次数,批量执行命令。
  • 尽可能在服务器端解决简单逻辑,比方应用 Lua 脚本。

    5. 不合理的长久化配置

    问题形容 :频繁的磁盘同步操作会影响性能,特地是在应用 AOF 长久化并配置为每次写入都同步时。
    解决方案

  • 依据数据安全性要求合理配置 AOF 的同步频率,例如改为每秒同步一次。
  • 对于不须要长久化的场景,能够敞开 AOF 或抉择适合的 RDB 快照策略。

    6. 单线程模型导致的 CPU 瓶颈

    问题形容 :尽管 Redis 是基于单线程模型,但在解决大量申请或执行简单命令时,CPU 可能成为瓶颈。
    解决方案

  • 防止应用简单的命令,特地是那些工夫复杂度较高的命令。
  • 在可能的状况下,通过减少更多的 Redis 实例来分担负载,应用负载平衡技术散发申请。

    29、说说为什么 Redis 过期了为什么内存没开释?

    当客户端拜访一个键时,Redis 会查看这个键是否曾经过期。如果曾经过期,Redis 在这个工夫点才会删除这个键。这意味着,如果一个曾经过期的键没有被拜访,它就不会被主动删除,因而内存不会被立刻开释。

    定期删除

    为了加重仅依赖惰性删除可能导致的内存占用问题,Redis 还会定期从数据库中随机测试一些键,并删除其中曾经过期的键。然而,这种办法也不保障所有过期的键都会被及时删除。因为定期删除操作只是随机抽查,并不会遍历所有的键。

    为什么内存没立刻开释

    基于以上两种策略,以下是一些起因导致 Redis 过期键后内存没有立刻开释的状况:

  • 未被拜访:如果过期的键没有被拜访,而且恰好没有被定期删除策略检测到,这些键就会持续占用内存。
  • 定期删除频率:定期删除是通过随机抽样的形式进行的,这意味着并非所有的键都会被查看,特地是在有大量键的数据库中,过期键可能在一段时间内不会被检测到。
  • 性能思考:Redis 设计为高性能的内存数据库,过多的删除操作(尤其是大量键同时过期时)可能会对性能产生影响。因而,Redis 采纳这种折衷的策略来均衡内存应用和性能。

    ### 解决方案

    如果过期键未被及时删除导致内存问题,能够思考以下策略:

  • 调整过期策略 :通过调整maxmemory-policy 配置,能够设置当内存达到限度时主动删除过期键。
  • 手动删除 :能够通过定期运行脚本应用SCAN 命令配合 TTL 查看键的过期工夫,手动删除已过期的键。
  • 监控和调整:监控 Redis 的内存应用状况,依据须要调整定期删除工作的执行频率。

    30、Redis 忽然变慢,有哪些起因?

    Redis 忽然变慢可能由多种起因引起,这些起因可能波及到 Redis 配置、硬件资源、客户端行为等多个方面。以下是一些可能导致 Redis 性能降落的常见起因及其解决方案:

    1. 内存满导致的替换(Swapping)

  • 起因:当 Redis 应用的内存超过物理内存时,操作系统会将局部数据交换到磁盘上,导致性能降落。
  • 解决方案 :优化内存应用,如调整maxmemory 配置和淘汰策略,缩小大 key 和深度嵌套构造,或减少物理内存。

    2. 键过期策略

  • 起因:大量键同时过期可能导致 Redis 在短时间内尝试删除这些键,耗费大量 CPU 资源。
  • 解决方案:防止设置大量键同时过期,尽可能扩散过期工夫。

    3. 长久化阻塞

  • 起因:Redis 的 RDB 快照或 AOF 重写操作可能导致主线程阻塞。
  • 解决方案 :调整快照和 AOF 的配置,如应用正当的保留距离,或启用 AOF 的appendfsync no 设置以异步写入磁盘。

    4. 大量慢查问

  • 起因 :执行简单命令(如KEYS、大范畴的ZREVRANGEBYSCORE 等)或解决大 key 可能导致单个命令执行工夫过长。
  • 解决方案 :优化查问命令,应用SCAN 代替KEYS,防止在大数据集上执行简单命令,宰割大 key。

    5. 网络瓶颈

  • 起因:客户端和 Redis 服务器之间的网络提早或带宽限度。
  • 解决方案:查看网络配置,尽可能在同一局域网内部署客户端和 Redis 服务器,应用 Pipeline 缩小网络往返。

    6. CPU 瓶颈

  • 起因:Redis 服务器 CPU 资源有余,可能因为背景工作(如 AOF 重写)、大量并发连贯或命令解决导致。
  • 解决方案:优化 Redis 配置,缩小并发连接数,降级服务器硬件。

    7. 存在 bigKey,造成阻塞

  • 起因:应用不适合的数据类型存储数据,或数据设计不合理。
  • 解决方案:依据理论需要抉择适合的数据类型,正当设计数据模型。

    8. Redis 版本问题

  • 起因:应用的 Redis 版本中存在已知的性能问题。
  • 解决方案:降级到最新的稳固版本。

    总结

    Redis 性能问题的诊断和解决通常须要从多个角度登程,包含但不限于配置优化、资源调整、查问优化等。应用 INFO 命令查看 Redis 状态,定位问题源头,并依据理论状况采取相应的解决措施。

31、为什么 Redis 集群的最大槽数是 16384 个?

Redis 集群通过分片(Sharding)来提供数据分布式存储的能力,它应用了一种称为哈希槽(Hash Slot)的技术来实现这一点。在 Redis 集群中,有 16384 个哈希槽,这个数字是固定的。每个键通过对其键名进行 CRC16 哈希计算,而后对 16384 取模来决定应该调配到哪个哈希槽,每个哈希槽指向存储数据的节点。
抉择 16384 个槽的起因波及到多个方面的思考:

1. 均衡性能和灵活性

16384 提供了足够的细粒度,使得数据能够在不同的节点间均匀分布,同时防止了治理过多槽所带来的复杂性和开销。这个数字是在性能、存储效率和操作复杂度之间的一个折中抉择。

2. 网络开销和重散布开销

当须要在节点间迁徙槽以实现集群的从新均衡或扩大时,应用 16384 个槽能够限度因槽迁徙所需的网络流量和操作开销。如果槽的数量过多,即便是小规模的调整也可能会导致大量的数据迁徙,减少网络压力和迁徙工夫。

3. CRC16 哈希和取模操作

CRC16 哈希算法生成的后果是一个 16 位的哈希值,这意味着实践上能够有 65536 个不同的后果。Redis 抉择 16384 作为槽数量,是因为它是 2 的 14 次幂,能够通过简略的取模操作疾速计算出一个键应该被调配到哪个槽。这种办法既保证了计算的快速性,也足够在集群环境中扩散键,缩小热点。

4. 实际中的验证

Redis 的设计者在实践中测试了不同的槽数量,最终发现 16384 是在保障性能和治理上的一个较好平衡点。它足够小,使得集群的治理和保护(如配置、监控)绝对简略,又足够大,可能反对大规模的集群部署,满足大多数利用场景的需要。
总之,Redis 集群抉择 16384 个哈希槽是基于性能、效率和操作简便性的综合思考。这个设计使得 Redis 集群可能以较低的治理老本反对高效的数据分布和扩展性。

32、Redis 存在线程平安的问题吗?

Redis 服务器自身是线程平安的,因为它基于一个单线程模型来解决命令。这意味着在任意时刻,只有一个命令在服务器上被执行,因而不会存在多个命令同时批改同一个数据造成的数据不统一问题。Redis 的这种设计简化了并发管制,防止了锁机制带来的复杂性和性能损失,同时也确保了高性能和高吞吐率。
然而,当咱们议论 Redis 的线程平安问题时,通常是指在客户端操作 Redis 时的线程安全性。客户端与 Redis 服务器的交互是否线程平安,取决于所应用的 Redis 客户端库:

  1. 客户端库的线程平安:并非所有的 Redis 客户端库都是线程平安的。一些客户端库设计为线程平安,能够在多个线程中共享和应用同一个连贯实例,而其余客户端库则可能要求每个线程应用独立的连贯实例,或者应用适当的线程同步机制来防止并发拜访问题。因而,开发者在应用 Redis 客户端库时,须要查阅该库的文档,理解其线程安全性,并依据库的领导应用它。
  2. 连接池:为了在多线程利用中无效地应用 Redis,许多线程不平安的客户端库提供了连接池性能。连接池容许利用事后创立肯定数量的 Redis 连贯,并在多个线程间共享这些连贯。每个线程须要与 Redis 交互时,从连接池中借用一个连贯,应用结束后返回连接池。这样既保证了线程平安,又进步了资源利用率和性能。
  3. 事务和 Lua 脚本:在须要执行多个操作作为一个原子操作时,Redis 的事务(MULTI/EXEC 命令)和 Lua 脚本执行提供了服务器端的“线程平安”机制,确保了这些操作序列的原子性和隔离性。

总结而言,Redis 服务器端是线程平安的,因为它实质上是单线程执行命令。客户端操作 Redis 的线程安全性则取决于所应用的客户端库是否反对线程平安,或者是否通过其余机制(如连接池)来确保线程平安。在多线程环境中应用 Redis 时,开发者须要特地留神这一点。

33、Redis 遇到哈希抵触怎么办?

Redis 解决哈希抵触次要依赖于其外部数据结构的设计。Redis 应用哈希表作为根底数据结构之一,哈希表在解决键值对时会遇到哈希抵触。Redis 解决哈希抵触的办法次要是通过链地址法(Separate Chaining)。

链地址法(Separate Chaining)

当两个或多个键的哈希值雷同,即它们映射到同一个哈希桶时,会产生哈希抵触。Redis 通过链地址法来解决这个问题,具体做法如下:

  • 每个哈希桶不间接存储键值对,而是存储了一个指向键值对链表(或者是更简单的数据结构,如跳表)的指针。
  • 如果产生哈希抵触,即新的键值对与现有键值对哈希到同一个桶,Redis 会将这个新的键值对插入到该桶对应的链表的头部(或其余地位,根据具体实现而定)。
  • 查找键时,Redis 会先计算键的哈希值,定位到具体的桶,而后遍历该桶的链表,直到找到该键对应的节点。

    动静扩容

    随着存储的键值对数量减少,哈希表的负载因子(即键值对数量与哈希桶数量的比值)会减少,导致抵触的概率回升,进而影响性能。为了维持效率,Redis 会依据负载因子和其余条件(如是否处于读写操作中)动静地扩容哈希表:

  • 扩容时,Redis 会减少哈希桶的数量,并从新计算每个键的哈希值,将键值对从新散布到新的哈希桶中。
  • Redis 的哈希表扩容是渐进式的。为了防止一次性从新哈希所有键值对带来的大量计算,Redis 会将这个过程摊派到后续的操作中,每次操作只迁徙局部键值对。

    总结

    Redis 通过链地址法无效地解决了哈希抵触问题,确保即便多个键哈希到同一个桶,也能通过遍历链表的形式精确疾速地拜访到每个键。同时,通过动静扩容机制,Redis 可能放弃哈希表的高效性能,即便在存储大量数据的状况下。这些设计使得 Redis 可能作为一个高性能的键值存储解决方案。

34、能说一下 Redis 的 I / O 多路复用吗?

援用知乎上一个高赞的答复来解释什么是 I / O 多路复用。假如你是一个老师,让 30 个学生解答一道题目,而后查看学生做的是否正确,你有上面几个抉择:

  • 第一种抉择:按程序一一查看,先查看 A,而后是 B,之后是 C、D。。。这两头如果有一个学生卡住,全班都会被耽搁。这种模式就好比,你用循环挨个解决 socket,基本不具备并发能力。
  • 第二种抉择:你创立 30 个分身,每个分身查看一个学生的答案是否正确。这种相似于为每一个用户创立一个过程或者 - 线程解决连贯。
  • 第三种抉择,你站在讲台上等,谁解答完谁举手。这时 C、D 举手,示意他们解答问题结束,你上来顺次查看 C、D 的答案,而后持续回到讲台上等。此时 E、A 又举手,而后去解决 E 和 A。

第一种就是阻塞 IO 模型,第三种就是 I / O 复用模型。

Redis 的 IO 多路复用机制容许单个线程高效地监督多个网络连接上的 IO 事件(如读写准备就绪)。这种机制依赖于操作系统提供的selectpollepoll(在 Linux 中)或kqueue(在 BSD 零碎中,包含 macOS)等零碎调用。通过这种形式,Redis 能够在不同的客户端连贯间“疾速切换”,在一个连贯上期待 IO 操作实现的同时,解决其余连贯上的 IO 申请。

最初说一句(求关注,求赞,别白嫖我)

最近无意间取得一份阿里大佬写的刷题笔记,一下子买通了我的任督二脉,进大厂原来没那么难
这是大佬写的,7701 页的 BAT 大佬写的刷题笔记,让我 offer 拿到手软

本文,已收录于,我的技术网站 aijiangsir.com,有大厂残缺面经,工作技术,架构师成长之路,等教训分享

求一键三连:点赞、分享、珍藏

点赞对我真的十分重要!在线求赞,加个关注我会非常感激!

正文完
 0