Redis 解析信息图
什么是 Redis?
Redis("REmote DIctionary Service" 的缩写)是一个开源的键值数据库服务器。
对 Redis 最准确的描述是它是一个数据结构服务器。Redis 的这种特定性质使其在开发人员中非常受欢迎和广泛采用。
与其对行进行迭代、排序和排列,不如从头开始使用数据结构来存储数据?早期,Redis 像 Memcached 一样使用,但随着 Redis 的改进,它变得可行于许多其他用例,包括发布-订阅机制、流处理和队列。
Redis-v2-separate-08.jpeg
用于存储的 Redis 数据类型
主要地,Redis 是一个内存中的数据库,用作其他“真实”数据库(如 MySQL 或 PostgreSQL)前面的缓存,以帮助提高应用程序的性能。它充分利用了内存的速度,并减轻了中央应用程序数据库的负载,用于以下情况:
- 很少更改但经常请求的数据
- 较不关键但经常演化的数据。
上述数据的示例可以包括会话或数据缓存以及仪表板的排行榜或汇总分析。
Redis-v2-separate-05.jpeg
Redis 如何用于缓存
然而,对于许多用例,Redis 提供了足够的保证,可以用作一个功能齐全的主数据库。结合 Redis 插件和各种高可用性(HA)设置,Redis 作为数据库对于某些场景和工作负载变得非常有用。
另一个重要的方面是,Redis 模糊了缓存和数据存储之间的界限。在内存中读取和操作数据比在传统数据存储中使用 SSD 或 HDD 更快,这一点非常重要。
FXZjqMPVUAAqUfs-1.jpeg
每位软件工程师都应该了解的重要延迟和带宽数据。
最初,Redis 最常与 Memcached 进行比较,后者在当时没有任何非易失性持久性。
Memcached
Memcached 由 Brad Fitzpatrick 于 2003 年创建,比 Redis 提前了六年。它最初是一个 Perl 项目,后来被重写为 C 语言。它是当时的事实上的缓存工具。它与 Redis 的主要区别在于它缺乏数据类型和仅支持 LRU(最近最少使用)的有限驱逐策略。
另一个区别是,Redis 是单线程的,而 Memcached 是多线程的。在严格的缓存环境中,Memcached 可能性能不错,但在分布式集群中需要进行一些设置,而 Redis 则可以立即支持此功能。
下面是这两个缓存之间功能的当前比较。
表格
尽管现在可以配置它如何将数据持久化到磁盘,但在首次引入时,Redis 使用了快照,其中内存中数据的异步副本被持久化到磁盘以进行长期存储。不幸的是,这种机制的缺点是在快照之间有可能丢失数据。
自 2009 年以来,Redis 已经成熟。我们将涵盖大部分 Redis 的架构和拓扑,以便您可以将 Redis 添加到您的数据存储系统工具库中。
Redis 架构
在我们开始讨论 Redis 内部之前,让我们讨论各种 Redis 部署及其权衡。
我们将主要关注以下配置:
- 单一 Redis 实例
- Redis 高可用性(HA)
- Redis Sentinel
- Redis 集群
根据您的用例和规模,您可以决定使用哪种设置。
单一 Redis 实例
CleanShot-2022-08-01-at-11.59.06.png
简单的 Redis 部署
单一 Redis 实例是 Redis 最简单的部署方式。它允许用户设置和运行小型实例,以帮助它们增长并加速其服务。然而,这种部署方式并不没有缺点。例如,如果此实例失败或不可用,所有对 Redis 的客户端调用都将失败,从而降低系统的整体性能和速度。
在具有足够内存和服务器资源的情况下,此实例可能非常强大。主要用于缓存的情况可能会在最少的设置中显著提高性能。在足够的系统资源的情况下,您可以在运行应用程序的同一台服务器上部署此 Redis 服务。
了解在系统内部管理数据的一些 Redis 概念至关重要。发送到 Redis 的命令首先在内存中处理。然后,如果这些实例上设置了持久性,就会在某个间隔上有一个分叉进程来促进数据持久性 RDB(Redis 数据的非常紧凑的瞬态表示)快照或 AOF(追加日志文件)。
这两个流程允许 Redis 具有长期存储、支持各种复制策略,并启用更复杂的拓扑。如果 Redis 没有设置持久性来持久化数据,那么在重新启动或故障切换的情况下数据会丢失。如果在重新启动时启用了持久性,它会将 RDB 快照或 AOF 中的所有数据加载到内存中,然后实例可以支持新的客户端请求。
说到这里,让我们看看您可能想要使用的更多分布式 Redis 设置。
Redis 高可用性(HA)
CleanShot-2022-08-01-at-12.00.06.png
具有次级故障切换的 Redis
Redis 另一个常见的设置是主要部署与次要部署的结合,次要部署与主要部署保持同步。当数据写入主要实例时,它会将这些命令的副本发送到辅助实例的客户端输出缓冲区,从而促进复制。辅助实例可以是部署中的一个或多个实例。这些实例可以帮助扩展对 Redis 的读取,或者在主要实例丢失时提供故障切换。
高可用性
高可用性(HA)是系统的一个特性,旨在确保在较长的平均时间内获得一定级别的运行性能,通常是可用性。
在这些 HA 系统中,不应该有单一故障点,因此系统可以迅速且优雅地恢复。这会导致可靠的交叉备份,因此在从主要到次要的过渡期间不会丢失数据,并且能够自动检测故障并从中恢复。
在这个拓扑中有一些需要考虑的新事物,因为我们现在已经进入一个具有许多需要考虑的谬论[1]的分布式系统。以前很简单的事情现在变得更加复杂。
Redis 复制
Redis 的每个主要实例都有一个复制 ID 和一个偏移量。这两个数据对于确定复制实例何时可以继续其复制过程或确定是否需要执行完全同步非常关键。这个偏移量会为发生在主要 Redis 部署上的每个操作递增。
复制 ID,偏移量
更明确地说,当 Redis 复制实例的偏移量仅落后于主要实例的几个偏移量时,它会接收主要 Redis 部署上的其余命令,并在其数据集上重新播放,直到同步为止。如果这两个实例不能就复制 ID 达成一致,或者偏移量对于主要实例来说是未知的,则复制实例将请求完全同步。这涉及到主要实例创建一个新的 RDB 快照,并将其发送到复制实例。在进行此传输时,主要实例会在快照截止和当前偏移之间的所有中间更新上进行缓冲,以在次要实例与快照同步后将其发送给次要实例。复制完成后,复制过程可以正常继续。
如果一个实例具有相同的复制 ID 和偏移量,它们具有完全相同的数据。现在您可能会想知道为什么需要复制 ID。当 Redis 实例升级为主要实例或从头开始作为主要实例重新启动时,它将获得新的复制 ID。这用于推断新升级的次要实例是从哪个以前的主要实例复制而来的。这允许能够执行部分同步(与其他次要实例一起)的能力,因为新的主要实例会记住其旧的复制 ID。
例如,两个实例,主要和次要,具有相同的复制 ID,但偏移量相差几百个命令,这意味着如果这些命令在偏移量稍微落后的实例上重新播放,它们将具有相同的数据集。现在,如果复制 ID 完全不同,当我们不知道新的复制 ID(重新连接并重新加入)的先前复制 ID(没有共同的祖先)时。我们需要执行昂贵的完全同步。
或者,如果我们知道以前的复制 ID,那么我们可以推理出如何使数据同步,因为我们可以推理出它们都共享的公共祖先以及偏移量对于部分同步是有意义的。
Redis Sentinel
CleanShot-2022-08-01-at-13.38.41.png
Redis Sentinel 部署(为了清晰起见,省略了来自其他 Sentinel 节点的额外监视/虚线)
Sentinel 是一个分布式系统。与所有分布式系统一样,Sentinel 具有一些优点和缺点。Sentinel 的设计是这样的,多个 Sentinel 进程一起协同工作,以协调状态,以提供 Redis 的高可用性。毕竟,您不希望系统保护您免受故障的情况下有其自己的单一故障点。
Sentinel 负责几个方面。首先,它确保当前的主要和次要实例正常运行并响应。这是必要的,因为 Sentinel(与其他 Sentinel 进程一起)可以在主要和/或次要节点丢失的情况下发出警报并采取行动。其次,它在服务发现中发挥了类似于其他系统中的 Zookeeper 和 Consul 的作用。因此,当新的客户端尝试将某些内容写入 Redis 时,Sentinel 将告诉客户端当前的主要实例是什么。
因此,Sentinel不断监视可用性,并将这些信息发送给客户端,以便如果它们确实出现故障转移,客户端可以对其做出反应。
以下是其职责:
- 监控 - 确保主要和次要实例按预期工作。
- 通知 - 通知系统管理员有关 Redis 实例中发生的情况。
- 故障转移管理 - Sentinel 节点可以在主要实例不可用并且足够多的(法定人数)节点同意此情况为真时启动故障转移流程。
- 配置管理 - Sentinel 节点还用作当前主要 Redis 实例的发现点。
使用 Redis Sentinel 可以实现故障检测。这种检测涉及到多个 Sentinel 进程达成一致,即当前的主要实例不再可用。这个一致性过程称为法定人数。这允许提高鲁棒性并保护不良机器无法到达主要 Redis 节点的情况。
法定人数
法定人数是分布式系统必须获得的最低选票数,以便允许执行操作,如故障切换。这个数字是可配置的,但应该反映分布式系统中的节点数量。大多数分布式系统的大小为三个或五个,法定人数分别为两个或三个。在需要打破关系的情况下,奇数个节点是首选的。
这种设置不是没有缺点的,因此我们将运行一些在使用 Redis Sentinel 时的推荐和最佳实践。
您可以以多种方式部署 Redis Sentinel。老实说,为了做出任何明智的建议,我需要比我现在拥有的更多的系统上下文。作为一般指导,我建议在每个应用程序服务器旁边运行一个 Sentinel 节点(如果可能的话),这样您也不需要考虑 Sentinel 节点和实际使用 Redis 的客户端之间的网络可达性差异。
您可以将 Sentinel 与 Redis 实例一起运行,甚至可以在独立节点上运行,但这会以不同的方式复杂化事情。我建议至少运行三个节点,法定人数至少为两个。下面是一个简单的图表,详细说明了集群中服务器数量以及关联的法定人数和可容忍的故障数量。
Redis 集群
Redis-v2-separate-03.jpeg
Redis 集群架构
我相信许多人都想知道当您无法在一台机器上存储所有数据时会发生什么。目前,在 AWS 上在线列出的单个服务器上可用的最大 RAM 为 24TB,尽管这很多,但对于某些系统来说,这还不够,即使对于缓存层也是如此。
Redis 集群允许 Redis 进行水平扩展。
垂直和水平扩展
随着系统的增长,您有三种选择:
- 做得更少(没有人完全这样做,因为我们是贪婪的怪物)。
- 增加规模。
- 扩展出去。
认真对待后两种情况,垂直扩展和水平扩展分别称为更大的机器或更多的机器。垂直扩展(更大的机器)并不是永远有效的策略,因为即使是大机器,RAM 也是有限的。
为了使系统能够水平扩展,系统需要能够扩展到多个节点,以便在不同节点之间均匀分布负载。Redis 集群允许用户对多个节点进行组合,以实现这种扩展。尽管 Redis 集群提供了一种方式来实现这一点,但分布式系统非常困难,不应该在不充分理解其优点和缺点的情况下使用。
首先,考虑以下问题:
- 数据的一致性 - 当您写入一个节点时,它如何确保在所有其他节点上都有相同的数据?
- 数据如何分区 - 将数据划分到多个节点时,如何处理数据?
- 故障如何被处理 - 如果节点失败,Redis 如何确保不会丢失数据并继续运行?
Redis 集群是 Redis 提供的官方分布式解决方案。它提供了一种在多个节点之间水平分区数据的方法,并具有自动重新分配和数据复制等内置功能,以处理节点故障。不过,需要注意,Redis 集群也需要更多的配置和维护工作,因为它引入了更多的复杂性。
Redis 集群配置
Redis 集群使用一种分片机制将数据划分为多个槽(slot)。每个槽都可以包含一个键值对。在 Redis 集群中,有 16384 个槽可供使用。当您写入或读取数据时,Redis 集群会根据键的哈希值将其映射到一个槽中,然后确定该槽所在的节点。这样,数据可以均匀地分布在不同的节点上。
在 Redis 集群中,键被映射到槽,并分布在不同的节点上。
要配置 Redis 集群,您需要运行多个 Redis 实例,每个实例都配置为具有不同的端口号和节点标识。这些实例将一起组成 Redis 集群。您还需要一个或多个 Sentinel 进程来监视和管理集群的健康状态。
以下是配置 Redis 集群的一般步骤:
- 启动多个 Redis 实例,每个实例都使用不同的配置文件和端口号,并配置它们为集群节点。
- 创建一个集群配置文件,指定每个节点的主机和端口号,以及槽的分配情况。您可以使用 redis-trib.rb 工具来生成此配置文件。
- 使用 redis-trib.rb 工具创建 Redis 集群。该工具会自动将槽分配给节点,并设置集群中的主节点和从节点。
- 启动 Sentinel 进程以监视集群的健康状态。Sentinel 进程可以配置为自动执行故障切换操作。
- 确保客户端应用程序知道如何连接到 Redis 集群,并使用集群模式来进行读取和写入操作。客户端库通常提供了支持 Redis 集群的功能。
需要注意的是,配置和维护 Redis 集群需要一些复杂性和额外的工作,因此在考虑使用 Redis 集群时,建议仔细研究 Redis 官方文档和最佳实践。
Redis 集群架构示例
以下是一个简单的 Redis 集群架构示例,其中包含 6 个节点(3 个主节点和 3 个从节点)以及 3 个 Sentinel 进程。每个节点都配置为监听不同的端口,并且通过 Redis 集群协议进行通信。
示例 Redis 集群架构
在这个示例中,有三个主节点(M1、M2 和 M3)和三个从节点(S1、S2 和 S3)。每个主节点都有一个或多个从节点,用于复制数据。Sentinel 进程(Sentinel1、Sentinel2 和 Sentinel3)用于监视集群的状态并执行故障切换操作。
Redis 集群的优点包括水平扩展能力、高可用性和自动数据分片。然而,它也需要更复杂的配置和管理,以确保集群的稳定性和性能。
Redis 数据模型
Redis 是一个键值存储系统,其中数据以键值对的形式存储在内存中。每个键都是唯一的,用于检索相关联的值。Redis 支持多种不同的数据类型,使其适用于各种用例。
以下是 Redis 支持的主要数据类型:
- 字符串(String):最简单的数据类型,可以包含文本、数字或二进制数据。字符串类型的值最大可以存储 512MB 的数据。
- 哈希表(Hash):类似于关联数组或字典,用于存储字段和与字段相关联的值。每个哈希表可以存储数百万个字段-值对。
- 列表(List):有序的字符串元素列表。列表支持从两端添加、删除和访问元素。它们适用于队列和栈等数据结构。
- 集合(Set):无序的字符串元素集合,不允许重复元素。集合支持添加、删除和检查成员的操作。
- 有序集合(Sorted Set):类似于集合,但每个成员都关联一个分数,用于排序。有序集合适用于排行榜和范围查询等情况。
- 位图(Bitmap):存储二进制位的数据结构,支持位级别的操作。位图适用于跟踪用户在线状态等应用。
- 超级日志(HyperLogLog):用于估计基数(不同元素的数量)的数据结构,支持基数估计和交集、并集等操作。
- 地理空间索引(Geospatial Index):用于存储地理位置数据和执行地理空间查询的数据结构。
Redis 还支持其他一些数据类型,如流(Stream)和发布-订阅(Pub/Sub),这些类型适用于特定的使用情况。您可以根据您的应用程序需求选择合适的数据类型,并将它们组合使用以满足不同的用例。
总结
Redis 是一个强大的内存数据库,可用于多种用例,包括缓存、数据存储和实时应用程序。您可以根据应用程序的需求选择不同的 Redis 配置,包括单机部署、Redis Sentinel 高可用性配置和 Redis 集群分布式部署。
了解 Redis 的数据模型和支持的数据类型对于有效使用 Redis 非常重要。Redis 提供了多种数据类型,如字符串、哈希表、列表、集合和有序集合,使其适用于各种用例。
最终,Redis 的成功使用取决于正确配置和管理,并且需要根据负载和可用性需求进行扩展和调整。不同的应用程序需要不同的 Redis 部署策略,因此深入了解 Redis 的功能和最佳实践是非常重要的。希望这些信息对您有所帮助,有助于更好地理解 Redis 及其在分布式系统中的作用。