分区副本和分区缓存拓扑
在集群中,如果所有服务器节点都具有相同的数据副本,则该数据具有高可用性。 这意味着集群可以承受一些节点故障而不会丢失任何数据。 然而,这并没有给你带来可扩展性。 当数据开始大量增长时,设计需要减少复制范围并开始对数据进行分区。
分区意味着您需要将数据分布在多个节点之间,以便分布式读取和写入数据加载。 随着数据的增长,您可以在集群中添加更多服务器节点来容纳更多数据。 集群中的每个服务器节点称为一个分区。
通过对数据进行分区,您可以实现可扩展性,但现在的问题是数据如何分区? 一个简单的解决方案可能是以循环方式将数据分配到分区,但是一旦将其添加到存储中,我们如何找到特定的数据呢?
通过循环,我们将失去跟踪数据位置的能力。 我们需要一种更好的数据分布方式,不仅要保证数据的均匀分布,还要保证快速查找的能力。
备注
分区拓扑也支持 NCache Professional.
备注
Partitioned 和 Partition-Replica 拓扑之间的唯一区别是前者没有副本缓存,这使得它容易丢失数据。
分区缓存的基于哈希的数据分区
NCache 将数据分为多个块并将这些块放置在不同的分区中。 这些块称为桶。 总共有 1000 个桶,在集群中的节点之间平均分配。 这里的想法是对项目的键应用哈希函数,并通过总存储桶数量(本例中为 1000)对其进行建模,以获得该数据的所有者存储桶。
分布图
集群中的协调器服务器有责任生成包含桶分布的映射。 这张图称为分布图。 协调器服务器与集群中的其余分区以及连接的客户端共享此分布图。 无论集群中的服务器数量如何,此方法始终为您提供相同的项目存储桶地址。 尽管存储桶可能在任何阶段从一个分区移动到另一个分区,但项目的存储桶永远不会改变。 这意味着,当桶移动时,它会带走所有数据。
根据分布图分布数据
当您启动具有单个分区的缓存集群时,所有 1000 个存储桶都分配给该节点。 这意味着所有数据都进入该分区。 当您在集群中启动另一个节点时,桶会平均分布在两个分区之间,每个分区有 500 个桶。 同样,在向集群添加第三个节点时,存储桶再次 redis致敬。 在这种情况下,三个节点将分别拥有 333、333 和 334 个桶。
类似地,当分区离开集群时,桶分布也会发生变化。 例如,当某个分区离开三节点集群时,该分区拥有的 333 或 334 个桶分别为 redis其余两个节点之间的贡献。 每当分布发生变化时,它就会触发状态传输,根据桶分布重新平衡节点之间的数据。
数据的随机分布
这种分区方法为您提供了相当大的随机性,以确保数据在存储桶和分区之间均匀分区。 但是,使用这种分区方法,您将失去对应将哪些数据分配给哪个分区的控制。 大多数情况下,您不会关心数据的去向。 但是,在某些情况下,您可能希望相关数据位于同一位置。 为此,您可以使用位置关联性,其中哈希函数应用于密钥的某些部分而不是整个密钥。
数据的平衡分布
每当桶是 redis在节点之间致敬, NCache 确保桶是 redis以这样的方式提供:每个分区接收的数据大小几乎相同。 每个分区以可配置的时间间隔与集群中的其他分区共享其拥有的存储桶的统计信息。 这有助于在需要时生成平衡的分布图,这对于每个分区获取的数据来说是公平的。 平衡基于数据的大小而不是项目的数量。 这种平衡通常在存储桶时得到保证 redis由于节点离开或加入而产生的贡献。
自动和手动数据负载平衡
但是,您可能会发现集群中的一个或多个分区是倾斜的,并且接收的负载比其他分区多。 在这种情况下,您可以选择手动平衡特定节点的数据,以确保该节点上的数据等于每个分区接收的平均数据大小。 然后还有一个称为“自动数据负载平衡”的功能,可以在后台自动完成这项工作。 该功能默认是关闭的,因为如果不小心使用会导致频繁的bucket redis归因,因此,分区之间不需要的状态转移。
每个分区的数据大小
每个分区可以容纳的数据大小等于配置的缓存大小。 例如,如果配置的缓存大小为2GB,集群大小为三个分区,则该集群上的缓存大小总量为6GB。
因此,通过这种拓扑,您不仅可以在服务器之间分配读写负载,还可以通过添加到集群中的每台新服务器来增加容量。
分区副本
现在我们已经介绍了分区副本拓扑如何扩展事务负载和存储容量。 让我们谈谈它如何处理高可用性。 集群中的每个节点都有另一个分区的备份,该分区充当称为副本的被动分区。 在节点故障的情况下,缓存集群知道丢失分区所拥有的数据在其副本中仍然可用。 因此,客户端应用程序继续平稳运行,因为丢失分区拥有的数据仍由集群通过此副本提供服务。
客户端应用程序仅与活动分区直接通信。 然后每个分区负责将其数据复制到其各自的副本。
即使此拓扑中的复制程度不如您在 复制拓扑,拥有一个备份至少可以确保您在节点发生故障时,您的数据仍然安全。 只要不存在同时发生的节点故障,该拓扑中的数据就是安全的,涵盖了大部分场景。
每个集群节点都有一个活动和一个副本,并且活动和副本实例都存在于每个集群节点上的同一个缓存进程中。
由于每个缓存节点上都存在副本实例,因此它需要与主缓存实例相同的内存大小。 这意味着每个分区副本缓存节点都需要针对其配置的缓存大小的双倍内存。
所有客户端添加的数据都存储在活动节点中,然后从活动节点复制到其专用副本,该副本位于集群中的某个其他节点上。 这种副本节点的安排确保了当活动节点出现故障时数据不会丢失。
副本选择策略
NCache 根据节点加入缓存集群的顺序自动选择副本节点。 第一个节点的副本出现在第一个节点之后加入集群的服务器节点上,依此类推。 并且,最后一个节点的副本被放置在缓存集群的第一个服务器节点(协调服务器)上。
这整个副本选择过程是自动的。 每当服务器节点离开缓存集群或新节点加入缓存集群时,副本也会根据更新后的成员映射重新分配。
单节点内存消耗
每个服务器节点(活动和副本)都会记录配置的缓存大小,并确保存储的数据永远不会超过指定的内存限制。 有两种特殊情况,此内存限制检查的工作方式不同。 它们解释如下:
- 只有一个节点处于运行状态,并且正在向其中添加数据。 活动缓存实例可以使用指定缓存大小的两倍来保存数据,因为其副本没有用处。
- 在多节点集群中,当所有其他节点离开集群并且只有一个节点保持活动状态时,其副本缓存实例中的数据将传输到活动缓存实例。 来自副本的空闲内存然后被活动缓存消耗以容纳从副本接收的数据。
复制策略
Partition-Replica 拓扑有两种复制策略将数据从活动服务器节点复制到副本节点:
异步复制: 在此模式下,后台队列用于复制数据,而不会阻塞客户端操作。 每个写入操作都会排队,专用后台线程从该队列中分块选取数据并将其复制到副本实例。 此复制策略适合经常进行写入但不希望在下一次缓存操作之前等待复制完成的应用程序。 但是,如果节点突然离开,则可能会丢失数据。 在这种情况下,未复制的排队操作将会丢失。
同步复制: 使用同步复制模式,来自客户端的每个写入操作都会在将控制权返回给客户端应用程序之前复制到副本。 这种复制模式可确保活动缓存实例和副本缓存实例具有相同的用户数据副本。 如果副本实例上的复制失败,则会从活动缓存实例和副本缓存实例中删除该项目。
操作行为
驱逐, 期满, 依赖, 直写/后写等由活动节点控制。 每当一个活动节点根据任何提到的特性从中删除一个项目时,它都会将它复制到它的副本以从中删除以前存储的数据。 相似地, 直写/后写 操作仅从活动缓存中执行。
在分区副本拓扑中,客户端直接与每个服务器节点连接,但仅与其活动分区/实例连接。 尽管如此,在某些情况下,客户端会通过集群调用临时与副本实例进行交互。 它们的解释如下:
- 在状态转移期间,当节点离开集群时,将从其副本提供针对离开节点的客户端操作。
- 当集群处于维护模式时,维护期间针对受维护节点的所有操作均由其副本提供。
状态转移
状态传输是在缓存节点之间自动传输/复制数据的过程。 当新节点加入集群或任何当前节点离开集群时触发状态转移。 节点离开/加入也会导致集群中的成员资格发生变化。
当一个节点收到更新的 分布图,它验证本地环境中存储桶(分配给它的)是否存在。 节点本地环境中不存在的分配的桶会从其他节点一一拉取。 因此,根据缓存集群中服务器节点的数量,在状态传输期间会传输多个桶。
在以下三种主要场景中触发状态转移:
节点加入
当有新节点加入缓存集群时,协调服务器会生成一个新的分布图,将桶从当前节点分发到新加入的节点。 并且,新加入的节点在收到分布图后,从当前节点中拉取桶。 在此状态转移期间,新加入的节点一次拉一个桶。 在收到一个桶后,它会拉下一个桶,依此类推,直到它根据其分布图从其他节点获取所有分配的桶。
节点离开
类似地,当缓存节点离开缓存集群时会触发状态转移。 协调服务器 redis在集群的活动节点中贡献它的桶。 在这种情况下,活动节点从离开节点的副本中提取数据。
备注
如果多个节点同时或一个接一个离开集群,而状态转移已经在进行中,可能会导致数据丢失
关于自动数据负载平衡
Partition-Replica 拓扑有一个特点: 自动数据负载平衡 它持续监控集群节点之间的数据分布。 并且,如果数据分布不在预期的分布范围内(60%到40%),它会自动触发自动数据负载平衡。 在这种情况下,协调服务器重新生成一个新的分布图并 redis以所有集群节点将具有相同大小的数据的方式向存储桶致敬。
备注
也可以进行数据负载均衡 手动 来自 NCache 管理中心。
无论状态转移的原因是什么,整个过程都是自动且无缝的。 而且,在状态转移期间,特别是当服务器节点离开缓存集群时,所有原本用于离开节点的客户端操作都通过集群操作从其副本提供服务。
副本也像其他活动节点一样从其活动节点执行状态传输。 副本从其活动节点拉出分配的存储桶,以在状态传输时获取数据副本。 然而,这种状态转移仅在存储桶重新分配时发生。 否则,数据将通过复制机制复制到副本。
监控状态传输的不同方法
NCache 提供多种方式来监控缓存集群中的状态传输。 它们解释如下:
- 缓存日志:每当状态传输被触发和停止时,都会记录在集群的缓存日志中。缓存日志存在于 %NCHOME%/bin/日志 文件夹中。
- 自定义计数器: NCache 还发布了可在 Windows 和 Linux 上查看的自定义计数器。
- 基于 Perfmon 的计数器: 在Windows上, NCache 还通过 Windows Perfmon 工具发布状态转移计数器。
- Windows 事件日志: 与状态传输相关的信息/事件也发布在 Windows 事件日志上。
- 电子邮件提醒: 状态转移特定的电子邮件警报可以在其启动和停止时进行配置。
客户端连接
如分区中所述,数据分布在集群中的所有服务器之间。 与其他拓扑不同,分区拓扑的客户端需要连接所有分区,其中每个分区包含总数据的一个子集。
客户端在连接调用上收到一个分布图,该分布图告知客户端正在运行的服务器节点及其 基于散列的分布。 客户端连接所有服务器节点以从缓存中获取完整数据。 客户得到一个 更新地图 在每个集群成员更改时保持连接。 客户端还会收到关于成员离开/加入的通知,并根据收到的信息重置连接 地图.
客户端根据 基于散列的分布图 它接收。 对于密钥未知的所有操作,例如 SQL 搜索, 获取标签等等,客户端将请求广播到所有服务器节点并组合它们各自的响应。
在任何情况下,如果客户端无法连接到集群的任何服务器节点,并不意味着它无法从该服务器节点写入和检索信息。 为此,它使用它所连接的其他服务器节点,这些节点代表它请求无法访问的服务器节点执行操作。 例如,如果客户端无法与 node1 连接并想要获取驻留在 node1 中的密钥,它会将请求发送到 node2,它重新路由到 node1 并返回响应。
维护模式
当需要修补或升级硬件/软件时 NCache 服务器,您可能不会遇到应用程序停机。 但是,停止缓存节点会触发 状态转移 在整个缓存集群内导致过度使用网络、CPU 和内存等资源。 这个 状态转移 根据缓存数据和集群的大小,该过程可能会很昂贵。 典型的升级工作流程涉及一次重新启动缓存节点,这需要两次状态转移,一次在节点离开时,另一次在节点加入时。
维护模式 引入它是为了避免在缓存服务器维护期间发生这些昂贵的状态传输。 一旦缓存服务器因维护而停止指定时间,正在维护的节点的副本将暂时变为活动状态并开始处理客户端请求。 当维护中的节点在指定时间内维护结束重新加入时, 状态转移 为该节点启动以将其与缓存集群同步。
集群退出 维护模式 在三个不同的州。 如果维护节点在指定时间内加入缓存集群, 状态转移 发起同步集群状态,集群退出 维护模式。 如果维护节点未能在指定时间内重新加入缓存集群,则集群认为该节点宕机,退出 维护模式, 生成一个新的 地图,并开始 状态转移. 除了成功和失败之外,还有一个异常退出 维护模式,即当一个节点离开时。 如果集群位于 维护模式 并且除维护节点之外的任何节点离开,集群退出 维护模式,并且可能导致数据丢失。
脑裂恢复
期限 裂脑 指一个缓存集群分裂成多个子集群的状态。 集群中的缓存服务器通过 TCP 进行通信。 因此,任何网络故障或问题都可能导致集群中存在的服务器之间的通信丢失。 如果服务器之间的通信丢失超过一定时间,则成员映射将根据服务器之间的连接性而改变。 这导致形成多个子集群。 这些子集群称为拆分。 我们称之为 脑裂 由于子集群无法相互交流,类似于在裂脑综合征中大脑的一半无法相互交流。
所有子集群都是健康的并处理它们包含的数据。 此外,客户端可以连接到这些子集群以进行进一步的读/写操作。 客户端从集群服务器接收成员映射以更新连接。 在这里,客户端可以根据收到的第一个地图连接到任何子集群。
脑裂 仅当服务器之间的通信恢复时才检测到,并且发现所有服务器都已启动并正在运行,但不是单个集群的一部分。 根据服务器之间的通信丢失,可以进行两个或多个拆分。 一次 脑裂 检测到,恢复过程启动。 所有的分裂一个一个地恢复,直到所有的子集群合并。
脑裂 恢复过程在检测后立即启动。 它需要两个健康的分片,识别它们的协调服务器,根据集群大小决定赢家和输家分片,获取失败者分片上的锁以限制该集群上的客户端活动,以及集群成员资格更改。 此后,所有客户端将被重定向到获胜者集群分片,而失败者分片的所有节点将一一重新启动以加入获胜者集群。 所有失败者分裂以相同的方式与获胜者集群分裂合并,并且集群再次变得健康。
预计数据丢失 脑裂 当集群分裂成多个子集群时,由于集群中的多个节点同时离开,会发生数据丢失。 子集群可以在以下状态下处理客户端请求 脑裂,如果客户端连接的split是loser split,重新启动加入主集群,这些操作可能会丢失。