Week 05- 作业一:一致性 hash 算法
发布于: 2020 年 07 月 06 日
用你熟悉的编程语言实现一致性 hash 算法。
编写测试用例测试这个算法,测试 100 万 KV 数据,10 个服务器节点的情况下,计算这些 KV 数据在服务器上分布数量的标准差,以评估算法的存储负载不均衡性。
基于C# 实现~~~
public class ConsistentDemo { private HashSet<string> _server = new HashSet<string>() { "server-0", "server-1","server-2","server-3","server-4", "server-5","server-6","server-7","server-8", "server-9" }; /// <summary> /// 虚拟多少倍 /// </summary> const int Multiples = 200; /// <summary> /// 测试样本数据量 /// </summary> private const int TestItemCount = 400000;//1_000_000; private const int FNV32_prime = 16777619;//0x01000193; private const long FNV32_basis = 2166136261;//0x811C9DC5; //一个哈希值对应N的VALUE. private Dictionary<long, string> _vServers = new Dictionary<long, string>(); private long GetServerHash(string serverName) { long hash = FNV32_basis; for (int i = 0; i < serverName.Length; i++) { hash = (hash ^ serverName[i]) * FNV32_prime; } hash += hash << 40; hash ^= hash >> 8; hash += hash << 7; hash ^= hash >> 5; hash ^= hash >> 4; hash += hash << 1; return hash; } public ConsistentDemo() { foreach (var item in _server) { AddServer(item); } } /// <summary> /// 新增服务器 /// </summary> /// <param name="name"></param> public void AddServer(string name) { for (int index = 0; index < Multiples; index++) { long hash = GetServerHash($"{name}:Virtual Server{index}"); _vServers.TryAdd(hash, name); } } /// <summary> /// 移除服务器 /// </summary> /// <param name="name"></param> public void RemoveServer(string name) { for (int index = 0; index < Multiples; index++) { long hash = GetServerHash($"{name}:Virtual Server{index}"); _vServers.Remove(hash); } } /// <summary> /// 获取Key-value 对应服务服务器 /// </summary> /// <param name="theValue"></param> /// <returns></returns> public string GetServer(string theValue) { if (_server.Count == 0) { return string.Empty; } long hash = GetServerHash(theValue); var target = _vServers.Keys.OrderBy(item => item).FirstOrDefault(item => item >= hash); if (_vServers.ContainsKey(target)) { return _vServers[target]; } else { return _vServers.FirstOrDefault().Value; } } public void Print() { Dictionary<string, int> data = new Dictionary<string, int>(); for (int i = 0; i < TestItemCount; i++) { string svrName = GetServer($"我是{i}号数据"); if (data.ContainsKey(svrName)) { data[svrName] += 1; } else { data[svrName] = 1; } } Console.WriteLine($"数据量:{TestItemCount},数据被分布在:{data.Count}台服务器上 虚拟倍数{Multiples} 总虚拟服务器个数为:{_vServers.Count}"); foreach (var item in data) { Console.WriteLine($"我是<{item.Key}> 我承载了{((float)item.Value / (float)TestItemCount) * 100}%数据"); } Console.WriteLine($"标准差为:{CalculateStdDev(data.Values.ToArray())}"); } private double CalculateStdDev(IEnumerable<int> values) { double ret = 0; if (values.Count() > 0) { // 计算平均数 double avg = values.Average(); // 计算各数值与平均数的差值的平方,然后求和 double sum = values.Sum(d => Math.Pow(d - avg, 2)); // 除以数量,然后开方 ret = Math.Sqrt(sum / values.Count()); } return ret; } }
static void Main(string[] args) { Stopwatch sw = new Stopwatch(); var xx = new ConsistentDemo(); sw.Restart(); Console.WriteLine("初始化服务器"); xx.Print(); Console.WriteLine($"总耗时:{sw.ElapsedMilliseconds}ms"); Console.WriteLine(""); sw.Restart(); Console.WriteLine("新增一个临时的"); xx.AddServer("临时服务器1"); xx.Print(); Console.WriteLine($"总耗时:{sw.ElapsedMilliseconds}ms"); Console.WriteLine(""); sw.Restart(); Console.WriteLine("删除一个"); xx.RemoveServer("server-1"); xx.Print(); Console.WriteLine($"总耗时:{sw.ElapsedMilliseconds}ms"); Console.ReadLine(); }
100W 、40W的测试
划线
评论
复制
发布于: 2020 年 07 月 06 日 阅读数: 34
版权声明: 本文为 InfoQ 作者【dean】的原创文章。
原文链接:【http://xie.infoq.cn/article/59bea5d94fc50d3805d915391】。文章转载请联系作者。
dean
关注
还未添加个人签名 2019.11.06 加入
还未添加个人简介
评论