【Redis】个人笔记
一、什么是Redis
Redis是一个开源的内存数据存储系统,也是一个高性能的键值存储数据库。它支持多种数据结构,包括字符串、哈希表、列表、集合以及有序集合。Redis的特点是快速、灵活和可扩展。
首先,Redis是一个内存数据存储系统,这意味着它将所有数据存储在内存中,因此具有非常快的读写速度。相比于传统的磁盘存储系统,Redis可以提供非常低的读写延迟,使得它非常适合需要快速响应的应用场景,如缓存、实时计算等。
其次,Redis支持多种数据结构。除了最基本的字符串类型,Redis还支持哈希表、列表、集合和有序集合等数据结构。这使得开发者可以根据自己的需求选择最适合的数据结构,并可以利用这些数据结构来实现更复杂的功能。例如,哈希表可以用来存储对象,列表可以用来实现队列和栈,集合可以用来存储唯一值,有序集合可以用来实现排行榜等。
此外,Redis还具有一些特殊的功能。它可以通过持久化机制将数据存储到硬盘上,以防止内存数据丢失。它还支持发布-订阅模式,使得不同的客户端可以通过订阅频道来接收消息。此外,Redis还提供了事务和 Lua 脚本功能,使得开发者可以执行一系列操作来保证数据的一致性。
另外,Redis还具有良好的可扩展性。它支持主从复制,可以将数据复制到多个节点上,提高数据的可用性和容错性。此外,Redis还支持集群模式,可以将数据分布在多个节点上,提供更高的性能和容量。
总而言之,Redis是一个快速、灵活和可扩展的内存数据存储系统,广泛应用于各种场景,包括缓存、实时计算、消息队列等。它的简单易用和高性能使得它成为许多开发者和企业的首选。
二、数据结构
Redis支持多种数据结构,每种结构都有其独特的用途和应用场景。以下是常见的Redis数据结构及其应用场景:
- String(字符串):
- 应用场景: 存储用户信息、缓存数据、计数器等。
- 例子:
SET key value
,GET key
.
- Hash(哈希表):
- 应用场景: 存储对象的字段和值,适合存储用户信息、配置信息等。
- 例子:
HSET key field value
,HGET key field
.
- List(列表):
- 应用场景: 存储有序的元素,适合消息队列、最新消息列表等。
- 例子:
LPUSH key value
,LRANGE key 0 -1
.
- Set(集合):
- 应用场景: 存储无序不重复的元素,适合关注列表、标签等。
- 例子:
SADD key member
,SMEMBERS key
.
- Zset(有序集合):
- 应用场景: 存储带有分数的有序元素,适合排行榜、范围查找等。
- 例子:
ZADD key score member
,ZRANGE key 0 -1 WITHSCORES
.
- Bitmap(位图):
- 应用场景: 存储二进制位,适合记录用户的签到情况、在线状态等。
- 例子:
SETBIT key offset value
,GETBIT key offset
.
- HyperLogLog:
- 应用场景: 用于基数估算,适合统计网站的独立访客数等。
- 例子:
PFADD key element
,PFCOUNT key
.
- List、Set、Zset的过期时间:
- 应用场景: 可以给List、Set、Zset设置过期时间,适合缓存、临时数据等。
- 例子:
EXPIRE key seconds
,TTL key
.
- Bloom Filter(布隆过滤器):
- 应用场景: 快速判断元素是否存在于一个大集合中,适合缓存击穿、分布式系统的唯一性判断等。
- 例子: 通常需要通过编程语言的库来使用布隆过滤器。
- Geo(地理信息):
- 应用场景: 存储地理位置信息,适合附近的人、地理围栏等。
- 例子:
GEOADD key longitude latitude member
,GEORADIUS key longitude latitude radius m
.
这些数据结构提供了灵活的存储方式,可以满足不同应用场景的需求。在设计系统时,根据具体的业务需求选择合适的数据结构是很重要的。
三、缓存穿透
缓存穿透
是指在使用缓存系统时,某个请求查询的数据在缓存中不存在,也不在后端存储系统中,导致每次请求都要访问后端存储系统,从而增加了系统的负载压力,严重影响系统的性能。
缓存系统的设计初衷是为了提高系统的性能和响应速度。当一个请求到达系统时,系统首先会查询缓存,如果缓存中存在该数据,则直接返回给用户,减少了对后端存储系统的访问。但是,当请求查询的数据不存在于缓存中时,系统仍然需要从后端存储系统中获取数据,并将其存入缓存,供后续请求使用。这就是缓存的正常流程。
然而,如果恶意攻击者针对系统中不存在的数据进行大量请求,这些请求会绕过缓存直接访问后端存储系统,导致后端存储系统承受巨大的负载压力。这种情况下就发生了缓存穿透。
缓存穿透可能会造成以下问题
-
性能问题:由于每次请求都要访问后端存储系统,系统的响应时间变慢,影响用户体验。
-
资源浪费:大量无效的请求会占用系统的计算资源和网络带宽,浪费了宝贵的系统资源。
为了解决缓存穿透问题,可以采取以下几种措施
-
布隆过滤器:使用布隆过滤器来过滤掉一部分恶意请求。布隆过滤器是一种概率型数据结构,可以判断一个元素是否在集合中,被广泛用于缓存穿透的解决方案中。
-
缓存空值:当后端存储系统查询不到数据时,也将空值存入缓存。这样,在下一次请求查询相同数据时,就可以直接从缓存中获取空值,而不需要再次访问后端存储系统。
-
设置短暂的过期时间:对于缓存中不存在的数据,可以给其设置一个较短的过期时间。这样,在过期时间内,即使有大量请求查询该数据,也能够直接从缓存中获取,而不需要访问后端存储系统。
-
异步加载数据:当发现某个请求查询的数据不存在于缓存中时,可以异步地去后端存储系统中加载数据,并将其存入缓存。这样可以避免在查询时阻塞请求线程,提高系统的并发性能。
综上所述,缓存穿透是指恶意请求查询缓存中不存在的数据,导致每次请求都需要访问后端存储系统,造成系统性能下降和资源浪费。为了解决这个问题,可以采取布隆过滤器、缓存空值、短暂过期时间和异步加载数据等措施来提升系统的性能和稳定性。
四、缓存击穿
缓存击穿
是指在使用缓存系统时,某个热点数据过期或被删除,而此时又有大量并发请求同时访问该数据,导致缓存系统无法命中并且每个请求都要访问后端存储系统,从而造成后端存储系统的压力过大,严重影响系统的性能。缓存的设计初衷是为了提高系统的性能和响应速度。当一个请求到达系统时,首先会查询缓存,如果缓存中存在该数据,就可以直接返回给用户,避免了访问后端存储系统的开销。然而,当某个热点数据过期或被删除时,如果此时有大量并发请求同时访问该数据,这些请求会绕过缓存直接访问后端存储系统,导致后端存储系统承受巨大的负载压力,而且每个请求都要进行独立的查询和加载数据,重复的工作浪费了系统资源。
缓存击穿可能会造成以下问题
-
性能问题:由于每个请求都要访问后端存储系统,系统的响应时间变慢,影响用户体验。
-
资源浪费:大量无效的请求会占用后端存储系统的计算资源和网络带宽,浪费了宝贵的系统资源。
为了解决缓存击穿问题,可以采取以下几种措施
-
加锁机制:通过在缓存查询的关键代码段加锁,使得只有一个线程可以从后端存储系统加载数据,并将加载的结果存入缓存。其他并发请求在等待锁释放后,直接从缓存获取数据。
预加载数据:在热点数据过期前主动加载数据并存入缓存,避免数据过期时出现大量并发请求同时访问。 -
使用互斥锁:在缓存失效时,只允许一个线程从后端存储系统加载数据,并将结果存入缓存。其他线程在等待期间直接从缓存获取数据,避免重复的查询操作。
-
降低数据过期时间:合理设置缓存数据的过期时间,避免过长的过期时间导致数据过期后出现缓存击穿的情况。
综上所述,缓存击穿是指热点数据过期或被删除,而此时有大量并发请求同时访问该数据,导致缓存系统无法命中并且每个请求都要访问后端存储系统,从而造成后端存储系统的压力过大。为了解决这个问题,可以采取加锁机制、预加载数据、使用互斥锁和降低数据过期时间等措施来提升系统的性能和稳定性。
五、缓存雪崩
缓存雪崩
是指在使用缓存系统时,大量的缓存数据同时失效或被删除,导致多个请求同时访问后端存储系统,从而使得后端存储系统无法承受如此大的负载压力,严重影响系统的性能和可用性。缓存的设计初衷是为了提高系统的性能和响应速度。当一个请求到达系统时,首先会查询缓存,如果缓存中存在该数据,就可以直接返回给用户,避免了访问后端存储系统的开销。然而,当大量的缓存数据同时失效或被删除时,如果此时有大量并发请求同时访问后端存储系统,后端存储系统会受到巨大的负载压力,可能导致系统崩溃或严重延迟。
缓存雪崩可能会造成以下问题
-
1.性能问题:由于大量请求同时访问后端存储系统,系统的响应时间变慢,影响用户体验。
-
2.可用性问题:过多的请求访问后端存储系统可能导致系统崩溃或严重延迟,使得整个系统不可用。
为了解决缓存雪崩问题,可以采取以下几种措施
-
1.设置合理的缓存过期时间:合理设置缓存数据的过期时间,避免大量缓存数据在同一时间失效。可以通过为不同的数据设置不同的过期时间,使得缓存数据的过期时间分散开来,减少缓存失效的集中发生。
-
2.缓存数据异步刷新:在缓存数据即将过期时,异步地从后端存储系统加载数据并刷新到缓存中,避免过多请求同时访问后端存储系统。
-
3.多级缓存策略:引入多级缓存,如本地缓存和分布式缓存,可以在本地缓存失效时从分布式缓存中获取数据,减少直接访问后端存储系统的频率。
-
4.限流和熔断机制:通过限制并发请求的数量或采取熔断机制,当请求过多时暂停或拒绝一部分请求,保护后端存储系统免受过大的负载压力。
综上所述,缓存雪崩是指大量的缓存数据同时失效或被删除,导致多个请求同时访问后端存储系统,使得后端存储系统无法承受如此大的负载压力。为了解决这个问题,可以采取设置合理的缓存过期时间、缓存数据异步刷新、多级缓存策略和限流熔断机制等措施来提升系统的性能和可用性。
六、持久化机制
-
RDB(Redis DataBase)
- 概要: 将内存中的数据以快照的形式定期保存到磁盘。
- 配置: 通过配置文件设置快照保存的频率和条件。
- 优点: 恢复速度快,占用空间小。
- 缺点: 可能会丢失一段时间内的数据。
-
AOF(Append-Only File)
- 概要: 记录所有写操作指令,以追加的方式保存到文件。
- 配置: 通过配置文件设置AOF的同步频率和条件。
- 优点: 不会丢失数据,适用于高可用场景。(也可能会丢失的)
- 缺点: 恢复速度相对较慢,占用磁盘空间相对较大。
-
混合持久化:
- 概要: 同时使用RDB和AOF,兼顾快速恢复和数据不丢失的优势。
七、优化机制
-
过期策略
- 概要: Redis可以为每个key设置过期时间,到期自动删除。
- 配置:
EXPIRE key seconds
- 优点: 避免无用数据长时间存储,释放内存。
-
LRU(Least Recently Used)
- 概要: Redis使用LRU算法来淘汰最近最少使用的key。
- 配置:
maxmemory
设置内存最大占用量,maxmemory-policy
设置淘汰策略。
-
分区(Sharding)
- 概要: 将数据分散到多个Redis实例,提高并发读写能力。
- 优点: 提高横向扩展性,分担单机负载。
- 缺点: 需要在应用层进行数据的一致性维护。
-
优化命令的使用:
- 概要: 避免使用耗时较长的命令,如
keys
、flushall
等。 - 优点: 减少命令执行时间,提高性能。
- 概要: 避免使用耗时较长的命令,如
-
使用数据结构的合理选择:
- 概要: 根据实际场景选择合适的数据结构,如使用Hash存储对象属性。
- 优点: 提高查询效率,降低内存占用。
-
使用连接池:
- 概要: 维护一定数量的Redis连接,避免频繁地创建和关闭连接。
- 优点: 减少连接的开销,提高连接的重用性。
-
使用Pipeline:
- 概要: 将多个命令打包发送,减少网络通信开销。
- 优点: 提高批量操作的性能。
-
适度的数据分片:
- 概要: 将大数据集切分成多个小的数据片段,提高并发处理能力。
- 优点: 减轻单一Redis实例的负担。
综合配置持久化机制和优化机制,可以使Redis在数据安全和性能方面取得平衡,满足不同应用场景的需求。
八、单线程却高性能
- 内存操作:
- Redis主要是基于内存的数据库,因此大多数操作都是在内存中完成的,而内存操作速度非常快。
- 非阻塞I/O:
- Redis采用非阻塞I/O模型,通过事件驱动机制处理网络请求。这意味着在进行读写操作时,单线程可以不断地切换任务,提高CPU的利用率,避免等待I/O操作完成而浪费时间。
- 单一数据结构的原子性操作:
- Redis的单线程模型在处理单一数据结构的原子性操作上非常高效。例如,对于字符串(String)的操作,可以在单个CPU时钟周期内完成。
- 避免多线程切换开销:
- 多线程之间的切换会带来一定的开销,而Redis的单线程模型避免了线程切换的开销。在单线程中,不会出现竞态条件,简化了数据访问的同步问题。
- 无锁设计:
- Redis采用无锁设计,避免了多线程之间的锁竞争。这样可以减少了线程间的争用,提高了整体性能。
- 数据结构和算法的优化:
- Redis在内部使用了高效的数据结构和算法,如快速列表、跳表等,这些数据结构在单线程环境下能够提供高性能的操作。
- 高效的事件驱动模型:
- Redis的事件驱动模型非常高效。它使用了高性能的事件库,能够处理大量的客户端请求,而不会因为等待I/O而被阻塞。
- 适用于高并发读写场景:
- 单线程模型适用于高并发的读写场景,因为读操作是非阻塞的,而写操作通过快速处理可以迅速完成。
虽然Redis是单线程的,但在实际应用中,由于上述因素的综合作用,它能够在高并发的情况下表现出色。需要注意的是,虽然单线程模型对于特定的场景非常高效,但并不适用于所有类型的应用。如果在处理大量计算密集型任务的情况下,可能会限制性能。
九、其他
Redis的优势是什么
- 高性能: Redis主要将数据存储在内存中,因此能够提供非常高的读写性能。
- 支持丰富的数据结构: Redis支持多种数据结构,适用于不同的应用场景。
- 持久化: 提供RDB快照和AOF日志两种持久化方式,可以用于数据备份和灾难恢复。
- 原子操作: Redis支持原子操作,能够在单个命令中执行复杂的操作,确保数据的一致性。
- 分布式: Redis Cluster支持数据分片,实现横向扩展。
什么是Redis的数据淘汰策略
Redis使用LRU(Least Recently Used)作为默认的数据淘汰策略。当内存不足以存储所有数据时,会优先淘汰最近最少使用的键,以释放空间。
Redis的持久化机制有哪些
- RDB快照: 将内存中的数据在指定时间点保存到磁盘上的一个快照文件。
- AOF日志: 记录了执行的写操作,通过重放这些写操作,可以还原数据。
什么是Redis的哨兵模式
哨兵模式是Redis用于高可用性的一种解决方案。它包括一组哨兵节点,用于监控主节点和从节点的健康状况。如果主节点失效,哨兵会选举一个从节点作为新的主节点,确保系统的可用性。
Redis只有单线程吗
Redis是单线程的,主要是指Redis的网络I/O线程,Redis的持久化、集群同步等操作,则是由另外的线程来执行
采用单线程为什么还这么快
Redis4.0版本之前
Redis的大部分操作都是在内存中完成的
单线程你模型避免了多线程之间的竞争
Redis采用了I/O多路复用机制处理大量的客户端Socket请求
Redis4.0版本之后
Redis添加了多线程的支持
但是多线程主要体现在大数据的异步删除功能上
Redis6.0版本之后
新增了多线程i/O的读写并发能力
也采用了多个i/O线程来处理网络请求,因为随着网络硬件的性能提升,Redis的性能瓶颈有时会出现在网络i/O的处理上,所以为了提高网络请求的
在 Redis 6.0 版本之后,也采用了多个 I/O 线程来处理网络请求,这是因为随着网络硬件的性能提升,Redis 的性能瓶颈有时会出现在网络 I/O 的处理上。
所以为了提高网络 I/O 的并行度,Redis 6.0 对于网络 I/O 采用多线程来处理。但是对于命令的执行,Redis 仍然使用单线程来处理,所以大家不要误解 Redis 有多线程同时执行命令。