Orleans框架源码笔记:一致性哈希环
一致性哈希、哈希环、虚拟节点、Silo、Grain
一、理解服务端(Grain、Silo)与客户端分布、通信交互
1.1、物理节点与 Grain 层次架构图
1.2、Grain 分布与通信细节图
二、一致性哈希(UniformHash)
哈希值是uint类型,取值范围为 0 到 4,294,967,295(即 2^32 - 1)。
IdSpan提供了比较、哈希和字符串转换方法,用于GrainId和GrainType的哈希值,Grain 均匀分配到不同 Silo 节点。
有两种算法XxHash32、JenkinsHash,XxHash32性能优于JenkinsHash。
2.1、XxHash32
概述:XxHash 是由 Yann Collet 开发的高性能非加密哈希算法,旨在提供比传统哈希(如 CRC32、MD5)更快的计算速度和更好的抗碰撞性。其中,XxHash32 是针对 32 位平台优化的版本,输出 32 位哈希值,常用于数据校验、哈希表构建、数据分桶等场景。
基于现代 CPU 特性优化(如 SIMD 指令),处理速度可达 5-10 GB/s(取决于硬件),适合高频调用的 Grain 路由场景。
应用场景:Grain 路由与负载均衡、流处理系统(Stream)。
2.1.1、Grain 路由与负载均衡
GrainId\GrainType\IdSpan三者关系:
GrainId=>GrainType+IdSpan;GrainType=>IdSpan
IdSpan的哈希值计算用XxHash32(非加密哈希算法):计算速度和更好的抗碰撞性。 XxHash32是一种生成 32 位哈希值的算法,其结果恰好可以用 C# 的uint类型取值范围。
为了跨平台数据(不同硬件架构、操作系统环境)一致性, XxHash32 哈希结果时考虑大小端(Endianness)问题;否则 同一Grain在不同节点上计算的哈希值不同,无法路由到正确的 Silo节点。
具体代码:
public static unsafe uint ComputeHash(ReadOnlySpan<byte> data)
{
uint hash;
XxHash32.TryHash(data, new Span<byte>((byte*)&hash, sizeof(uint)), out _);
return BitConverter.IsLittleEndian ? hash : BinaryPrimitives.ReverseEndianness(hash);
}
2.1.2、流处理系统(Stream)
2.2、JenkinsHash
纯软件实现,采用逐字节处理,无法利用硬件并行性。早期版本的 Orleans 使用 JenkinsHash 作为默认算法,向后兼容性仍保留。
应用场景:成员表管理(MembershipTableManager)、系统目标路由(SystemTarget)
2.2.1、成员表管理(MembershipTableManager)
Silo 地址哈希。
Gossip 协议中的状态同步。
2.2.2、系统目标路由(SystemTarget)
内部组件寻址:为系统内部组件(如 MembershipSystemTarget
、GatewaySystemTarget
)生成唯一 Grain ID。
系统消息路由:将系统消息(如心跳、负载信息)路由至正确的目标 Silo。
三、哈希环
3.1、物理 Silo 、虚拟节点、哈希环之间交互图
物理 Silo:SiloAddress
虚拟节点:VirtualBucketsRingProvider
哈希环:IRingRange
3.2、虚拟节点哈希值计算,以及如何划分哈希环
虚拟节点哈希值计算:是根据其对的Silo地址(SiloAddress)哈希+虚拟节点索引计算的哈希值。
如:新Silo加入时,根据每个Silo虚拟节点数量的配置(numBucketsPerSilo),计算它所有虚拟节点的哈希值,如:
3.3、虚拟节点:VirtualBucketsRingProvider
它负责管理当前Silo节点(SiloAddress)的虚拟节点对应哈希环范围,同时包含集群中所有虚拟节点和Silo关系。
Silo增加和移除:
监控指标:
一致性哈希环(IConsistentRingProvider)还有一个实现方式是ConsistentRingProvider:它直接使用 Silo 地址进行哈希,适用于对负载均衡要求不高、Silo 数量较少的场景,或者对性能要求较高,不希望引入过多虚拟桶带来的额外开销的场景。根据配置启用不同实现。
3.4、哈希环:IRingRange
涉及接口\类:IRingRange\IRingRangeInternal\ISingleRange、SingleRange\GeneralMultiRange。
- IRingRange 是最基础的接口,定义了检查值是否在范围内的方法。
- IRingRangeInternal 继承自 IRingRange,并增加了计算范围百分比的方法。
- ISingleRange 继承自 IRingRange,定义了单一连续范围的起始和结束边界。
- SingleRange 类实现了 IRingRangeInternal 和 ISingleRange 接口,是单一连续范围的具体实现。
- GeneralMultiRange 类实现了 IRingRangeInternal 接口,用于表示多个连续范围的集合。
RangeFactory工厂类,创建SingleRange或者GeneralMultiRange。GeneralMultiRange创建时,如果多个范围中有相邻虚拟节点会合并,与VirtualBucketsRingProvider中移除Silo后重新计算哈希环相对应。
3.5、物理 Silo:SiloAddress
用于封装 Silo(Orleans 集群中的节点)的地址信息。
Endpoint:类型为 IPEndPoint,表示 Silo 的网络端点,包含 IP 地址和端口号。
Generation:类型为 int,表示 Silo 的生成号,用于区分不同版本或重启后的 Silo。
更多推荐
所有评论(0)