文章目录
- 1、redis简介
- 2、为什么要选择redis做缓存
- 3、数据结构
- 4、redis多线程模型
- redis6.0的变化
- 5、redis持久化
- AOF的实现过程
- RDB的实现过程
- 6、redis集群的搭建
- 7、 redis过期删除和淘汰策略
- 8、redis的内存淘汰策略
1、redis简介
Redis(Remote Dictionary Server)是一个高性能的开源内存数据库系统,它可以用作数据库、缓存和消息代理。Redis最初由Salvatore Sanfilippo开发,后来成为开源项目,得到了广泛的应用和支持。以下是Redis的一些重要特点和用途:
-
内存数据库: Redis主要将数据存储在内存中,这使得它具有非常高的读写速度。它的速度比许多传统的磁盘存储数据库快得多。
-
键值存储: Redis是一个键值存储数据库,其中的数据以键值对的形式存储。这使得它非常适合存储缓存、配置信息、会话数据等。
-
数据结构: Redis支持丰富的数据结构,包括字符串、列表、集合、散列、有序集合等。这些数据结构使得Redis可以用于更广泛的用途,如计数、排名、发布/订阅等。
-
持久性: Redis可以配置为支持不同级别的持久性。你可以将数据持久化到磁盘,以便在重启后恢复数据。
-
复制和高可用性: Redis支持主从复制,可以创建多个Redis实例来提高系统的可用性。如果主节点失效,从节点可以接管服务。
-
分布式: Redis Cluster是Redis的分布式解决方案,它可以水平扩展数据存储和提供高可用性。
-
事务支持: Redis支持事务,你可以在一个事务中执行多个命令,并保证它们要么全部成功,要么全部失败。
-
Lua脚本: Redis允许你使用Lua脚本在服务器端执行一系列命令,这可以提高性能和减少网络开销。
-
发布/订阅: Redis支持发布/订阅模式,可以用于实现消息队列、事件通知等。
-
社区支持: Redis拥有活跃的社区,提供丰富的文档、工具和库,以及解决问题的支持。
Redis广泛用于各种应用场景,包括缓存、会话存储、排行榜、计数器、消息队列等。它的性能、灵活性和可扩展性使其成为许多大型Web应用和分布式系统的核心组件。请注意,尽管Redis非常适用于许多用例,但它也有一些限制,如内存需求较高和持久性配置可能会导致性能下降等。因此,在选择Redis作为解决方案时,需要根据具体的需求和场景仔细考虑配置和使用方式。
2、为什么要选择redis做缓存
很多人都说用 Redis 作为缓存,但是 Memcached 也是基于内存的数据库,为什么不选择它作为缓存呢?要解答这个问题,我们就要弄清楚 Redis 和 Memcached 的区别。 Redis 与 Memcached 共同点:
都是基于内存的数据库,一般都用来当做缓存使用。
都有过期策略。
两者的性能都非常高。
Redis 与 Memcached 区别:
Redis 支持的数据类型更丰富(String、Hash、List、Set、ZSet),而 Memcached 只支持最简单的 key-value 数据类型;
Redis 支持数据的持久化,可以将内存中的数据保持在磁盘中,重启的时候可以再次加载进行使用,而 Memcached 没有持久化功能,数据全部存在内存之中,Memcached 重启或者挂掉后,数据就没了;
Redis 原生支持集群模式,Memcached 没有原生的集群模式,需要依靠客户端来实现往集群中分片写入数据;
Redis 支持发布订阅模型、Lua 脚本、事务等功能,而 Memcached 不支持;
3、数据结构
Redis 支持五种主要的数据类型,每种数据类型都有其独特的特性和用途。以下是这五种数据类型以及它们是如何实现的:
-
字符串(String):
- 字符串是最简单的数据类型,它是一个二进制安全的字符串,可以包含任何数据,如文本、序列化的对象等。
- Redis 使用字节数组(byte array)来表示字符串数据类型。
- 字符串可以存储的内容非常灵活,可以是文本、JSON、XML、二进制数据等。
-
列表(List):
- 列表是有序的字符串元素集合,可以在列表的两端进行插入、删除、获取操作。
- Redis 使用一个双向链表来实现列表数据类型,这使得在列表的两端执行操作的时间复杂度都是 O(1)。
- 列表常用于实现队列、栈等数据结构。
-
集合(Set):
- 集合是无序的字符串元素集合,每个元素都是唯一的,不允许重复。
- Redis 使用哈希表来实现集合数据类型,保证了元素的唯一性。
- 集合常用于实现用户标签、共同好友等应用场景。
-
有序集合(Sorted Set):
- 有序集合是集合的扩展,每个元素都关联一个分数(score),用于排序元素。
- Redis 使用一个跳跃表和一个哈希表来实现有序集合数据类型,使得元素能够按分数有序存储。
- 有序集合常用于排行榜、优先级队列等应用场景。
-
哈希表(Hash):
- 哈希表是一种键值对集合,每个键都映射到一个值。
- Redis 使用哈希表来实现哈希数据类型,其中键是字符串,值可以是字符串。
- 哈希表通常用于存储对象的字段和值,如用户信息、配置信息等。
这些数据类型在Redis内部都有高效的数据结构和算法支持,以实现快速的数据存储和检索。Redis的这种数据模型非常灵活,使其适用于多种不同的应用场景,包括缓存、实时计数、消息队列、分布式锁等。根据具体的需求,你可以选择合适的数据类型来存储和处理数据。
4、redis多线程模型
Redis 使用了单线程的事件循环模型,这是它的主要线程模型。这个单线程并不是指 Redis 只能在单个 CPU 核心上运行,而是指 Redis 采用了事件驱动的方式来处理多个客户端的请求。下面是 Redis 的线程模型的关键特点:
-
单线程处理请求: Redis 主要使用单个线程来处理所有的客户端请求。这个线程负责接受客户端连接、处理命令请求、执行数据操作等操作。
-
事件循环(Event Loop): Redis 的单线程通过事件循环来处理多个客户端请求。它会持续监听文件描述符(sockets)上的事件,如新连接的到来、数据到达等事件。
-
非阻塞 I/O: Redis 使用非阻塞 I/O 操作,这意味着它可以在一个请求等待数据的同时继续处理其他请求,而不会被阻塞。
-
多路复用(Multiplexing): Redis 使用多路复用技术来同时监听多个客户端连接,这有助于提高并发性能。
-
事件处理器: Redis 使用事件处理器来处理各种类型的事件,包括命令请求、定时任务、数据过期等事件。
-
数据结构的原子性操作: Redis 中的许多操作是原子性的,这意味着它们可以在单个事件循环中执行,而不会被其他操作中断。
Redis 之所以选择单线程事件循环模型,是因为它旨在提供高性能和低延迟,特别适用于处理大量的读操作,如缓存、计数器等。这种模型允许 Redis 避免了多线程的复杂性和线程同步开销,使得其代码更加简洁和可维护。但同时也需要注意,如果 Redis 遇到长时间运行的命令或大量的写操作,可能会影响到其他客户端请求的响应时间,因此需要谨慎设计和优化应用。在某些情况下,可以使用多个 Redis 实例来提高性能和可用性。
redis6.0的变化
Redis 6.0 引入了多线程 I/O 模型,这是一个重要的改进,旨在提高 Redis 的网络吞吐量和性能。以下是关于 Redis 多线程 I/O 模型的一些重要信息:
-
目的: 多线程 I/O 的主要目的是提高 Redis 在处理网络请求时的并发能力,尤其是在多核处理器的系统中。传统的单线程模型在处理大量并发请求时可能会受到性能瓶颈的限制,因此引入多线程 I/O 以充分利用多核 CPU 的性能。
-
线程数: Redis 的多线程 I/O 模型可以配置使用多个线程,每个线程都可以处理多个客户端的连接。你可以根据系统的配置和性能需求来决定使用多少个线程。
-
事件循环: 每个线程都有自己的事件循环,用于监听客户端连接的事件,处理读写请求以及执行命令。这意味着 Redis 在多线程模式下可以同时处理多个连接和请求。
-
非阻塞 I/O: Redis 多线程模型仍然使用非阻塞 I/O 操作,这意味着它可以在等待数据就绪时继续处理其他请求,而不会被阻塞。
-
线程同步: 为了确保多线程操作的安全性,Redis 使用了线程同步机制,如互斥锁(Mutex)。这确保了在多线程环境中对共享数据的访问是安全的。
-
性能提升: 多线程 I/O 模型可以显著提高 Redis 在多核 CPU 上的性能。它特别适用于处理大量网络请求的场景,如高吞吐量的 Web 服务。
-
配置和兼容性: Redis 的多线程模式是可配置的,你可以在配置文件中指定线程数。此外,多线程 I/O 模型与 Redis 的命令和数据结构兼容,因此现有的 Redis 应用程序可以相对容易地迁移到多线程模式下。
需要注意的是,虽然多线程 I/O 模型可以提高 Redis 的性能和并发能力,但它也引入了多线程编程的复杂性和线程同步的开销。因此,在使用多线程模式时,需要谨慎设计和优化应用程序,以确保线程安全和高性能。此外,多线程模式可能不适用于所有的 Redis 使用场景,因此需要根据具体需求和系统配置来选择是否使用。
5、redis持久化
Redis 提供了两种主要的持久化机制,以确保数据在服务重启或崩溃时不会丢失。这两种持久化机制分别是快照(Snapshot)和追加文件(Append-Only File,AOF)。下面我将介绍这两种持久化方式:
-
快照(Snapshot)持久化:
- 快照持久化是 Redis 的默认持久化方式。
- 它通过周期性地将内存中的数据快照(snapshot)写入磁盘上的一个二进制文件(RDB 文件)来实现。
- RDB 文件包含了某个时间点上的所有数据,因此在恢复数据时,可以加载这个文件来还原数据状态。
- 快照持久化适用于需要定期备份数据的场景,但在故障发生时可能会导致一定量的数据丢失。
-
追加文件(Append-Only File,AOF)持久化:
- AOF 持久化以追加的方式将每个写操作(包括命令、数据更新等)记录到一个文本文件中。
- 这个文本文件包含了将数据从空状态还原到当前状态所需的所有写操作,因此它是一个逐步构建的日志。
- AOF 文件的内容是可读的,因此可以用于数据恢复、备份以及分析 Redis 的操作历史。
- AOF 持久化适用于对数据完整性要求高的场景,因为它可以最小化数据丢失。
可以根据应用的需求选择其中一种或同时使用两种持久化方式。通常,Redis 用户会根据以下考虑选择持久化方式:
- 数据一致性需求: 如果应用程序要求最小化数据丢失,通常会选择 AOF 持久化,因为它可以提供更细粒度的数据恢复。
- 备份需求: 如果需要定期备份数据以用于灾难恢复,快照持久化通常更方便,因为它创建了一个完整的数据快照。
- 性能: AOF 持久化会导致更多的磁盘写入操作,可能会对性能产生一定的影响。因此,快照持久化在性能上可能更有优势。
此外,Redis 还提供了混合持久化(Mixed Persistence)的功能,允许同时使用快照和 AOF 持久化,以提供更灵活的持久化配置。这使得可以在快照备份的同时,通过 AOF 文件记录写操作以确保数据完整性。
AOF的实现过程
Redis 的 AOF(Append-Only File)持久化是一种将写操作追加到日志文件的方式,用于记录 Redis 服务器的所有写操作。这个日志文件可以用来还原数据,并且在服务器重启时重新执行操作,从而实现数据的持久化。以下是 Redis AOF 持久化的实现过程:
-
AOF 文件的创建和写入:
- 当 Redis 服务器接收到写操作(例如 SET、INCR、DEL 等)时,它不仅会将操作应用到内存中的数据结构,还会将操作以追加的方式写入 AOF 文件。
- Redis 使用操作的文本表示(例如 SET key value)将命令追加到 AOF 文件的末尾。
- AOF 文件包含了一系列写操作的历史记录,这使得可以通过重新执行这些操作来还原数据。
-
AOF 文件的同步:
- 为了确保数据不会丢失,Redis 提供了不同的 AOF 同步选项,包括
always
、everysec
和no
。 always
模式下,每个写操作都会同步到 AOF 文件,确保数据的持久性和完整性。但这也可能导致性能下降,因为每个写操作都需要进行磁盘同步。everysec
模式下,Redis 每秒同步一次 AOF 文件,这可以提供良好的性能和相对较低的数据丢失风险。no
模式下,Redis 不主动同步 AOF 文件,而是依赖操作系统进行同步。这可能会导致较高的数据丢失风险,但具有最好的性能。
- 为了确保数据不会丢失,Redis 提供了不同的 AOF 同步选项,包括
-
AOF 文件的重写:
- 为了避免 AOF 文件不断增长,Redis 提供了 AOF 文件的后台重写机制。
- AOF 重写是一个可选的操作,它会生成一个新的 AOF 文件,其中只包含可以完整还原数据的最小写操作集合。
- 这个过程不会阻塞主 Redis 进程,因为 AOF 重写是在后台进行的。一旦重写完成,旧的 AOF 文件会被替换,从而减小了文件大小。
-
AOF 文件的恢复:
- 当 Redis 服务器启动时,它会尝试从 AOF 文件中重新执行保存的写操作以还原数据状态。
- Redis 会逐行读取 AOF 文件中的命令,并将其应用到内存中的数据结构,从而恢复数据。
- 如果 AOF 文件非常大,恢复可能会花费一定的时间,但这允许 Redis 在崩溃后快速恢复到最后一次同步点的状态。
总之,Redis 的 AOF 持久化通过将写操作以文本形式追加到文件中,以及提供不同的同步选项和后台重写机制,实现了数据的持久性和恢复能力。这使得 Redis 成为一个可靠的数据存储解决方案,适用于多种应用场景。
RDB的实现过程
Redis的RDB(Redis Database Dump)持久化是一种将内存中的数据以二进制形式快照到磁盘的方式,用于数据的备份和恢复。以下是Redis RDB持久化的实现过程:
-
触发快照:
- RDB持久化可以手动触发,也可以通过配置文件中的自动保存选项来定期触发。自动保存选项通常配置了多个不同的时间间隔,Redis会根据这些时间间隔周期性地执行快照操作。
- 当一个快照被触发时,Redis会开始执行RDB持久化。
-
数据快照的创建:
- Redis会创建一个子进程来执行RDB快照操作,以避免阻塞主Redis进程。
- 在创建数据快照之前,Redis会使用复制-on-write机制创建数据副本,以确保在创建快照期间不会修改数据。
- 数据快照以二进制格式保存内存中的数据,包括所有数据库的键值对、数据类型、过期时间等信息。
-
快照数据的写入:
- 数据快照首先会写入一个临时文件,确保在写入完成之前不会破坏原始RDB文件。
- 当快照写入完成后,Redis会用新的快照文件替换旧的RDB文件。这是一个原子操作,确保RDB文件的一致性。
-
快照完成和恢复:
- 一旦快照完成,Redis会记录生成快照的时间戳和其他信息。
- 当Redis需要重启或者从快照文件中恢复数据时,它会加载最新的RDB文件,并将其中的数据恢复到内存中。
- 数据恢复后,Redis可以立即提供服务,且数据与快照时间点一致。
总结来说,Redis的RDB持久化是通过创建内存数据的二进制快照来实现的,这个快照可以随时备份并在需要时恢复数据。RDB持久化适用于备份和恢复整个数据集,以及在启动时快速加载数据。但需要注意的是,RDB持久化是点对点的备份方式,可能会导致一定量的数据丢失,具体取决于触发快照的时间间隔。
6、redis集群的搭建
在 Redis 中搭建集群可以提高性能和可用性,分布数据存储,以及实现负载均衡。Redis 集群是一个分布式系统,由多个 Redis 节点组成,每个节点负责存储一部分数据。以下是在 Redis 中搭建集群的基本步骤:
注意:Redis 集群需要至少6个 Redis 实例,通常是3个主节点和3个从节点,以确保高可用性。
-
安装和配置 Redis:
- 首先,你需要在每个节点上安装 Redis。
- 确保每个节点的 Redis 配置文件(redis.conf)已正确配置,包括绑定IP地址、端口、集群配置等。你需要在配置文件中指定集群模式并提供集群配置文件的路径。
-
创建集群配置文件:
- 在一个节点上,使用
redis-trib.rb
工具来创建集群配置文件。 - 运行以下命令创建集群配置文件:
- 在一个节点上,使用
redis-trib.rb create --replicas 1 <node1>:<port> <node2>:<port> <node3>:<port> ...
其中,<node1>:<port>
,<node2>:<port>
,等等是你要添加到集群的节点的地址和端口。--replicas
选项指定了每个主节点的从节点数量。
-
启动 Redis 节点:
- 启动每个 Redis 节点,确保它们读取了集群配置文件并按照配置运行。
-
添加节点到集群:
- 使用
redis-trib.rb
工具将每个节点添加到集群。运行以下命令来添加节点:
这将把redis-trib.rb add-node <new-node>:<port> <existing-node>:<port>
<new-node>:<port>
添加到<existing-node>:<port>
所在的集群中。
- 使用
-
重新分配槽位(Slots):
- 在 Redis 集群中,数据被分割成一系列槽位。你需要手动将槽位分配给各个节点,以确保负载均衡。
- 使用
redis-trib.rb
工具来分配槽位,或者使用CLUSTER SETSLOT
命令来手动设置。
-
测试集群:
- 使用
redis-trib.rb
工具或者连接到集群中的任何节点来测试 Redis 集群。确保数据正确分布,节点之间可以互相通信,并且集群可以正常工作。
- 使用
-
监控和维护:
- 定期监控 Redis 集群的性能和可用性。
- 需要备份和恢复集群中的数据,以防止数据丢失。
Redis 集群的搭建和维护是一个复杂的过程,需要谨慎处理。建议阅读 Redis 官方文档中关于集群的详细信息,并确保按照最佳实践来设置和运行集群。另外,你也可以考虑使用 Redis Sentinel 或第三方管理工具来简化集群的维护和监控。
7、 redis过期删除和淘汰策略
Redis 中有两种不同的策略来控制内存中数据的清理:过期删除(Expiration)和内存淘汰(Eviction)。它们分别用于处理过期键和内存不足的情况。
-
过期删除(Expiration):
- Redis 允许为每个键设置过期时间(TTL,Time To Live),一旦键过期,它就会被自动删除。
- 过期时间可以通过
EXPIRE
、TTL
、PEXPIRE
等命令来设置,以秒或毫秒为单位。 - Redis 使用定期扫描过期键,并删除已经过期的键。这个过期键扫描是一种懒惰的方式,因为它并不会在键过期时立即删除,而是在后台的扫描任务中进行。
- 这种方式确保了 Redis 的写操作的低延迟,因为过期键的删除是异步执行的。
-
内存淘汰(Eviction):
- 当 Redis 内存用量超出配置的最大内存限制时,它会根据内存淘汰策略删除一些键以腾出内存空间。
- 常见的内存淘汰策略包括:LRU(Least Recently Used,最近最少使用)、LFU(Least Frequently Used,最不经常使用)、Random(随机淘汰)等。
- 可以通过配置文件或运行时命令来选择内存淘汰策略。例如,可以使用
maxmemory-policy
配置选项设置淘汰策略。
总结来说,过期删除和内存淘汰是 Redis 管理内存的两种主要方式。过期删除用于自动删除过期的键,而内存淘汰用于在内存不足时选择性删除键以释放内存空间。这两种机制结合在一起,使得 Redis 能够有效地管理内存,并确保高效的读写性能。根据具体的应用场景和需求,你可以选择合适的过期时间和内存淘汰策略。
8、redis的内存淘汰策略
Redis 提供了多种内存淘汰策略,用于在内存不足时选择性删除键以释放内存空间。以下是常见的 Redis 内存淘汰策略:
-
LRU(Least Recently Used,最近最少使用):
- LRU 策略会删除最近最久未使用的键。当内存不足时,Redis 将优先删除最近最少被访问的键。
- LRU 策略可以通过
maxmemory-policy
配置选项来启用。
-
LFU(Least Frequently Used,最不经常使用):
- LFU 策略会删除访问频率最低的键。当内存不足时,Redis 将优先删除访问次数最少的键。
- LFU 策略可以通过
maxmemory-policy
配置选项来启用。
-
Random(随机淘汰):
- 随机淘汰策略会随机选择一个键进行删除,没有明确的规则。
- 这是一种简单的淘汰策略,但不太可控,因此不适合特定需求。
-
TTL(Time To Live,过期时间):
- TTL 策略会优先删除带有较短过期时间的键。当内存不足时,Redis 将优先删除即将过期的键,以确保过期键及时被清理。
- 这个策略有助于减少过期键堆积造成的内存压力。
-
Allkeys-LRU 和 Allkeys-Random:
Allkeys-LRU
策略会在所有键中选择最近最少使用的键进行删除,而Allkeys-Random
策略则会在所有键中随机选择一个进行删除。- 这两个策略适用于全局淘汰,而不仅限于按数据库或过期时间进行淘汰。
-
No Eviction(不淘汰):
- 如果选择了这个策略,当内存不足时,Redis 将停止写入操作并返回错误,而不会删除键。
- 这个策略可以用于确保数据不会被删除,但在内存不足时会影响写入操作。
可以通过修改 Redis 配置文件中的 maxmemory-policy
选项来选择合适的内存淘汰策略。不同的策略适用于不同的应用场景和需求,你可以根据你的具体情况来选择和配置合适的策略。需要注意的是,选择适当的淘汰策略对于维护 Redis 性能和数据完整性非常重要。