一致性哈希的核心是HashRing结构,需用虚拟节点、稳定哈希函数(如SHA256)、SortedDictionary实现环,并正确处理绕环查找、增删节点及并发安全。

一致性哈希的核心是 HashRing 结构,不是简单取模
直接用 Math.Abs(hash % nodeCount) 分配缓存节点,扩容缩容时 90% 以上 key 会失效。一致性哈希要让每个节点对应一段连续的哈希环区间,key 落在哪段就找顺时针最近的节点。
- 必须预分配虚拟节点(比如每个物理节点映射 100 个
vNode),否则节点数少时分布严重不均 - 推荐用
SHA256或MurmurHash3(非GetHashCode)——后者易冲突且跨进程不一致 - 环用
SortedDictionary实现,键是哈希值,值是节点标识(如"redis-01:6379")
GetNodeFor 方法必须处理哈希值“绕环”问题
查 key 对应节点时,先算出 keyHash,再在环中找第一个 ≥ keyHash 的节点;如果没找到,就取 ring.Keys.First()(即从环头开始)。漏掉这个逻辑,所有落在最大哈希值之后的 key 都会丢失。
- 别用
List——它对未排序或重复键行为不可靠,.BinarySearch SortedDictionary的FirstOrDefault更稳 - 测试时故意传入
"zzzz"这类高哈希字符串,验证是否能 fallback 到首个节点 - 环为空时必须抛明确异常(如
InvalidOperationException("Hash ring is empty")),不能静默返回 null
删除节点时不能只删一个哈希点,得删全部 vNode
每个物理节点对应多个虚拟节点(比如 "redis-01" → "redis-01#0", "redis-01#1"…),删节点必须遍历清除所有相关键。否则残留的 vNode 会导致流量继续打到已下线节点。
- 建议用
ConcurrentDictionary维护节点到虚拟哈希值的映射,删节点时批量移除> - 加节点同理:先生成新
vNode哈希值,再逐个插入环;避免一次性 AddRange 导致中间态不一致 - 生产环境别用
lock(this)同步环操作——改用ReaderWriterLockSlim,读多写少场景性能差 3 倍以上
和 StackExchange.Redis 配合时,KeyHashSlot 不可替代一致性哈希
Redis Cluster 自带的 KeyHashSlot(CRC16(key) % 16384)是固定 16384 槽位,不解决节点增减时的数据迁移问题。如果你用的是独立 Redis 实例(非 Cluster 模式),或者想跨不同存储后端(Redis + MemoryCache)统一路由逻辑,就必须自己实现环。
- 别试图把
KeyHashSlot值直接塞进你的环——它的范围(0–16383)太小,虚拟节点无法有效摊平 - 若同时支持 Cluster 和自建环,用策略模式封装:根据连接字符串判断模式,避免运行时混用
- 注意 .NET 6+ 的
HashCode.Combine是非加密、非稳定哈希,禁止用于分布式场景
实际最难调的往往是虚拟节点数量和哈希函数选择的组合效果——测 10 万 key 分布时,标准差超过平均值 15%,就得调 vNode 数或换哈希算法。











