Redis 集群是 Redis 的分布式实现,在设计中按重要性顺序具有以下目标:
- 高性能和线性可扩展性,多达 1000 个节点。没有代理,使用异步复制,并且不对值执行合并操作。
- 可接受的写入安全程度:系统尝试(以最大努力)保留来自与大多数主节点连接的客户端的所有写入。通常有一些小窗口,其中确认的写入可能会丢失。当客户端位于少数分区中时,丢失已确认写入的 Windows 会更大。
- 可用性:Redis 集群能够在大多数主节点可访问的分区中幸存下来,并且对于不再可访问的每个主节点,至少有一个可访问的副本。此外,使用副本迁移,不再由任何副本复制的主节点将从多个副本覆盖的主节点接收一个。
本文档中描述的内容在 Redis 3.0 或更高版本中实现
Redis Cluster实现了非分布式版本Redis中所有可用的单键命令。执行复杂的多键操作(如集合并集和交集)的命令用于将操作中涉及的所有键散列到同一槽的情况。
Redis Cluster实现了一个称为哈希标签的概念,可以用来强制将某些密钥存储在同一个哈希槽中。然而,在手动重新装载期间,多键操作可能会在一段时间内不可用,而单键操作始终可用。
Redis群集不支持多个数据库,如独立版本的Redis。我们只支持数据库0;不允许SELECT命令。
在 Redis 集群中,节点负责保存数据, 并获取群集的状态,包括将密钥映射到正确的节点。 群集节点还能够自动发现其他节点,检测不工作 节点,并在需要时按顺序提升副本节点以主节点 以在发生故障时继续运行。
要执行其任务,所有群集节点都使用 TCP 总线和二进制协议,称为 Redis 集群总线。 每个节点都使用群集连接到群集中的每个其他节点 总线。节点使用八卦协议来传播有关集群的信息 为了发现新节点,发送ping数据包以确保所有 其他节点工作正常,并发送群集消息所需的 信号特定条件。集群总线也用于 在整个集群中传播发布/订阅消息并手动编排 用户请求时的故障转移(手动故障转移是故障转移 不是由 Redis 集群故障检测器启动,而是由 直接系统管理员)。
由于群集节点无法代理请求,因此可以使用重定向错误-MOVED和-ASK将客户端重定向到其他节点。理论上,客户机可以自由地向集群中的所有节点发送请求,如果需要,可以进行重定向,因此客户机不需要保持集群的状态。然而,能够缓存键和节点之间的映射的客户端可以以合理的方式提高性能。
Redis 集群使用节点之间的异步复制,上次故障转移胜过隐式合并功能。这意味着最后一个选择的主数据集最终会替换所有其他副本。在分区期间,总是有一个时间窗口可能会丢失写入。但是,对于连接到大多数主节点的客户端和连接到少数主节点的客户端,这些窗口非常不同。
与在少数端执行的写入相比,Redis 集群会更努力地保留由连接到大多数主服务器的客户端执行的写入。 以下是导致已确认丢失的方案示例 故障期间在多数分区中收到的写入:
- 写入操作可能会到达主节点,但虽然主节点可能能够回复客户端,但写入操作可能不会通过主节点和副本节点之间使用的异步复制传播到副本节点。如果主服务器在写操作到达副本的情况下死亡,则当主节点在足够长的时间内无法访问以提升其副本之一时,写操作将永远丢失。在主节点完全突然发生故障的情况下,这通常很难观察到,因为主节点试图几乎同时回复客户端(确认写入)和副本(传播写入)。然而,这是一种现实世界的故障模式。
- 理论上可能的写入丢失的故障模式如下:
- 由于分区,无法访问主节点。
- 它被其中一个副本故障转移。
- 一段时间后,它可能会再次访问。
- 具有过期路由表的客户端可以在集群将其转换为(新主节点)副本之前写入旧主节点。
第二种故障模式不太可能发生,因为主节点无法与大多数其他主节点通信足够长的时间进行故障转移,将不再接受写入,并且当分区固定时,写入仍会被拒绝一小段时间,以允许其他节点通知配置更改。此故障模式还要求客户端的路由表尚未更新。
针对分区少数侧的写入具有更大的丢失窗口。例如,Redis Cluster 在只有少数主节点和至少一个或多个客户端的分区上丢失大量写入操作,因为如果主节点在多数端进行故障转移,则发送到主服务器的所有写入操作都可能会丢失。
具体来说,对于要进行故障转移的主机,大多数主机必须至少在NODE_TIMEOUT内无法访问它,因此如果在该时间之前分区已修复,则不会丢失任何写入。当分区持续时间超过NODE_TIMEOUT时,在少数方执行的所有写入操作都可能丢失。然而,当NODE_TIMEOUT时间过去后,Redis群集的少数方将开始拒绝写入,而不会与多数方接触,因此有一个最大窗口,在该窗口之后,少数方将不再可用。因此,在此时间之后,不会接受或丢失任何写入。
具体来说,对于要进行故障转移的主机,大多数主机必须至少在NODE_TIMEOUT内无法访问它,因此如果在该时间之前分区已修复,则不会丢失任何写入。当分区持续时间超过NODE_TIMEOUT时,在少数方执行的所有写入操作都可能丢失。然而,当NODE_TIMEOUT时间过去后,Redis群集的少数方将开始拒绝写入,而不会与多数方接触,因此有一个最大窗口,在该窗口之后,少数方将不再可用。因此,在此时间之后,不会接受或丢失任何写入。
Redis群集在分区的少数部分不可用。在分区的多数侧,假设至少有大多数主机和每个不可访问的主机的副本,则在NODE_TIMEOUT时间加上副本选择和故障切换其主机所需的几秒后,群集将再次可用(故障切换通常在1或2秒内执行)。
这意味着Redis群集的设计是为了在集群中的几个节点发生故障时能够生存下来,但对于需要在发生大规模网络拆分时可用性的应用程序来说,它不是一个合适的解决方案。
在由N个主节点组成的集群的示例中,其中每个节点都具有单个副本,并且当两个节点被分割开时,将以1-(1/(N*2-1))的概率保持可用(在第一个节点发生故障之后,我们总共剩下N*2-1个节点,唯一没有副本的主节点发生故障的概率为1/(N*2-1))。
例如,在一个具有5个节点和每个节点一个副本的集群中,有1/(5*2-1)=11.11%的概率,即在将两个节点从大多数节点分割后,该集群将不再可用。
由于Redis群集的一个称为副本迁移的功能,副本迁移到孤立的主机(主机不再具有副本)这一事实在许多现实场景中提高了群集的可用性。因此,在每次成功的失败事件中,集群都可以重新配置副本布局,以便更好地抵御下一次失败。
在 Redis 中,集群节点不会将命令代理给负责给定密钥的正确节点,而是将客户端重定向到为密钥空间的给定部分提供服务的正确节点。
最终,客户端会获得群集的最新表示形式,以及哪个节点为哪个密钥子集提供服务,因此在正常操作期间,客户端会直接联系正确的节点以发送给定的命令。
由于使用了异步复制,节点不会等待其他节点的写入确认(如果未使用 WAIT 命令显式请求)。
此外,由于多键命令仅限于近键,因此除非重新分片,否则数据永远不会在节点之间移动。
正常操作的处理方式与单个 Redis 实例的处理方式完全相同。这意味着,在具有 N 个主节点的 Redis 集群中,随着设计线性扩展,您可以期望获得与单个 Redis 实例乘以 N 相同的性能。同时,查询通常在单个往返中执行,因为客户端通常保留与节点的持久连接,因此延迟数字也与单个独立 Redis 节点的情况相同。
非常高的性能和可扩展性,同时保留弱但 合理形式的数据安全性和可用性是 Redis 集群
Redis 集群设计避免了多个节点中同一键值对的冲突版本,因为在 Redis 数据模型的情况下,这并不总是可取的。Redis 中的值通常非常大;通常会看到包含数百万个元素的列表或排序集。此外,数据类型在语义上也很复杂。传输和合并这些类型的值可能是一个主要瓶颈和/或可能需要应用程序端逻辑的不平凡参与、用于存储元数据的额外内存等。
这里没有严格的技术限制。CRDT 或同步复制 状态机可以对类似于 Redis 的复杂数据类型进行建模。然而, 此类系统的实际运行时行为与 Redis 集群不同。 Redis 集群旨在涵盖 非集群 Redis 版本。
在 Redis 集群中,节点负责保存数据, 并获取群集的状态,包括将密钥映射到正确的节点。 群集节点还能够自动发现其他节点,检测不工作 节点,并在需要时按顺序提升副本节点以主节点 以在发生故障时继续运行。
要执行其任务,所有群集节点都使用 TCP 总线和二进制协议,称为 Redis 集群总线。 每个节点都使用群集连接到群集中的每个其他节点 总线。节点使用八卦协议来传播有关集群的信息 为了发现新节点,发送ping数据包以确保所有 其他节点工作正常,并发送群集消息所需的 信号特定条件。集群总线也用于 在整个集群中传播发布/订阅消息并手动编排 用户请求时的故障转移(手动故障转移是故障转移 不是由 Redis 集群故障检测器启动,而是由 直接系统管理员)。
用于将密钥映射到哈希槽的基本算法如下(请阅读下一段,了解该规则的哈希标记例外情况):
CRC16的规定如下:
- 名称:XMODEM(也称为ZMODEM或CRC-16 / ACORN)
- 宽度:16位
- 多边形:1021(实际上是 x^16 + x^12 + x^5 + 1)
- 初始化:0000
- 反射输入字节:假
- 反射输出 CRC:假
- 输出 CRC 的异或常数:0000
- “”的输出:31C3
使用了 14 个 CRC16 输出位中的 16 个(这就是为什么有 上式中的模 16384 运算)。
在我们的测试中,CRC16在分配不同种类的 键均匀地跨 16384 插槽。
注意:本文档的附录A中提供了所用CRC16算法的参考实现。
集群中的每个节点都有一个唯一的名称。节点名是一个160位随机数的十六进制表示,在节点首次启动时获得(通常使用/dev/urandom)。节点将将其ID保存在节点配置文件中,并将永远使用相同的ID,或者至少在系统管理员未删除节点配置文件,或者通过CLUSTER reset命令请求硬重置的情况下使用相同ID。
节点 ID 用于标识整个群集中的每个节点。 给定节点无需任何需要即可更改其 IP 地址 以同时更改节点 ID。群集还能够检测到更改 在 IP/端口中,并使用在集群上运行的 gossip 协议重新配置 总线。
节点 ID 不是与每个节点关联的唯一信息,而是 唯一始终全局一致的。每个节点还具有 以下一组关联的信息。一些信息是关于 此特定节点的群集配置详细信息,并最终 在整个集群中保持一致。其他一些信息,例如上次 一个节点被 ping 到,而是每个节点的本地节点。
每个节点都维护关于它在集群中知道的其他节点的以下信息:节点ID、节点的IP和端口、一组标志、如果节点被标记为副本,则节点的主节点是什么、上次ping节点的时间和上次接收到pong的时间、节点的当前配置时期(本规范稍后解释)、,链接状态以及最后服务的哈希槽集。
CLUSTER NODES命令可以发送到群集中的任何节点,并根据查询节点具有的群集本地视图提供群集的状态和每个节点的信息。
以下是发送到主服务器的
群集节点命令的示例输出 节点在包含三个节点的小集群中。
在上面的列表中,不同的字段按顺序排列:节点ID,地址:端口,标志,上次发送的ping,收到的最后一个pong,配置纪元,链路状态,插槽。有关上述字段的详细信息将在我们讨论 Redis 集群的特定部分时立即介绍。
每个 Redis 集群节点都有一个额外的 TCP 端口用于接收 来自其他 Redis 集群节点的传入连接。此端口将通过向数据端口添加 10000 来派生,也可以使用群集端口配置指定。
示例 1:
如果 Redis 节点正在侦听端口 6379 上的客户端连接, 并且您没有在 redis.conf 中添加集群端口参数, 将打开群集总线端口 16379。
示例 2:
如果 Redis 节点正在侦听端口 6379 上的客户端连接, 并在 redis.conf 中设置集群端口 20000, 将打开群集总线端口 20000。
节点到节点的通信只使用集群总线和集群总线协议:一种由不同类型和大小的帧组成的二进制协议。群集总线二进制协议没有公开记录,因为外部软件设备不打算使用该协议与Redis群集节点进行通信。但是,您可以通过阅读Redis Cluster源代码中的Cluster.h和Cluster.c文件来获得有关Cluster总线协议的更多详细信息。
Redis 集群是一个完整的网格,其中每个节点都使用 TCP 连接与其他节点连接。
在由 N 个节点组成的群集中,每个节点都有 N-1 个传出 TCP 连接和 N-1 个传入连接。
这些 TCP 连接始终保持活动状态,而不是按需创建。 当节点期望 pong 回复以响应集群总线中的 ping 时,在等待足够长的时间以将节点标记为无法访问之前,它将尝试 通过从头开始重新连接来刷新与节点的连接。
虽然 Redis 集群节点形成一个完整的网格,但
节点使用 gossip 协议和 配置更新机制,以避免交换太多 正常情况下节点之间的消息,所以消息的数量 交换不是指数级的。
节点始终接受集群总线端口上的连接,甚至回复 收到时 ping,即使 ping 节点不受信任。 但是,如果 发送节点不被视为群集的一部分。
一个节点将仅以两种方式接受另一个节点作为群集的一部分:
- 如果节点向自己显示一条MEET消息(CLUSTER MEET命令)。meet消息与PING消息完全相同,但会强制接收方接受节点作为集群的一部分。只有当系统管理员通过以下命令请求时,节点才会向其他节点发送MEET消息:CLUSTER MEET ip port
- 如果一个已经受信任的节点会八卦另一个节点,那么该节点也会将另一个结点注册为集群的一部分。因此,如果A知道B,B知道C,最终B会向A发送关于C的八卦消息。当这种情况发生时,A会将C注册为网络的一部分,并尝试与C连接。
这意味着只要我们加入任何连接的图中的节点,它们最终将自动形成一个完全连接的图。这意味着群集能够自动发现其他节点,但前提是存在系统管理员强制的受信任关系。
此机制使集群更加健壮,但可防止不同的 Redis 集群在更改 IP 地址或其他网络相关事件后意外混合。
Redis客户端可以免费向集群中的每个节点发送查询,包括副本节点。节点将分析查询,如果它是可接受的(即,查询中只提到一个密钥,或者提到的多个密钥都属于同一个哈希槽),它将查找哪个节点负责密钥所属的哈希槽。
如果哈希槽由节点提供服务,则简单地处理查询,否则节点将检查其内部哈希槽到节点的映射,并用MOVED错误回复客户端,如以下示例所示:
错误包括密钥的哈希槽(3999)和可以为查询服务的实例的endpoint:port。客户端需要向指定节点的端点地址和端口重新发出查询。端点可以是IP地址、主机名,也可以是空的(例如-MOVED 3999:6380)。空端点表示服务器节点具有未知端点,客户端应将下一个请求发送到与当前请求相同的端点,但具有提供的端口。
请注意,即使客户机在重新发出查询之前等待了很长时间,同时集群配置发生了变化,如果哈希槽3999现在由另一个节点提供服务,则目标节点将再次回复MOVED错误。如果联系的节点没有更新的信息,也会发生同样的情况。
因此,从集群节点由ID标识的角度来看,我们试图简化与客户机的接口,只需暴露哈希槽和由端点:端口对标识的Redis节点之间的映射。
客户端不需要,但应该尝试记住哈希槽3999由127.0.0.1:6381提供。这样,一旦需要发出新命令,它就可以计算目标密钥的哈希槽,并有更大的机会选择正确的节点。
另一种方法是在收到MOVED重定向时,使用cluster SHARDS或不推荐使用的cluster SLOTS命令刷新整个客户端集群布局。当遇到重定向时,很可能重新配置了多个插槽,而不是一个插槽,因此尽快更新客户端配置通常是最佳策略。
注意,当集群稳定时(配置中没有持续变化),最终所有客户端都将获得哈希槽->节点
要创建集群,首先需要在集群模式下运行几个空的Redis实例。
至少在redis.conf文件中设置以下指令:
/code>
节点 ID
。
添加一个空节点
。
在终端应用程序中创建新选项卡。
输入群集测试目录。
创建名为7006的目录。
在内部创建redis.conf文件,与其他节点使用的文件类似,但使用7006作为端口号。
最后用..启动服务器/redis服务器/redis.conf文件
redis-cli
来将节点添加到 现有群集。
如您所见,我使用了 add-node 命令指定 新节点作为第一个参数,以及 聚类作为第二个参数。
实际上,这里的redis-cli对我们帮助很小,它只是 向节点发送了 CLUSTER MEET 消息,这也是可能的 以手动完成。但是,redis-cli 也会检查 集群之前运行,所以最好先执行集群操作 始终通过 Redis-CLI 即使您知道内部结构的工作原理。
现在我们可以连接到新节点,看看它是否真的加入了集群:
可以通过两种方式添加新复制副本。显而易见的是 再次使用 Redis-cli,但使用 --cluster-slave 选项,如下所示:
要删除副本节点,只需使用redis-cli的del node命令:
第一个参数只是集群中的一个随机节点,第二个参数 是要删除的节点的 ID。
您也可以以相同的方式删除主节点,但是为了 删除主节点,它必须为空。如果主节点不为空,则需要 将数据从它重新分片到之前的所有其他主节点。
官网:Scaling with Redis Cluster | Redis
到此这篇fastdfs架构(fastdfs集群搭建原理)的文章就介绍到这了,更多相关内容请继续浏览下面的相关推荐文章,希望大家都能在编程的领域有一番成就!
版权声明:
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若内容造成侵权、违法违规、事实不符,请将相关资料发送至xkadmin@xkablog.com进行投诉反馈,一经查实,立即处理!
转载请注明出处,原文链接:https://www.xkablog.com/kjbd-jg/64492.html