# 一、分布式方案介绍

## 2.一致性哈希环分布：

https://www.cnblogs.com/lpfuture/p/5796398.html

http://www.zsythink.net/archives/1182

# 二、代码实现

## 1.数据结构：

Key：long类型，存储节点的hash%2^32；

Value：String类型，存储节点，即IP:PORT；

## 2.代码

private int CalculateHashValue(String key)

{

int hv;

switch (_hashingAlgorithm)

{

case EnumHashingAlgorithm.Native:

hv = key.GetHashCode();

break;

case EnumHashingAlgorithm.OldCompatibleHash:

hv = HashingAlgorithmTool.OriginalHashingAlgorithm(key);

break;

case EnumHashingAlgorithm.NewCompatibleHash:

hv = HashingAlgorithmTool.NewHashingAlgorithm(key);

break;

default:

// use the native hash as a default

hv = key.GetHashCode();

_hashingAlgorithm = EnumHashingAlgorithm.Native;

break;

}

return hv;

}

//哈希取余值，为什么是2的32次方：IPV4的总量是2的32次方个，可以保证环上的IP不重复
long HashValue = (long)Math.Pow(2, 32);

private long GenerateConsistentHashValue(String key)
{
long serverHV = CalculateHashValue(key);
long mod = serverHV % HashValue;
if (mod < 0)
{
mod = mod + HashValue;
}
return mod;
}

        private void GenerateServersToBuckets()
{
for (int i = 0; i < _servers.Count; i++)
{
// 创建物理节点
String server = _servers[i];
long mod = GenerateConsistentHashValue(server);
//创建虚拟节点
List<String> virtualHostServers = GenerateVirtualServer(server, this.Weights[i]);
foreach (String v in virtualHostServers)
{
mod = GenerateConsistentHashValue(v);
}
}
}

private static List<String> GenerateVirtualServer(String server, int count)
{
if (count > 255)
{
throw new ArgumentException("每服务器虚拟节点数不能超过254");
}
List<String> virtualServers = new List<string>();

#region 1.按修改IP值+随机GUID生成虚拟节点
String invariantIPPart = ip.Substring(ip.IndexOf('.'));
int succ = 0;
for (int i = 1; i <= 255; i++)
{
{
String virtualServer = i.ToString() + invariantIPPart + ":" + port + i;// Guid.NewGuid().ToString("N").ToUpper();
succ++;
}
if (succ == count)
{
break;
}
}
#endregion

#region 2.物理节点自增序号||随机GUID
//for (int i = 0; i < count; i++)
//{
//}
#endregion

#region 32.其它生成算法
//TODO
#endregion

return virtualServers;
}

# 四、存取数据查找服务器

1.从节点环中查找服务器

private String FindServer(String key, ref long startIndex)
{
long mod = startIndex;
if (mod < 0)
{
mod = GenerateConsistentHashValue(key);
}
foreach (KeyValuePair<long, String> kvp in buckets)
{
startIndex = kvp.Key;
//找到第一个大于或等于key的服务器
if (kvp.Key >= mod)
{
//若找到的服务器不可用，则继续查找下一服务器
{
continue;
}
return kvp.Value;
}
}
//如果大于mod的服务器均不可用或没有找到，则从头开始找可用服务器
foreach (KeyValuePair<long, String> kvp in buckets)
{
startIndex = kvp.Key;
if (kvp.Key >= mod)
{
break;
}
{
continue;
}
return kvp.Value;
}
//不存在可用服务器
return string.Empty;
}

2.获取服务器及连接

 public ISockIO GetSock(string key)
{
if (buckets.Count == 0)
{
return null;
}

if (buckets.Count == 1)
{
return GetConnection(buckets[0]);
}

long startIndex = -1;//开始查找位置，-1表示从hash(key)% HashValue位置开始查找
int tries = 0;//重试次数，不超过总服务器数
while (tries++ <= this.servers.Count)
{
String server = FindServer(key, ref startIndex);
//找不到可用的服务器
if (String.IsNullOrEmpty(server))
{
return null;
}
ISockIO sock = GetConnection(server);
if (sock != null)
{
WriteLog.Write("key：" + key + ",server：" + server);
return sock;
}
//是否需要故障转移，若需要，则会继续查找可用的服务器
if (!_failover)
{
return null;
}
}
return null;
}

posted @ 2018-10-11 18:51 陈苏乾 阅读(...) 评论(...) 编辑 收藏