一致性哈希算法(c#版)
最近在研究"一致性HASH算法"(Consistent Hashing),用于解决memcached集群中当服务器出现增减变动时对散列值的影响。后来 在JAVAEYE上的一篇文章中,找到了其中的 KetamaHash 算法的JAVA实现(一种基于虚拟结点的HASH算法),于是为了加深理解,对照 JAVA版本,用C#重写了一个。放到这里,如果大家感兴趣的话, 可以下载测试一下,如果发现写法有问题请及时告之我,以便我及时修正。
下面是对Ketama的介绍:
Ketama is an implementation of a consistent hashing algorithm, meaning you can add or remove servers from the memcached pool without causing a complete remap of all keys.
Here’s how it works:
* Take your list of servers (eg: 1.2.3.4:11211, 5.6.7.8:11211, 9.8.7.6:11211)
* Hash each server string to several (100-200) unsigned ints
* Conceptually, these numbers are placed on a circle called the continuum. (imagine a clock face that goes from 0 to 2^32)
* Each number links to the server it was hashed from, so servers appear at several points on the continuum, by each of the numbers they hashed to.
* To map a key->server, hash your key to a single unsigned int, and find the next biggest number on the continuum. The server linked to that number is the correct server for that key.
* If you hash your key to a value near 2^32 and there are no points on the continuum greater than your hash, return the first server in the continuum.
If you then add or remove a server from the list, only a small proportion of keys end up mapping to different servers.
我的理解,这类方法其实有点像大学里的微积分的思想(通过连续函数的取值区间来计算图形面积)。通过把已知的实结点(memcached服务IP端口)列表结成一个圆,然后在两两实结点之间“放置”尽可能多的虚拟节点(上面文中的unsigned
ints),
假设用户数据映射在虚拟节点上(用户数据真正存储位置是在该虚拟节点代表的实际物理服务器上),这样就能抑制分布不均匀,最大限度地减小服务器增减时的缓存重新分布。如下图:
下面是添加结点时:
如这篇文章所说(总结一致性哈希(Consistent Hashing)):
Consistent
Hashing最大限度地抑制了hash键的重新分布。另外要取得比较好的负载均衡的效果,往往在服务器数量比较少的时候需要增加虚拟节点来保证服务器能均匀的分布在圆环上。因为使用一般的hash方法,服务器的映射地点的分布非常不均匀。使用虚拟节点的思想,为每个物理节点(服务器)在圆上分配100~200个点。这样就能抑制分布不均匀,最大限度地减小服务器增减时的缓存重新分布。用户数据映射在虚拟节点上,就表示用户数据真正存储位置是在该虚拟节点代表的实际物理服务器上。
了解了原理,下面看一下具体实现。
JAVA实现代码取自Spy Memcached client中的类,原文的作者也尽可能的对代码进行注释说明,所以让我剩了不少时间。
下面是相应的.NET实现(注释参考JAVA版本):
public class KetamaNodeLocator
{
//原文中的JAVA类TreeMap实现了Comparator方法,这里我图省事,直接用了net下的SortedList,其中Comparer接口方法)
private SortedList<long, string> ketamaNodes = new SortedList<long, string>();
private HashAlgorithm hashAlg;
private int numReps = 160; //此处参数与JAVA版中有区别,因为使用的静态方法,所以不再传递HashAlgorithm alg参数
public KetamaNodeLocator(List<string> nodes, int nodeCopies)
{
ketamaNodes = new SortedList<long, string>(); numReps = nodeCopies;
//对所有节点,生成nCopies个虚拟结点
foreach (string node in nodes)
{
//每四个虚拟结点为一组
for (int i = 0; i < numReps / 4; i++)
{
//getKeyForNode方法为这组虚拟结点得到惟一名称
byte[] digest = HashAlgorithm.computeMd5(node + i);
/** Md5是一个16字节长度的数组,将16字节的数组每四个字节一组,分别对应一个虚拟结点,这就是为什么上面把虚拟结点四个划分一组的原因*/
for (int h = 0; h < 4; h++)
{
long m = HashAlgorithm.hash(digest, h);
ketamaNodes[m] = node;
}
}
}
} public string GetPrimary(string k)
{
byte[] digest = HashAlgorithm.computeMd5(k);
string rv = GetNodeForKey(HashAlgorithm.hash(digest, 0));
return rv;
} string GetNodeForKey(long hash)
{
string rv;
long key = hash;
//如果找到这个节点,直接取节点,返回
if (!ketamaNodes.ContainsKey(key))
{
//得到大于当前key的那个子Map,然后从中取出第一个key,就是大于且离它最近的那个key 说明详见: http://www.javaeye.com/topic/684087
var tailMap = from coll in ketamaNodes
where coll.Key > hash
select new { coll.Key };
if (tailMap == null || tailMap.Count() == 0)
key = ketamaNodes.FirstOrDefault().Key;
else
key = tailMap.FirstOrDefault().Key;
}
rv = ketamaNodes[key];
return rv; }}
下面的代码与JAVA中有所不同,它使用静态方法实现:
public class HashAlgorithm
{
public static long hash(byte[] digest, int nTime)
{
long rv = ((long)(digest[3 + nTime * 4] & 0xFF) << 24)
| ((long)(digest[2 + nTime * 4] & 0xFF) << 16)
| ((long)(digest[1 + nTime * 4] & 0xFF) << 8)
| ((long)digest[0 + nTime * 4] & 0xFF); return rv & 0xffffffffL; /* Truncate to 32-bits */
} /**
* Get the md5 of the given key.
*/
public static byte[] computeMd5(string k)
{
MD5 md5 = new MD5CryptoServiceProvider();
byte[] keyBytes = md5.ComputeHash(Encoding.UTF8.GetBytes(k));
md5.Clear();
//md5.update(keyBytes);
//return md5.digest();
return keyBytes;
}
}
下面是.net版本下的测试结果
分布平均性测试:测试随机生成的众多key是否会平均分布到各个结点上测试结果如下:
最上面一行是参数说明,节点数目,总共有多少key,每个节点应该分配key的比例是多少。下面是每个结点分配到key的数目和比例。 多次测试后发现,这个Hash算法的节点分布都在标准比例左右徘徊。
节点增删测试:在环上插入N个结点,每个节点nCopies个虚拟结点。随机生成众多key,在增删节点时,测试同一个key选择相同节点的概率,测试如果如下:
上面三行分别是正常情况,节点增加,节点删除情况下的节点数目。下面两行表示在节点增加和删除情况下,同一个key分配在相同节点上的比例(命中率)。
后来我修改了几次增删结点的数量,基本验证了JAVA那位仁兄所说的那样:
多次测试后发现,命中率与结点数目和增减的节点数量有关。同样增删结点数目情况下,结点多时命中率高。同样节点数目,增删结点越少,命中率越高。这些都与实际情况相符。
这里还有一些链接,都是介绍和讨论Consistent Hashing的,有兴趣的朋友可以看一下,呵呵:)
总结一致性哈希(Consistent Hashing)
Ketama一致性Hash算法学习(含Java代码)
还有淘宝核心系统团队博客的这篇文章, Dynamo 简介
好了,今天的文章就先到这里了,这里是相应语言的源码下载链接: java c#
原文链接:http://www.cnblogs.com/daizhj/archive/2010/08/24/1807324.html
BLOG: http://daizhj.cnblogs.com/
一致性哈希算法(c#版)的更多相关文章
- _00013 一致性哈希算法 Consistent Hashing 新的讨论,并出现相应的解决
笔者博文:妳那伊抹微笑 博客地址:http://blog.csdn.net/u012185296 个性签名:世界上最遥远的距离不是天涯,也不是海角,而是我站在妳的面前.妳却感觉不到我的存在 技术方向: ...
- 一致性哈希算法与Java实现
原文:http://blog.csdn.net/wuhuan_wp/article/details/7010071 一致性哈希算法是分布式系统中常用的算法.比如,一个分布式的存储系统,要将数据存储到具 ...
- 五分钟理解一致性哈希算法(consistent hashing)
转载请说明出处:http://blog.csdn.net/cywosp/article/details/23397179 一致性哈希算法在1997年由麻省理工学院提出的一种分布式哈希(DHT)实现算法 ...
- 每天进步一点点——五分钟理解一致性哈希算法(consistent hashing)
转载请说明出处:http://blog.csdn.net/cywosp/article/details/23397179 一致性哈希算法在1997年由麻省理工学院提出的一种分布式哈希(DHT) ...
- 一致性哈希算法以及其PHP实现
在做服务器负载均衡时候可供选择的负载均衡的算法有很多,包括: 轮循算法(Round Robin).哈希算法(HASH).最少连接算法(Least Connection).响应速度算法(Respons ...
- Java_一致性哈希算法与Java实现
摘自:http://blog.csdn.net/wuhuan_wp/article/details/7010071 一致性哈希算法是分布式系统中常用的算法.比如,一个分布式的存储系统,要将数据存储到具 ...
- 一致性哈希算法(consistent hashing)【转】
一致性哈希算法 来自:http://blog.csdn.net/cywosp/article/details/23397179 一致性哈希算法在1997年由麻省理工学院提出的一种分布式哈希 ...
- 一致性哈希算法学习及JAVA代码实现分析
1,对于待存储的海量数据,如何将它们分配到各个机器中去?---数据分片与路由 当数据量很大时,通过改善单机硬件资源的纵向扩充方式来存储数据变得越来越不适用,而通过增加机器数目来获得水平横向扩展的方式则 ...
- 一致性哈希算法——算法解决的核心问题是当slot数发生变化时,能够尽量少的移动数据
一致性哈希算法 摘自:http://blog.codinglabs.org/articles/consistent-hashing.html 算法简述 一致性哈希算法(Consistent Hashi ...
随机推荐
- StringBuilder与StringBuffer
转:http://www.cnblogs.com/pepcod/archive/2013/02/16/2913557.html JAVA中用于处理字符串常用的有三个类: java.lang.Strin ...
- 【Codeforces Round #519】
A:https://www.cnblogs.com/myx12345/p/9872082.html B:https://www.cnblogs.com/myx12345/p/9872124.html ...
- 冬训day3 简单数据结构
A - 简单计算器 模拟加栈..写一写就好,从头到尾扫一遍,分两个栈存,一个存运算符,一个存中间结果,遇到乘除就先处理了,每次遇到加减就处理上一个加减的两个数,结果压进去...同时把这个运算符存进去. ...
- usb 2.0 operation mode
一般來說 USB 的通訊結構有如 Server/Client,以 PC 上的情形為例,位於主機上的 USB 裝置稱為『USB Host』,我們可以在上面外接上數個裝置(與 USB Host 相連的裝置 ...
- C#将图片进行马赛克处理
/// <summary> /// 马赛克处理 /// </summary> /// <param name="bitmap"></par ...
- POJ1655 Balancing Act(树的重心)
题目链接 Balancing Act 就是求一棵树的重心,然后统计答案. #include <bits/stdc++.h> using namespace std; #define REP ...
- 聚类kmeans算法在yolov3中的应用
yolov3 kmeans yolov3在做boundingbox预测的时候,用到了anchor boxes.这个anchors的含义即最有可能的object的width,height.事先通过聚类得 ...
- Codeforces Round #490 (Div. 3)
感觉现在\(div3\)的题目也不错啊? 或许是我变辣鸡了吧....... 代码戳这里 A. Mishka and Contes 从两边去掉所有\(≤k\)的数,统计剩余个数即可 B. Reversi ...
- 【BZOJ1562】【jzyzOJ1730】【COGS409】NOI2009变换序列 二分图匹配
[问题描述] 对于N个整数0, 1, ……, N-1,一个变换序列T可以将i变成Ti,其中 定义x和y之间的距离.给定每个i和Ti之间的距离D(i,Ti), 你需要求出一个满足要求的变换 ...
- Android 控件架构与自定义控件详解
架构: PhoneWindow 将一个 DecorView 设置为整个应用窗口的根 View,这里面所有 View 的监听事件,都通过 WindowManagerService 来接收.DecorVi ...