redis面试题
一、基础知识面试
1.说说你对Redis的理解
Redis是一个基于Key-Value存储结构的开源内存数据库,也是一种NoSQL数据库。
它支持多种数据类型,包括String、Map、Set、ZSet和List,以满足不同应用场景的需求。
Redis以内存存储和优化的数据结构为基础,提供了快速的读写性能和高效的数据访问。常被用作应用与数据库之间的缓存组件,提升数据IO效率。
此外,Redis支持主从复制、哨兵机制和集群方式,实现高可用性和水平扩展。
总而言之,Redis是一款功能强大、灵活且可靠的数据库解决方案,适用于各种企业级应用开发场景。
2.你是如何解决热Key问题的
热 Key 问题是指在缓存系统中,某些特定的缓存key受到高频访问,导致对这些热门数据的读取/写入操作集中在少数几个缓存节点上,使得这些节点的负载过高,而其他节点负载较轻甚至空闲。这会造成系统性能不均衡,可能导致部分请求响应变慢或服务不可用。
解决热 Key 问题有这些方案:
-
缓存预热:在系统启动或业务低峰期,通过批量加载或预先访问热门数据,将这些热门数据提前加载到缓存中。这样可以避免大量请求同时涌入导致的热点问题,提高系统的稳定性和性能。
-
动态散列:将缓存节点组织成一个哈希环,根据缓存键的哈希值将数据分散存储在多个节点上。通过增加缓存节点的数量,让请求更均匀地分布在各个节点上,减轻热 Key 对单个节点的压力。当节点数量发生变化时,可以通过一致性哈希算法进行平滑迁移,避免数据大规模迁移带来的负载过高。
-
数据分片:将数据按特定规则(如数据范围、业务维度等)分成多个片段,分别存储在不同的缓存节点上。这样可以使热 Key 所在的数据尽量均匀地分布在多个节点上,减轻单个节点的压力。
通过综合使用以上解决方案,有效地应对热 Key 问题,提高缓存系统的性能和稳定性。
3.一个REDIS实例最多能存放多少KEYS
Redis 的每个实例最多可以存放约 2^32 - 1 个keys,即大约 42 亿个keys。这是由 Redis 内部使用的哈希表实现决定的,它使用 32 位有符号整数作为索引。Redis 使用的哈希函数和负载因子等因素也会影响实际可存放键的数量。
需要注意的是,尽管 Redis 允许存储数量庞大的键,但在实践中,存储过多的键可能会导致性能下降和内存消耗增加。因此,在设计应用程序时,需要根据实际需求和硬件资源来合理规划键的数量,避免过度使用 Redis 实例造成负担。如果需要存储更多的键值对,可以考虑使用 Redis 集群或分片技术,以扩展整体存储容量。
4.Redis为什么这么快
Redis之所以快速的原因主要包括以下几点:
-
内存存储:Redis将数据存储在内存中,实现了快速的读写操作。
-
单线程模型:Redis采用单线程处理请求,避免了多线程的竞争和上下文切换开销。
-
高效的数据结构:Redis内部使用了高效的数据结构,如哈希表、跳跃表等,提供了快速的数据访问和操作。
-
异步IO:Redis利用异步IO来处理网络请求,能够同时处理多个请求,提高并发性能。
-
事件驱动架构:Redis基于事件驱动的模型,通过事件循环机制处理请求和操作,提高系统的效率。
-
优化的操作:Redis对常用操作进行了优化,如批量操作和管道技术,减少了网络通信开销。
综上所述,Redis之所以快速在于内存存储、单线程模型、高效的数据结构、异步IO、事件驱动架构和优化的操作等因素的综合作用。这使得Redis能够以高性能和高响应速度处理各类数据操作请求。
5.Redis为什么把所有数据都放内存
Redis将所有数据放到内存中的主要原因是为了提供高性能的读写操作。
以下是几个主要的原因:
-
高速读写:内存访问速度快,相比于磁盘和数据库,内存操作速度更快,能够更迅速地响应读写请求。将数据存储在内存中可以大大缩短读写的延迟,提高系统的响应速度和吞吐量。
-
简单数据结构:Redis使用简单的数据结构来存储数据,如字符串、列表、哈希、集合和有序集合等。这些数据结构直接映射到内存,不需要进行复杂的数据转换和序列化操作,提高了读写效率。
-
数据持久化:尽管Redis将数据存储在内存中,但它也支持数据的持久化。通过使用RDB快照和AOF日志两种方式,Redis可以将内存中的数据定期或实时写入磁盘,以保证数据的持久性和安全性。
需要注意的是,由于内存容量有限,Redis的内存管理也是需要考虑的。通过设置合适的数据过期策略、内存淘汰策略和最大内存限制等措施,可以在保证高性能的同时,有效地管理内存使用。同时,Redis也可以通过集群和分片等方式来扩展内存容量和提高系统的可用性和性能。
6.怎么实现Redis的高可用?
要实现Redis的高可用性,可以采取以下几个关键步骤和措施:
-
主从复制:通过设置主从复制,将主节点的数据同步到多个从节点上。主节点负责处理写操作,并将写操作的日志复制给从节点,从节点则负责处理读请求。如果主节点发生故障,可以将一个从节点升级为新的主节点,从而实现故障转移和高可用。
-
哨兵机制:使用Redis 哨兵来监控主节点和从节点的状态。哨兵是一组独立运行的进程,它会监控Redis实例的健康状态,并在主节点出现故障时自动进行故障转移。它还能够监控从节点,并在需要时将其提升为主节点。
-
集群模式:Redis 集群是一种分布式方案,可以将多个Redis节点组成一个逻辑集群,提供数据分片和自动故障恢复。每个节点负责存储和处理部分数据,通过节点间的数据分片和分布式算法保证数据的可用性和负载均衡。当集群中的某个节点出现故障时,集群会自动进行故障转移和恢复。
7.Redis是单线程还是多线程
Redis 采用的是单线程模型。通常说得单线程,主要指的是 Redis 对外提供的键值存储服务的主要流程是单线程的,即网络 I/O 和数据读写是由单个线程来完成的。这样设计可以避免多线程之间的竞争条件和锁开销,提高了访问共享数据的效率。
然而,除了对外提供的键值存储服务,Redis 在某些功能上会使用额外的线程来执行,比如持久化、异步删除和集群数据同步等。这些功能需要在后台执行,不参与主要的网络 I/O 和数据处理。因此,严格来说,Redis 并不是完全单线程。
8.为什么Redis 单线程模型效率也能那么高
尽管Redis采用了单线程模型,但其效率仍然非常高。以下是一些原因:
-
非阻塞IO:Redis使用了事件驱动的非阻塞IO机制。它通过事件循环处理来自客户端的请求,在等待数据IO时并不会阻塞主线程,而是继续处理其他请求。这种机制允许Redis以高效地方式处理大量的并发连接。
-
内存操作:Redis主要将数据存储在内存中,并且由于单线程模型的存在,在内存操作的情况下,Redis可以通过简单的指针操作来实现快速读写,而不需要考虑复杂的数据同步和竞争条件。
-
单线程避免的开销:与多线程模型相比,单线程模型避免了线程间的上下文切换、锁竞争和资源管理开销。这使得Redis可以更高效地使用CPU资源,并减少了大量与线程相关的开销。
需要注意的是,Redis单线程模型适合于处理大量的短期操作和快速响应的场景,但在处理长时间运行的计算密集型任务时可能会有性能上的不足。为了提高处理能力和并发性,可以使用Redis的集群模式、多实例部署或将计算密集型任务委托给其他更适合的工具或语言来处理。
9.说说 Redis 的数据类型
Redis支持五种主要的数据类型:
-
String:String是最常用的数据类型,在Redis中以二进制安全的方式存储字符串值。它可以包含任何类型的数据,比如文本、整数或二进制数据。
-
Hash:Hash是一个键值对的集合,其中每个键都与一个值相关联。在Redis中,Hash可以用于存储和操作对象,每个键值对相当于对象的字段和值。
-
List:List是一个按照插入顺序排序的字符串元素集合。集合中的元素可以重复,可以从列表的两端进行插入和删除操作,可用于实现队列、栈等数据结构。
-
Set:Set是一个无序、唯一的字符串集合,不允许重复的成员。可以对集合执行添加、删除和判断成员是否存在等操作,也支持集合间的交集、并集和差集运算。
-
Sorted Set:Sorted Set是一个有序的字符串集合,每个成员都关联着一个分数。集合中的成员根据分数的大小进行排序,可以进行范围查询和按分数排名操作。
除了这些主要的数据类型,Redis还提供了其他一些特殊的数据结构和功能,如HyperLogLog用于基数统计、Geo用于地理位置信息存储、Pub/Sub用于发布与订阅等。
通过这些不同的数据类型,Redis可以灵活地存储和操作各种类型的数据,满足不同应用场景下的需求。
10.使用 Redis 有哪些好处
使用Redis的好处包括:
-
缓存功能:作为高性能缓存系统,Redis能够将热门数据存储在内存中,提升数据访问速度和减轻数据库负载。
-
高性能:Redis采用内存存储和高效数据结构,具备快速读写速度,适用于处理大量请求和实时数据需求。
-
多样化数据类型:Redis支持多种数据类型,如字符串、哈希、列表、集合和有序集合,满足各种数据存储和操作需求。
-
支持持久化:Redis支持数据持久化,可将数据写入磁盘,确保数据的可靠性和持久存储。
-
支持分布式:Redis提供集群和分片机制,实现数据分布和水平扩展,提供高可用性和可扩展性。
-
简单易用:Redis具有简洁的命令接口,易于使用和管理,同时提供丰富的内置命令和客户端库。
总之,Redis以其高性能、多样化数据类型、持久化支持、缓存功能、分布式支持和简单易用等特点,成为广泛应用于各种场景的数据存储解决方案。
11.说说你对Redis操作原子性的理解
Redis 的操作是原子性的,这是因为 Redis 的每个命令都是以单线程的方式执行的,整个命令的执行过程是不可中断的,要么全部执行成功,要么全部执行失败。
在 Redis 中,每个命令都会被转换成一个或多个底层操作,这些操作会基于数据结构的特定实现来执行。比如,对于字符串类型,获取一个键值对、设置一个键值对等操作都是原子性的。在执行这些底层操作时,Redis 会使用一些技术来保证原子性,主要包括以下两点:
-
Redis 使用单线程模型,避免了多线程之间的竞争条件和锁开销,从而保证了操作的原子性。
-
Redis 在执行一些复杂的操作时,比如事务、Lua 脚本等,会将多个底层操作打包成一个原子性操作,这些底层操作要么全部执行成功,要么全部执行失败。在事务和 Lua 脚本中,Redis 同时支持回滚操作,即当一些命令执行成功,后面的命令出错时,Redis 可以自动撤销已经执行的命令。
因此,Redis 的操作是原子性的,这得益于 Redis 单线程模型和底层操作的实现方式。这种原子性操作保证了 Redis 能够提供高效和可靠的服务。
12.说说Redis的持久化机制
Redis有两种持久化机制:RDB和AOF。
-
RDB是一种快照持久化的方式,它会将Redis在某个时间点的数据状态以二进制的方式保存到硬盘上的一个文件中。RDB持久化可以通过配置定时或手动触发,也可以设置自动触发的条件。RDB的优点是生成的文件比AOF文件更小,恢复速度也更快,适合用于备份和灾难恢复。
-
AOF是一种追加日志持久化方式,它会将Redis执行的写命令追加到一个文件的末尾。当Redis重启时,它会重新执行这些写命令来恢复数据状态。AOF提供了更可靠的持久化方式,因为它可以保证每个写操作都被记录下来,并且不会发生数据丢失的情况。AOF文件可以根据配置进行同步写入硬盘的频率,包括每秒同步、每写入命令同步和禁用同步三种模式。
在使用持久化机制时,可以选择同时使用RDB和AOF,也可以只使用其中一种。同时使用两种方式时,Redis在重启时会先加载AOF文件来恢复数据,如果AOF文件不存在或损坏,则会尝试加载RDB文件。因此,AOF具有更高的优先级。
总结
-
推荐两者均开启
-
如果对数据不敏感,可以选单独用RDB
-
不建议单独用AOF,因为可能会出现Bug
-
如果只是做纯内存缓存,可以都不用
13.MySQL 和 Redis 数据保持一致
MySQL 和 Redis 的关系:MySQL 是数据库,用来持久化数据,一定程度上保证数据的可靠性;Redis 是用来当缓存,用来提升数据访问的性能。
1、缓存不一致是如何产生的
通常缓存不一致是发生在数据有变更的时候。因为每次数据变更你需要同时操作数据库和缓存,而他们又属于不同的系统,无法做到同时操作成功或失败,总会有一个时间差。在并发读写的时候可能就会出现缓存不一致的问题(理论上通过分布式事务可以保证这一点,不过实际上基本上很少有人这么做)。
2、缓存更新的几种设计
缓存更新的设计方法大概有以下四种:
-
先删除缓存,再更新数据库(这种方法在并发下最容易出现长时间的脏数据,不可取)
-
先更新数据库,删除缓存(Cache Aside Pattern)
-
只更新缓存,由缓存自己同步更新数据库(Read/Write Through Pattern)
-
只更新缓存,由缓存自己异步更新数据库(Write Behind Cache Pattern)
14.说说Redis的过期策略
Redis的过期策略主要有三种:惰性删除、定期删除和定期淘汰。
-
惰性删除: 惰性删除是Redis默认的过期键删除策略。当客户端尝试访问一个已过期的键时,Redis会立即将该键删除,并返回空值。这种策略的优点是删除操作是在需要时进行,减少了不必要的删除开销。但是,如果大量过期键在一次性被访问之前没有被访问过,这些键会一直占据内存空间。
-
定期删除:Redis会每隔一段时间执行一次检查,删除那些已过期的键。默认情况下,Redis每秒执行10次检查。定期删除通过释放过期键所占据的内存空间,使得内存能够及时被回收。但这种方式可能会导致内存占用较高,因为Redis并不保证在每次定期删除操作中都会删除足够数量的过期键。
-
定期淘汰: 定期淘汰是Redis 4.0版本引入的一种新的过期策略。与定期删除不同的是,定期淘汰不仅删除已过期的键,而且会主动查找并淘汰一些尚未过期但是由于内存不足而需要释放的键。通过定期淘汰,Redis可以更主动地管理内存,避免因为内存持续增长而导致系统性能下降。
总的来说,我们需要根据实际需求和业务场景选择最适合的过期策略,以平衡内存使用和系统性能。
15.说说Redis的内存淘汰策略
Redis中的内存淘汰策略用于在内存不足时选择要淘汰的键,以释放内存空间。以下是几种常见的内存淘汰策略:
-
LRU(最近最少使用): LRU是Redis默认的内存淘汰策略。根据最近使用的时间戳来判断键的热度,将最久未被使用的键淘汰出去。这种策略保留了最近较常访问的键,适合于热点数据的场景。
-
LFU(最不经常使用): LFU根据键被访问的频率来判断热度,淘汰访问频率最低的键。这种策略适用于访问模式稳定但不同键的访问频率差异明显的场景。
-
Random(随机淘汰): 随机淘汰策略是一种基于概率的淘汰方法,随机选择一个键进行淘汰。这种策略简单高效,但可能导致较高的缓存命中率下降。
-
TTL(生存时间): TTL策略基于键的过期时间,淘汰剩余生存时间最短的键。适用于关注数据实效性的场景。
-
Maxmemory Policy(最大内存策略): Redis提供了几种最大内存策略,包括noeviction(禁止淘汰)、allkeys-lru、allkeys-random等。这些策略是在达到设定的最大内存限制后,对写操作返回错误,避免继续写入导致系统崩溃。
在Redis中,可以通过配置文件或动态命令来设置内存淘汰策略。根据具体的业务需求和数据访问模式,选择合适的内存淘汰策略以提高缓存的效率和性能。
16.Redis有哪些常用应用场景
Redis的常用应用场景主要包括:
-
缓存:作为高性能缓存层,提供快速数据访问。
-
分布式会话管理:实现跨服务器的会话共享。
-
消息队列:用作中间件实现异步通信和任务队列。
-
实时排行榜/计数器:用有序集合实现实时排名和计数功能。
-
地理位置信息存储与查询:支持存储地理位置信息并进行位置查询。
-
实时数据分析:存储实时生成的数据,进行快速统计和分析。
需要注意根据具体场景合理使用,充分考虑内存容量和数据持久化等因素。同时,Redis也可与其他存储系统结合使用构建复杂应用架构。
17.什么是缓存击穿、缓存穿透、缓存雪崩
缓存击穿、缓存穿透和缓存雪崩是与缓存相关的一些常见问题,具体定义如下:
-
缓存击穿:指当一个缓存键(key)对应的数据在缓存中不存在,同时又有大量并发请求访问该缓存键时,这些请求会直接绕过缓存,查询数据库或其他存储系统,导致数据库压力增大。缓存击穿通常在缓存过期后发生。
-
缓存穿透:指当一个查询请求访问一个不存在于缓存中且也不存在于数据库中的数据时,这个请求会无效地继续访问数据库,而不会被缓存。如果黑客故意发送大量非法请求,则缓存层无法起到过滤作用,可能导致数据库负载过大。
-
缓存雪崩:指当缓存集中在某个时间点失效或由于某个原因发生故障,导致大量的请求直接打到后端数据库,造成数据库瞬时压力过大,甚至引起数据库崩溃。在缓存雪崩期间,系统性能急剧下降,无法正常提供服务。
为了应对以上问题,可以采取以下措施:
-
对热点数据采用永不过期策略,避免缓存击穿。
-
在缓存层进行空值缓存,即将查询结果为空的数据也缓存一段时间,避免缓存穿透。
-
设置合理的缓存过期时间,并使用分布式缓存的多节点部署,避免缓存雪崩。
-
引入限流、熔断等机制,控制并发访问量,保护后端系统。
-
对重要数据做冷备份,确保即使缓存失效或故障,仍能从其他系统中恢复数据。
18.REDIS 集群的原理是什么
Redis 集群通过数据分片和主从复制实现了横向扩展和高可用性。它将数据划分为 16384 个哈希槽,并将这些槽均匀地分配到多个节点上。每个节点负责处理一部分槽的数据,实现了数据的分散存储和负载均衡。
在集群中,每个哈希槽有一个主节点和多个从节点。主节点负责处理读写请求,而从节点则通过主从复制机制复制主节点的数据,提供数据的冗余备份和故障恢复功能。
当主节点发生故障时,集群会自动进行故障转移。它会选举一个从节点升级为新的主节点,保证服务的持续可用性。同时,集群管理节点负责监控节点的状态,并协调故障转移过程。
客户端在与 Redis 集群交互时,根据键的哈希值将请求发送到相应的节点。客户端还可以通过集群管理节点获取整个集群的拓扑信息,了解哪些键存储在哪个节点上。
通过数据分片和主从复制,Redis 集群实现了数据水平切分、负载均衡和高可用性。它允许数据规模和吞吐量的线性扩展,并能自动处理节点故障。集群管理节点协调集群状态,客户端通过哈希槽映射与集群交互,从而实现了一个稳定和可靠的 Redis 分布式系统。
19.REDIS集群方案什么情况下会导致整个集群不可用
Redis 集群在以下情况下可能导致整个集群不可用:
-
多个主节点同时故障:如果多个主节点同时发生故障,而且它们的从节点无法正常升级为新的主节点,那么整个集群将无法提供读写服务。
-
集群管理节点故障:集群管理节点负责监控集群状态和协调故障转移操作。如果集群管理节点发生故障,并且无法及时恢复或替换,那么集群将失去管理和协调能力,可能导致集群不可用。
-
网络分区:如果集群中的节点之间发生网络分区,即无法互相通信,那么可能会引起脑裂(split-brain)问题。在这种情况下,每个分区内的节点可能会认为自己是合法的 Redis 集群,导致数据冲突和不一致性,最终导致整个集群无法正常工作。
-
配置错误:如果 Redis 集群的配置出现错误或者某些节点的配置不一致,可能导致集群无法正常运行。
-
内存不足:如果集群中的某个节点的内存不足以容纳当前处理的数据量,可能会导致该节点性能下降甚至崩溃,从而影响整个集群的可用性。
为避免整个集群不可用,建议采取以下措施:
-
配置正确的主从复制和故障转移机制,确保每个主节点都有足够的从节点,并定期进行故障转移测试。
-
部署多个独立的集群管理节点,以确保高可用性和决策一致性。
-
定期检查和监控集群配置,确保各个节点之间的配置一致性。
-
实施网络分区容忍策略,例如使用网络拓扑结构和分布式一致性协议,以减少脑裂问题的发生。
-
监控集群节点的内存使用情况,及时扩容或优化内存管理,避免内存不足问题。
综上所述,要确保 Redis 集群的高可用性和稳定性,需要合理设计和配置集群架构,并采取适当的监控和容错措施来应对潜在的故障情况。
20.REDIS集群会有写操作丢失吗?为什么
在Redis集群中,由于采用了主从复制模型的异步复制机制,写操作有一定的丢失风险。
当客户端向主节点发送写操作时,主节点会立即返回成功响应,而不等待所有从节点执行复制。如果主节点在执行完写操作后出现故障或网络问题,导致从节点无法及时接收到复制操作,那么这些未复制的写操作将会丢失。
为了减少写操作丢失的可能性,可以采取以下措施:
-
定期监测集群状态,确保主从节点之间的复制正常进行;
-
设置合理的持久化策略,将数据写入磁盘或使用AOF模式以便数据恢复;
-
在应用程序层实施数据确认机制,检查写操作是否成功。
需要注意的是,Redis集群的主从复制模型无法完全消除写操作丢失的风险,但通过配置和监控的合理手段,可以最大限度地降低写操作丢失的可能性,保障数据的安全性和可靠性。
21.说说你对PIPELINE的理解
PIPELINE 是 Redis 提供的优化命令执行的机制,通过减少网络往返次数和批量处理命令来提高性能。 它将多个命令打包发送给服务器,减少了网络延迟,提升了吞吐量。 使用 PIPELINE 还可以降低服务器资源消耗,提高整体效率。适用于需要连续执行多个命令或批量操作的场景,特别适合延迟敏感或大量请求的应用程序。 总之,PIPELINE 是一种高效的方式来优化 Redis 命令执行,提升性能和效果。
22.什么是Redis哨兵机制
Redis 哨兵是一种用于高可用性的解决方案,它可以监控 Redis 主从复制模式下的主节点和从节点,发现节点故障,并自动进行故障转移,保证 Redis 系统的稳定性和可靠性。
Redis 哨兵机制由多个相互独立的进程组成,这些进程使用 TCP/IP 协议相互通信,实现 Redis 节点的监控和故障转移。哨兵机制的关键进程包括:
-
sentinel:主进程,用于监控 Redis 节点的状态,并执行故障转移操作。
-
monitor:哨兵进程,用于监控 Redis 的主节点和从节点是否正常工作,并在需要时通知其他哨兵进程和客户端。
-
judge:哨兵进程,用于对节点的健康状况进行评估,并根据预定义的阈值决定是否要将一个不健康的节点标记为“主观下线”。
-
failover:哨兵进程,负责执行故障转移操作,将主节点故障时选举出来的从节点晋升为新的主节点,并通知其他 Redis 节点更新配置信息。
通过上述哨兵进程的协同工作,Redis 哨兵机制可以实现自动化的故障转移,使得 Redis 的高可用性得到有效保障。在实际应用中,可以通过配置多个哨兵进程,使其互相监控和备份,从而进一步提高 Redis 系统的可靠性和稳定性。
23.说说你对缓存双写不一致的理解
缓存双写不一致是指在使用缓存的架构中,当数据更新时,由于缓存和数据库的写操作没有同步进行,导致数据在缓存和数据库之间出现不一致的情况。
以下是对缓存双写不一致的一般理解:
-
更新顺序问题:当应用程序更新了数据库中的数据,但在更新缓存之前发生了错误或异常,导致缓存中的数据仍然是旧值。这种情况下,数据库中的数据已经被修改,但缓存中的数据仍然是旧的,导致缓存和数据库之间存在不一致。
-
缓存失效问题:当数据库中的数据发生变化,并成功更新后,缓存中的数据却没有及时更新或失效了。这可能是由于缓存的过期策略、缓存维护、网络延迟等原因导致的。此时,从缓存读取的数据将是旧值,与数据库中的新值不一致。
-
并发更新问题:当多个应用程序同时更新相同的数据时,缓存和数据库的更新操作可能不是原子性的。如果两个更新操作同时进行,可能会导致缓存和数据库在更新时发生冲突,导致不一致的结果。
为了解决缓存双写不一致的问题,可以考虑以下方法:
-
缓存更新策略:在更新数据库的同时,立即更新缓存,确保缓存中的数据与数据库中的数据保持一致。可以使用同步或异步方式进行。
-
数据库与缓存的事务性操作:通过数据库事务和缓存的原子性操作来保证更新的一致性。
-
更新通知机制:通过发布-订阅(Pub/Sub)模式,或使用消息队列等机制来通知缓存节点更新数据,确保缓存的实时性。
-
使用强一致性缓存:如 Redis 的事务和 pipeline 特性,可以确保对缓存的多个操作按顺序执行,减少不一致的概率。
-
定期刷新缓存:通过定期刷新缓存,保证缓存中的数据不会过期太久,降低不一致性发生的概率。
综上所述,缓存双写不一致是在使用缓存时常见的问题,通过合理的缓存更新策略、事务性操作、更新通知机制等措施,可以有效地减少不一致的发生。
24.Redis 事务支持 ACID 么?
原子性(Atomicity):一个事务的多个操作必须完成,或者都不完成。
一致性(Consistency):事务执行结束后,数据库的完整性约束没有被破坏,事务执行的前后顺序都是合法数据状态。
隔离性(Isolation):事务内部的操作与其他事务是隔离的,并发执行的各个事务之间不能互相干扰。
持久性(Durability):事务一旦提交,所有的修改将永久的保存到数据库中,即使系统崩溃重启后数据也不会丢失。
25.主从复制的作用
-
① 读写分离:master 写、slave 读,提高服务器的读写负载能力。
-
② 负载均衡:基于主从结构、配合读写分离,由 slave 分担 master 负载,并根据需求的变化,改变 slave 的数量,通过多个从节点分担数据读取负载,大大提高 Redis 服务器并发量和数据吞吐量。
-
③ 故障恢复:当 master 出现问题的时候,由 slave 提供服务,实现快速的故障恢复。
-
④ 数据冗余:实现数据热备份,是持久化之外的一种数据冗余方式。
-
⑤ 高可用基石:基于主从复制,构建哨兵模式和集群,实现 Redis 的高可用方案。
26.哨兵作用
-
① 监控:
-
-
不断的检查 master 和 slave 是否正常运行。
-
-
-
master 存活检测、master 和 slave 运行情况检测。
-
-
② 通知(提醒):当被监控的服务器出现问题的时候,向其他(哨兵间、客户端)发送通知。
-
③ 自动故障转移:断开 master 和 slave 之间的连接,选取一个 slave 作为 master ,将其它 slave 连接到新的 master 上,并告知客户端新的服务器地址。
总结
-
监控:同步信息。
-
通知:保持联通。
-
故障转移:
-
-
发现问题。
-
-
-
竞选负责人。
-
-
-
优选新 master 。
-
-
-
新 master 上任,其他 slave 切换 master ,原来的 master 作为 slave 故障恢复后连接。
-
27.集群作用
-
-
① 分散单台服务器的访问压力,实现负载均衡。
-
-
-
② 分散单台服务器的存储压力,实现可扩展性。
-
-
-
③ 降低单台服务器宕机带来的业务灾难。
-
28.分布式锁应该具备哪些条件?
一个最基本的分布式锁需要满足:
-
互斥:任意一个时刻,锁只能被一个线程持有。
-
高可用:锁服务是高可用的,当一个锁服务出现问题,能够自动切换到另外一个锁服务。并且,即使客户端的释放锁的代码逻辑出现问题,锁最终一定还是会被释放,不会影响其他线程对共享资源的访问。这一般是通过超时机制实现的。
-
可重入:一个节点获取了锁之后,还可以再次获取锁。
除了上面这三个基本条件之外,一个好的分布式锁还需要满足下面这些条件:
-
高性能:获取和释放锁的操作应该快速完成,并且不应该对整个系统的性能造成过大影响。
-
非阻塞:如果获取不到锁,不能无限期等待,避免对系统正常运行造成影响。