根据您的用例和规模进行决定。 单个 Redis 实例 
Redis 实例是安装 Redis 最简单的方法。它允许用户设置和运行小型实例,帮助他们快速增长并加速他们的服务。然而,这种安装并非没有缺点。例如,如果此实例发生故障或变得不可用,则所有客户端对 Redis 的调用都将失败,从而降低系统的整体性能和速度。 只要有足够的内存和服务器资源,这个实例就可以非常强大。主要用于缓存的场景可以通过最少的设置获得显着的性能提升。如果有足够的系统资源,您可以将此 Redis 服务部署在运行应用程序的同一台计算机上。 在管理系统中的数据时,了解一些 Redis 概念至关重要。发送到 Redis 的命令首先在内存中进行处理。然后,当在这些实例上设置持久性时,在一个间隔内有一个 fork 进程,生成数据持久性 RDB(Redis 数据的非常紧凑的时间点表示)快照或 AOF(仅添加文件)。 这两个进程让Redis能够拥有长期存储,支持多种复制策略,并能够实现更复杂的拓扑。如果 Redis 未配置为保存数据,则数据将在重新启动或故障转移时丢失。如果启用重启时持久性,它会将 RDB 快照或 AOF 中的所有数据加载回内存,然后实例可以支持新的客户端请求。 话虽如此,让我们看看一些可以使用的更多分布式 Redis 设置。 Redis 高可用性 
Redis 的另一种流行框架是主从部署方法,其中从部署与主部署保持数据同步。当数据写入主实例时,它会将这些命令的副本发送到从部署客户端输出缓冲区以实现数据同步。部署中可以有一个或多个实例。这些实例可以帮助扩展 Redis 读取操作或在 main 丢失时进行故障转移。 我们现在进入了一个分布式系统,所以这个拓扑中有很多新的东西需要考虑。以前简单的事情现在变得复杂了。 Redis 复制 Redis 的每个主实例都有一个复制 ID 和一个偏移量。这两条数据对于确定副本可以继续其复制过程或确定是否需要执行完全同步至关重要。对于主 Redis 部署上发生的每个操作,此偏移量都会递增。 更具体地说,如果 Redis 副本实例仅落后主实例几个偏移量,它会从主实例接收剩余命令,然后在其数据集上重播它们,直到同步完成。如果两个实例在复制 ID 上不一致,或者主实例不知道偏移量,则副本会请求完全同步。此时,主服务器创建一个新的 RDB 快照并将其发送到副本。 在此传输期间,主实例会缓冲快照截止和当前偏移之间的所有中间更新指令,以便在快照同步后将它们发送到副本实例。一旦完成,复制就可以正常进行。 如果实例具有相同的复制 ID 和偏移量,则它们具有完全相同的数据。现在您可能想知道为什么需要复制 ID。当 Redis 实例升级为主实例或从头开始重新启动为主实例时,它会获得一个新的复制 ID。 这用于确定此新升级的副本实例是从哪个先前的主实例复制的。这允许执行部分同步(与其他副本节点),因为新主节点会记住其旧的复制 ID。 例如,两个实例(主实例和从实例)具有相同的复制 ID,但偏移量相差数百个命令,这意味着当在实例上的这些偏移量之后重放命令时,它们将具有相同的数据集。现在,如果复制ID完全不同,并且我们不知道新降级(或重新加入)从节点的先前复制ID(没有共同祖先)。我们将不得不进行昂贵的完全同步。 相反,如果我们知道之前的复制 ID,我们就可以推断出数据是如何同步的,因为我们可以推断出它们共享的共同祖先,并且偏移量对于部分同步来说再次有意义。 Redis Sentinel 
Sentinel 是一个分布式系统。与所有分布式系统一样,Sentinel 有几个优点和缺点。 Sentinel 的设计是为了让多个 Sentinel 进程协同工作来协调状态,从而为 Redis 提供高可用性。毕竟,您不希望保护您免受故障影响的系统有自己的单点故障。 Sentinel 负责几件事。首先,它确保当前主从实例正常工作并响应。这是必要的,以便 Sentinel(以及其他 Sentinel 进程)可以在主节点和/或从节点丢失时发出警报并采取行动。其次,它起到服务发现的作用,就像其他系统中的Zookeeper、Consul一样。因此,当新客户端尝试写入 Redis 时,Sentinel 会告诉客户端当前的主实例是什么。 因此,Sentinel 会持续监控可用性并将此信息发送给客户端,以便他们在出现故障时能够做出反应。 以下是他们的职责: - 监控 - 确保主实例和从实例按预期工作。
- 通知 - 通知系统管理员有关 Redis 实例中的事件。
- 故障转移管理 - 如果主实例不可用并且足够的(仲裁)节点同意这一点,哨兵节点可以启动故障转移。
- 配置管理 - Sentinel 节点还充当当前主 Redis 实例的发现服务。
以这种方式使用 Redis Sentinel 可以实现错误检测。此检测涉及多个哨兵进程一致认为当前主实例不再可用。这个共识过程称为法定人数。这提高了鲁棒性并防止机器行为不当导致主 Redis 节点无法访问。 此设置并非没有缺点,因此我们将介绍使用 Redis Sentinel 时的一些建议和最佳实践。 您可以通过多种方式部署Redis Sentinel。坦率地说,为了提出有意义的建议,我需要更多有关您的系统的背景信息。作为一般指南,我建议在每个应用程序服务器旁边运行 Sentinel 节点(如果可能),这样您就不必考虑 Sentinel 节点与使用 Redis 的客户端之间的网络可达性差异。 您可以使用 Redis 实例运行 Sentinel,甚至可以在独立节点上运行 Sentinel,但处理方式不同,这使事情变得更加复杂。我建议至少运行三个节点,并且法定人数至少为两个。这是一个简单的图表,详细说明了集群中的服务器数量以及相关的仲裁和可以容忍的持续故障。 服务器数量 | 法定人数 | 容忍的错误数量 |
---|
1 | 1 | 0 | 2 | 2 | 0 | 3 | 2 | 1 | 4 | 3 | 1 | 5 | 3 | 2 | 6 | 4 | 2 | 7 | 4 | 3 |
这会因系统而异,但总体思路保持不变。 让我们花点时间思考一下这样的设置可能会出现什么问题。如果你运行这个系统足够长的时间,你就会遇到所有这些。 - 如果哨兵节点超过法定人数怎么办?
- 如果网络分裂使旧的主实例成为少数怎么办?这些著作会发生什么? (剧透:系统完全恢复后就会丢失)
- 如果哨兵节点和客户端节点(应用节点)的网络拓扑错位会怎样?
没有持久性保证,特别是因为持久化到磁盘的操作(见下文)是异步的。当客户发现新小学时,还有一个恼人的问题,写给一所不知名的小学,我们会损失多少? Redis 建议在建立新连接时查询新的 master。根据系统配置,这可能意味着大量数据丢失。 如果强制主实例将写入操作复制到至少一个副本实例,有多种方法可以减少损坏程度。请记住,所有 Redis 复制都是异步的,这有其缺点。因此,它必须独立跟踪确认,如果至少一个副本实例没有确认,主实例将停止接受写入。 Redis 集群 
我相信很多人都想过如果你不能将所有数据存储在一台机器的内存中会发生什么。目前,单台服务器可用的最大 RAM 为 24TIB,目前 AWS 在线列出了该值。当然,这很多,但对于某些系统来说这还不够,即使对于缓存层也是如此。 Redis Cluster 允许 Redis 水平扩展。 首先,让我们先了解一些术语;一旦我们决定使用Redis集群,我们就决定将存储的数据分布在不同的机器上,这称为分片。因此集群中的每个Redis实例都被视为整个数据的一个切片。 这就提出了一个新问题。当我们将一个键推送到集群时,我们如何知道哪个 Redis 实例(分片)保存了数据?有多种方法可以做到这一点,但 Redis Cluster 使用算法分片。 为了查找给定密钥的分片,我们将密钥对分片总数取模。然后,使用确定性哈希函数,这意味着某个键总是映射到同一个分片,我们可以推断将来将在哪里读取特定键。 如果我们稍后想向系统添加新剪辑会怎样?这个过程称为重新分片。 假设键 'foo' 之前映射到分片 0,那么在插入新分片后,它可以映射到分片 5。然而,如果我们需要快速扩展系统,移动数据以实现新的分片映射将是缓慢且不切实际的。它还会对 Redis 集群的可用性产生负面影响。 Redis Cluster 针对这个问题设计了一个解决方案,称为哈希槽,所有数据都映射到它上面。有16K个哈希槽。这为我们提供了一种在集群中传播数据的合理方法,当我们添加新分片时,我们只需在系统之间移动哈希槽即可。通过这样做,我们只需将 hashlot 从一个分片移动到另一个分片,并简化向集群添加新主实例的过程。 这可以在不中断且对性能影响最小的情况下实现。让我们通过一个例子来谈谈。 - M1 包含从 0 到 8191 的哈希位置。
- M2 包含从 8192 到 16383 的哈希位置。哈希位置(16K),从而得到 M2 的映射。现在假设我们添加一个新实例 M3。新映射将为:
- M1 包含从 0 到 5460 的哈希槽。
- M2 包含从 5461 到 10922 的哈希槽。
- M3 包含从 10923 到 16383 的哈希槽。
现在必须移动映射到 M2 的 M1 中映射哈希槽的所有键。但是散列槽的各个键的散列不需要移动,因为它们已经被划分到散列槽中。因此,这种程度的误导解决了算法分片的重新分片问题。 Gossiping Protocol Redis 集群使用 gossip 来确定整个集群的健康状况。在上图中,我们有 3 M 个顶点和 3 S 个顶点。所有这些节点都在不断地进行通信,以了解哪些分片可用并准备好服务请求。 如果有足够多的节点认为 M1 没有响应,它们可以决定控制 M1 的副本 S1 以保持集群健康。触发该操作所需的节点数量是可配置的,并且必须正确执行。当分区两侧相等时,如果做错了并且未能打破平局,可能会导致集群分裂。这种现象称为裂脑。作为一般规则,您应该拥有奇数个主设备和两个副本,以实现最稳健的设置。 — 3 — Redis 持久化模型 当我们使用 Redis 时,如果存储此类数据很重要,我们将使用持久化来存储此类数据。 。在许多用例中,如果丢失了存储在 Redis 中的数据,这并不是世界末日。将其用作缓存或支持实时分析的地方,即使发生数据丢失也不是世界末日。 在其他场景中,我们希望在数据持续时间和恢复方面有一些保证。 
无持久性 无持久性:如果需要,您可以完全关闭持久性。这是运行 Redis 的最快方式,并且没有持久性保证。 RDB 文件 RDB(Redis 数据库):RDB 持久性以指定的时间间隔拍摄数据集的时间点快照。 这种机制的主要缺点是快照之间数据会丢失。此外,这种存储机制依赖于主进程的分支,这可能会导致在处理较大数据集中的请求时出现短暂延迟。话虽这么说,RDB 文件在内存中的加载速度比 AOF 快得多。 AOF AOF(仅下载文件):AOF 持久记录从服务器接收到的每个写操作。当服务器开始重建原始数据集时,这些操作会再次执行。 这种持久化方法比 RDB 快照提供更高的持久性,因为它是单个文件。当操作发生时,我们将它们缓冲在日志中,但它们尚未持久化。该日志与我们当前运行的命令一致,因此如果需要可以重播。 然后,如果可能的话,我们使用 fsync 将其刷新到磁盘(如果此运行是可配置的),并且它将持续存在。缺点是格式不紧凑,并且比 RDB 文件使用更多的磁盘。 为什么不两种方式呢? RDB + AOF:AOF 和 RDB 可以组合在同一个 Redis 实例中。如果你愿意的话,用速度换取持久性是一种妥协。我认为这是一种可以接受的设置 Redis 的方式。如果重新启动,请记住,如果两者都启用,Redis 将使用 AOF 来重建数据,因为它是最完整的。 Forking 现在我们了解了持久化的类型,让我们讨论如何在像Redis这样的单线程应用程序中实际实现它。 
在我看来,Redis 最酷的部分是它如何使用分叉和写时复制来有效地促进数据持久化。 分叉是操作系统通过创建自身副本来创建新进程的一种方式。这样,你就获得了一个新的进程ID和一些其他信息以及进程,以便新的fork进程(子进程)可以与原始进程父进程进行通信。 现在事情变得有趣了。 Redis是一个分配大量内存的进程,那么它如何在不耗尽内存的情况下进行复制呢? 当启动一个进程时,父进程和子进程共享内存,并且在子进程中,Redis启动快照(Redis)进程。这是通过称为写时复制的内存共享技术来实现的,该技术在创建分叉时传递对内存的引用。如果子进程保留在磁盘上时没有发生任何更改,则不会进行新的分配。 如果发生更改,内核会保留对每个页面的引用,如果页面有更多更改,则更改会写入新页面。子进程完全不知道变化并且有一致的内存快照。因此,我们可以非常快速有效地获取潜在千兆字节内存的时间点快照,同时仅使用一小部分内存! 来源:Geek Reborn
|
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。