.net的一致性哈希实现
最近在项目的微服务架构推进过程中,一个新的服务需要动态伸缩的弹性部署,所有容器化示例组成一个大的工作集群,以分布式处理的方式来完成一项工作,在集群中所有节点的任务分配过程中,由于集群工作节点需要动态增减,因此需要利用etcd(或zk)来管理集群,同时用一致性哈希算法来定位每个工作项的具体工作节点,一致性哈希算法的实现(.NET)为如下地址:
https://github.com/cerasumat/ConsistentHash/tree/develop
算法的原理不再赘述,用baidu都能够在第一页直接检索到,原理很简单,这个实现中哈希空间只有2^32-1,已经能够满足我的业务场景(只处理最近某一段时长的对象实体,这个空间已够用)。源码也很简单,结合原理中那个桶的图示,一看就明白。
简单说说用法:
1:以物理节点初始化哈希路由器
PhysicalNode node1 = new PhysicalNode("SituationAnalysis", "10.202.1.1", 80); PhysicalNode node2 = new PhysicalNode("SituationAnalysis", "10.202.1.2", 80); PhysicalNode node3 = new PhysicalNode("SituationAnalysis", "10.202.1.3", 80);
var pNodes = new List<PhysicalNode>();
pNodes.Add(node1);
pNodes.Add(node2);
pNodes.Add(node3);
var router = new Router(pNodes, 3);
初始化得到一个物理节点*虚拟副本数的虚拟节点集群,分布在哈希环上
2:以该路由器提供的GetNode方法,对目标资源进行哈希路由
int count85 = 0; int count86 = 0; int count87 = 0; Stopwatch sw = new Stopwatch(); sw.Start(); for (int i = 1; i < 100000; i++) { var dataKey = string.Format("SA-20161115-Issue232-{0}", i.ToString().PadLeft(5, '0')); var node = router.GetNode(dataKey); switch (node.Ip) { case "10.202.1.1": Interlocked.Increment(ref count85); break; case "10.202.1.2": Interlocked.Increment(ref count86); break; case "10.202.1.3": Interlocked.Increment(ref count87); break; } } sw.Stop(); TimeSpan elapse = sw.Elapsed; int total = count85 + count86 + count87; Assert.IsTrue(total == 99999);
上述代码只是UT代码中的片段,主要测试用第1步获取的router对99999个key进行哈希定位的耗时(在我笔记本上500ms左右)以及目标keys是否无遗漏地分布到每个节点。
3:集群动态伸缩
IRouter提供了集群伸缩的接口(AddNode,RemoveNode)等,可供使用过程中集群动态伸缩需求使用(可以考虑采取监控etcd或zookeeper中集群信息的方式来实时更新当前集群信息,达到动态伸缩的目的,具体实现这篇帖子不再表述)
以上就是一致性哈希算法的一个简单实现,可根据实际需求引入项目使用,适用于分布式处理的场景。