取模只是轮询的最终映射步骤,必须配合原子计数(如atomic.AddUint64)与健康节点快照(深拷贝或读锁),才能避免竞态、越界和panic;节点为空须提前返回错误,加权场景需用平滑加权轮询(SWRR)而非简单取模,哈希取模适用于key稳定的粘滞路由。

取模只是最后一步,不能单独用
直接写 index = counter % len(nodes) 看似轮询,但并发下 counter++ 会竞态——多个 goroutine 同时读、改、写同一个变量,结果错乱。必须用原子操作保序。
- 用
sync/atomic.AddUint64(&counter, 1)替代普通自增 - 取模前先读当前节点列表(建议深拷贝或加读锁),避免节点动态增删导致索引越界
- 节点为空时提前返回错误,别让取模运算在空切片上 panic
节点列表要“活”起来,不能硬编码
很多实现把 nodes 写成全局常量切片,但线上服务常需动态上下线节点。如果只维护一个计数器,而节点列表变了,取模结果就可能指向不存在的地址。
开箱即用的技能链路由引擎。13 条预定义链覆盖搜索、开发、审查、MLOps、法律、创意等场景,三层路由架构(触发词→SAD反馈→DAG编排),recall@10=96.97%。配置驱动(chains.yaml),零代码扩展。pip install skill-weave-chains 一键安装。
- 每次选节点前,先获取当前可用节点的快照:比如
nodes := getActiveNodes() - 快照应是不可变副本(如
append([]string{}, original...)),避免后续修改影响本次路由 - 若节点数为 0,立即返回 error,不往下执行取模
权重场景下,取模不等于轮询
如果节点性能不同(比如一台 32C,一台 8C),单纯取模会让强弱节点被调用次数一样,造成资源浪费或瓶颈。这时取模无法表达“能者多劳”。
- 加权轮询要用平滑加权轮询(SWRR)算法,靠累积权重+最大权重比较来调度
- 简单加权取模(如按权重重复填充节点列表再取模)会导致高权重节点连续被选中,引发抖动
- 真正均匀的加权分发,得维护每个节点的当前权重和已分配权重差值
哈希取模是另一条路,适合 key 稳定的场景
当请求带唯一标识(如 user_id、order_no),可用哈希取模替代计数器轮询,天然无状态、可横向扩展。
- 用
crc32.ChecksumIEEE([]byte(key)) % uint32(len(nodes))计算索引 - 优势:相同 key 永远落到同一节点,适合缓存、会话粘滞等场景
- 缺点:节点增减时大量 key 映射关系失效,需配合一致性哈希缓解


















