背景:

一致性Hash用于分布式缓存系统,将Key值映射到详细机器Ip上,而且添加和删除1台机器的数据移动量较小,对现网影响较小



实现:

1 Hash环:将节点的Hash值映射到一个Hash环中。每一个Key顺时针第一个找到的节点。就是这个Key被路由到的机器

2 "虚拟节点":将节点虚拟成多个"虚拟节点"分布在Hash环上,使得分布更均匀。扩缩容影响较小

代码实例:

/*
* @ 一致性Hash模拟測试
* @ 结论:模拟4台机器扩容1台。遍历Key[0,999983]
- 一致性Hash需移动181161个Key,约占18%(1/5左右,符合预期效果)
- 取模Hash需移动799984个Key,约占80%
* @ 2014.05.30
*/ #include <stdint.h>
#include <iostream>
#include <string.h>
#include <sstream>
#include <map>
#include <vector>
using namespace std; #define HASH_MOD (999983) template <class T>
string ToStr(const T &t)
{
stringstream stream;
stream << t;
return stream.str();
} uint32_t APHash(string &sKey)
{
char *key = (char*)sKey.c_str();
unsigned int hash = 0;
for (int i=0; *key; i++)
{
if ((i & 1) == 0) {
hash ^= ((hash<<7)^(*key++)^(hash>>3));
} else {
hash ^= (~((hash<<11)^(*key++)^(hash>>5)));
}
}
return hash%HASH_MOD;
} class CMyConHash
{
public:
/* 加入一台机器(IP) */
void AddIp(const string &sIp)
{
// 每一个IP分配128个虚拟节点,原因:结合APHash实验结果分布较均匀
for (int i = 0; i < 128; i ++)
{
string sCode = sIp + ToStr(i) + "#Hash";
uint32_t uVirKey = APHash(sCode);
mapVirKey2Ip[uVirKey] = sIp;
mapIp2VirKey[sIp].push_back(uVirKey);
}
} /* 删除一台机器(IP) */
void DelIp(const string &sIp)
{
if (mapIp2VirKey.count(sIp) == 0) {
cout << "DelIp Err: mapIp2VirKey Don`t Has Ip=" << sIp << endl;
return;
}
vector<uint32_t> vecVirKey = mapIp2VirKey[sIp];
for (int i = 0; i < vecVirKey.size(); i ++)
{
uint32_t uVirKey = vecVirKey[i];
if (mapVirKey2Ip[uVirKey] == sIp) {
// 得推断下。有可能2个IP虚拟节点相等后覆盖了
mapVirKey2Ip.erase(uVirKey);
}
}
mapIp2VirKey.erase(sIp);
} /* 路由:给每一个Key找到负责的机器(IP) */
int FindIp(uint32_t uKey, string &sIp)
{
if (mapVirKey2Ip.size() == 0) {
cout << "FindIp Err: mapVirKey2Ip.size() == 0" << endl;
return -1;
}
bool bFind = false;
uint32_t uVirKey;
map<uint32_t, string>::iterator iter;
// 遍历std::map是按Key大小顺序输出(差别std::tr1::unordered_map)
for(iter = mapVirKey2Ip.begin(); iter != mapVirKey2Ip.end(); iter ++)
{
uVirKey = iter->first;
if (uVirKey > uKey%HASH_MOD) {
sIp = iter->second;
bFind = true;
break;
}
}
if (!bFind) {
// 找不到比Key小的虚拟节点,故使用最小的虚拟节点(环)
iter = mapVirKey2Ip.begin();
uVirKey = iter->first;
sIp = iter->second;
}
//cout << "FindIp Suc:" << uKey%HASH_MOD << "=>" << uVirKey << "," << sIp << endl;
return 0;
} /* 打印各个IP负责的Key区域大小。影响因素:1 Hash函数 2 虚拟节点个数 */
/* 4台机器的情况,相对还是较均匀:
Ip=202.168.14.241,Cnt=251649
Ip=202.168.14.242,Cnt=257902
Ip=202.168.14.243,Cnt=245945
Ip=202.168.14.244,Cnt=235516 */
void EchoIpState()
{
map<string, uint32_t> mapIpCnt;
map<uint32_t, string>::iterator iter = mapVirKey2Ip.end();
iter --;
uint32_t uPreKey = iter->first;
string sPreIp = iter->second;
do {
iter --;
uint32_t uVirKey = iter->first;
string sIp = iter->second;
if (mapIpCnt.count(sPreIp) == 0) {
mapIpCnt[sPreIp] = uPreKey-uVirKey;
} else {
mapIpCnt[sPreIp] += uPreKey-uVirKey;
}
uPreKey = uVirKey;
sPreIp = sIp;
} while (iter != mapVirKey2Ip.begin()); cout << "Ip Size=" << mapIpCnt.size() << endl;
map<string, uint32_t>::iterator iter1;
for(iter1 = mapIpCnt.begin(); iter1 != mapIpCnt.end(); iter1 ++)
{
cout << "Ip=" << iter1->first << ",Cnt=" << iter1->second << endl;
}
}
private:
map< uint32_t, string > mapVirKey2Ip;
map< string, vector<uint32_t> > mapIp2VirKey;
}; class CMyModHash
{
public:
void AddIp(const string &sIp)
{
vecIpList.push_back(sIp);
}
void FindIp(uint32_t uKey, string &sIp)
{
sIp = vecIpList[uKey%vecIpList.size()];
}
void EchoIpState()
{
cout << "Ip Cnt=" << vecIpList.size() << endl;
}
private:
vector<string> vecIpList;
}; int main()
{
CMyConHash oMyHash;
// CMyModHash oMyHash; // 模拟初始化4台机器
oMyHash.AddIp("202.168.14.241");
oMyHash.AddIp("202.168.14.242");
oMyHash.AddIp("202.168.14.243");
oMyHash.AddIp("202.168.14.244");
oMyHash.EchoIpState(); // 保存下各个Key路由的机器
string sIp, arrKeyIp[HASH_MOD];
for (uint32_t key = 0; key < HASH_MOD; key ++)
{
oMyHash.FindIp(key, sIp);
arrKeyIp[key] = sIp;
} // 模拟加入1台机器
oMyHash.AddIp("202.168.14.245");
oMyHash.EchoIpState(); // 推断多少Key相应数据须要移动机器
uint32_t uCnt = 0;
for (uint32_t key = 0; key < HASH_MOD; key ++)
{
oMyHash.FindIp(key, sIp);
if (arrKeyIp[key] != sIp) {
uCnt ++;
}
}
cout << "Key Sum=" << HASH_MOD << " , Need To Move:" << uCnt << endl; return 0;
}

