不能用math.abs(hash % nodecount)因取模是静态分片,节点数变化导致90%以上key路由失效;一致性哈希通过哈希环与虚拟节点实现增删节点仅影响局部key,需用sha256/murmurhash3、sorteddictionary建环并正确处理绕环查找与vnode批量增删。

为什么不能用 Math.Abs(hash % nodeCount) 做节点路由
扩容缩容时 90% 以上的 key 会失效,根本没法用。取模本质是静态分片,节点数一变,所有 key 的余数全重算,缓存命中率断崖下跌。一致性哈希要解决的正是这个问题:增减节点只影响邻近一小段 key,其余 key 路由不变。
常见错误是把物理节点直接塞进环、每个节点只算一个哈希值。节点少(比如只有 2–3 台 Redis)时,哈希环上分布极不均匀,大量 key 都挤在某几个区间,导致流量倾斜严重。
- 必须用虚拟节点(vNode),例如每个物理节点映射 100 个
"redis-01#0"、"redis-01#1"… 形式的标识再哈希 - 哈希函数禁用
GetHashCode()或HashCode.Combine()—— 它们跨进程、跨重启不一致,且非加密,碰撞率高 - 推荐用
SHA256(输出转long取低 64 位)或MurmurHash3(有 .NET 移植版),确保稳定可复现
怎么用 SortedDictionary<long string></long> 正确建环
环结构必须支持高效查找“第一个 ≥ keyHash 的节点”,SortedDictionary 的 Keys 是有序的,且 FirstOrDefault(x => x >= keyHash) 底层走的是红黑树遍历,比 List.BinarySearch 更稳——后者要求手动维护排序+处理重复键,出错概率高。
初始化环时,别一次性 AddRange 所有 vNode;应逐个 Add,避免中间态不一致(比如加到一半被并发读取)。环为空时,GetNodeFor 必须抛 InvalidOperationException("Hash ring is empty"),不能返回 null 或默认值,否则调用方无法感知故障。
开箱即用的技能链路由引擎。13 条预定义链覆盖搜索、开发、审查、MLOps、法律、创意等场景,三层路由架构(触发词→SAD反馈→DAG编排),recall@10=96.97%。配置驱动(chains.yaml),零代码扩展。pip install skill-weave-chains 一键安装。
- 键用
long(哈希值截断后),值用节点标识如"redis-01:6379" - 插入前先检查是否已存在相同哈希值(极小概率冲突),避免覆盖
- 查节点逻辑必须包含绕环 fallback:
var node = ring.FirstOrDefault(kvp => kvp.Key >= keyHash); return node.Value ?? ring.First().Value; - 测试时传
"zzzz"这类高哈希字符串,验证是否真能 fallback 到首个节点
删节点时为什么不能只删一个哈希点
每个物理节点对应多个 vNode,比如 "redis-01" 映射了 "redis-01#0" 到 "redis-01#99" 共 100 个哈希点。如果删节点时只删其中一个(比如只删 "redis-01#0" 对应的键),剩下 99 个还在环里,key 依然会路由过去,但目标实例可能已下线,请求直接失败。
正确做法是:维护一份反向映射,例如 ConcurrentDictionary<string hashset>></string>,记录每个物理节点名 → 它所有 vNode 的哈希值集合。删节点时,先查出全部哈希值,再逐个从 SortedDictionary 中 Remove。
- 加节点同理:先生成全部 vNode 哈希值,再逐个
Add,不要批量 - 并发场景下,环读多写少,别用
lock(this),改用ReaderWriterLockSlim,性能差 3 倍以上 - 删除操作完成后,建议触发一次轻量级健康检查(比如 ping 目标地址),确认节点确实不可达再清理本地映射
和 StackExchange.Redis 配合时的关键避坑点
StackExchange.Redis 自带的 KeyHashSlot(CRC16(key) % 16384)不是一致性哈希,它只是 Redis Cluster 固定槽位分片机制,范围太小(仅 0–16383),无法支撑虚拟节点摊平;而且它不解决扩容时的数据迁移问题。如果你用的是单机 Redis 或混合后端(Redis + MemoryCache),就必须自己实现环。
更危险的是:有人试图把 CRC16 结果直接当哈希值塞进自己的环——这会导致所有 key 都挤在环的前 1/1000 区间,完全失去负载均衡意义。
- 若同时支持 Cluster 模式和自建环,必须用策略模式封装:根据连接字符串是否含
cluster-yes或slots字段判断路由模式 - 禁止在运行时混用两种路由逻辑,否则同一个 key 在不同请求中可能打到不同节点
- 生产环境上线前,用真实 key 分布做压力测试,观察各节点 QPS 和内存占用是否落在 ±15% 偏差内