一致性Hash简单介绍和使用的更多相关文章

  1. 一致性Hash算法介绍(分布式环境算法)

    32的整数环(这个环被称作一致性Hash环),根据节点名称的Hash值(其分布范围同样为0~232)将节点放置在这个Hash 环上.然后根据KEY值计算得到其Hash值(其分布范围也同样为0~232  ...

  2. hash简单介绍

    hash也称"散列", 是一种基于映射关系的存储方式,将任意长度的二进制值输出为固定长度的较小的二进制值,这种输出的小的固定长度的值为hash值: 1. 散列技术是在关键字key与 ...

  3. 给面试官讲明白:一致性Hash的原理和实践

    "一致性hash的设计初衷是解决分布式缓存问题,它不仅能起到hash作用,还可以在服务器宕机时,尽量少地迁移数据.因此被广泛用于状态服务的路由功能" 01分布式系统的路由算法 假设 ...

  4. 一致性Hash算法原理,java实现,及用途

    学习记录: 一致性Hash算法原理及java实现:https://blog.csdn.net/suifeng629/article/details/81567777 一致性Hash算法介绍,原理,及使 ...

  5. 11.redis cluster的hash slot算法和一致性 hash 算法、普通hash算法的介绍

    分布式寻址算法 hash 算法(大量缓存重建) 一致性 hash 算法(自动缓存迁移)+ 虚拟节点(自动负载均衡) redis cluster 的 hash slot 算法 一.hash 算法 来了一 ...

  6. 负载均衡算法: 简单轮询算法, 平滑加权轮询, 一致性hash算法, 随机轮询, 加权随机轮询, 最小活跃数算法(基于dubbo) java代码实现

    直接上干活 /** * @version 1.0.0 * @@menu <p> * @date 2020/11/17 16:28 */ public class LoadBlance { ...

  7. LB中使用到的一致性Hash算法的简单实现

    1.类的Diagram 2.代码实现 2.1.Node类,每个Node代表集群里面的一个节点或者具体说是某一台物理机器: package consistencyhash; import lombok. ...

  8. 转载自lanceyan: 一致性hash和solr千万级数据分布式搜索引擎中的应用

    一致性hash和solr千万级数据分布式搜索引擎中的应用 互联网创业中大部分人都是草根创业,这个时候没有强劲的服务器,也没有钱去买很昂贵的海量数据库.在这样严峻的条件下,一批又一批的创业者从创业中获得 ...

  9. 一致性hash算法简介

    一致性哈希算法在1997年由麻省理工学院提出的一种分布式哈希(DHT)实现算法,设计目标是为了解决因特网中的热点(Hot spot)问题,初衷和CARP十分类似.一致性哈希修正了CARP使用的简单哈希 ...

随机推荐

  1. Javascript 开启浏览器全屏模式

    作者:伯乐在线/前端空城师 通常在某些情况下,我们需要让浏览器开启全屏模式,以便获得更好的视觉体验,先看下全屏模式简单的几个API. 浏览器默认绑定 非全屏模式下, document的F11按键绑定开 ...

  2. vue-cli脚手架每行注释--摘抄

    .babelrc文件 { // 此项指明,转码的规则 "presets": [ // env项是借助插件babel-preset-env,下面这个配置说的是babel对es6,es ...

  3. Linux 之 MySQL主从同步

    MySQL主从同步 参考教程:[千峰教育] 1.架设两个虚拟服务器,都安装好mysql. 2.关闭防火墙和Selinux. service iptables stop setenforce 0 3.修 ...

  4. js-键盘回车搜索enter

    这个问题需求在移动版上经常用到. <div class="sousuo">        <input type="text" placeho ...

  5. js-(19,999,999.00)

    function price(n, precision) { let s = String(n), int = parseInt(n).toString(), pre = s.split('.')[1 ...

  6. Codefroces Gym101572 I.Import Spaghetti-有向图跑最小环输出路径(Floyd)

    暑假学的很多东西,现在都忘了,补这道题还要重新学一下floyd,有点难过,我暑假学的东西呢??? 好了,淡定,开始写题解. 这个题我是真的很难过啊,输入简直是有毒啊(内心已经画圈诅咒出题人无数次了.. ...

  7. Java 内存查看与分析

    1:gc日志输出 在jvm启动参数中加入 -XX:+PrintGC -XX:+PrintGCDetails -XX:+PrintGCTimestamps -XX:+PrintGCApplication ...

  8. .Net Core中的配置文件源码解析

    一.配置简述 之前在.Net Framework平台开发时,一般配置文件都是xml格式的Web.config,而需要配置其他格式的文件就需要自己去读取内容,加载配置了..而Net Core支持从命令行 ...

  9. Django-自己写的py文件调用models&Non-ASCII character报错&url接收参数

    1.这个设置是网上能查到的最多的,但是没解决我的问题: Django的models.py在外部独立使用,新建一个文件夹,和monitor1目录平级 import sys,os sys.path.app ...

  10. CF997D

    分析: 假设在第一个树上我们有一个长度为x的环,在第二树上我们有一个长度为y的环,那么可以在叉积树上构造出$\binom{x+y}{x}$个长度为x+y的环 问题的关键就变成了如何统计出在一个树上的长 ...