一致性Hash简单介绍和使用
背景:
一致性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简单介绍和使用的更多相关文章
- 一致性Hash算法介绍(分布式环境算法)
32的整数环(这个环被称作一致性Hash环),根据节点名称的Hash值(其分布范围同样为0~232)将节点放置在这个Hash 环上.然后根据KEY值计算得到其Hash值(其分布范围也同样为0~232 ...
- hash简单介绍
hash也称"散列", 是一种基于映射关系的存储方式,将任意长度的二进制值输出为固定长度的较小的二进制值,这种输出的小的固定长度的值为hash值: 1. 散列技术是在关键字key与 ...
- 给面试官讲明白:一致性Hash的原理和实践
"一致性hash的设计初衷是解决分布式缓存问题,它不仅能起到hash作用,还可以在服务器宕机时,尽量少地迁移数据.因此被广泛用于状态服务的路由功能" 01分布式系统的路由算法 假设 ...
- 一致性Hash算法原理,java实现,及用途
学习记录: 一致性Hash算法原理及java实现:https://blog.csdn.net/suifeng629/article/details/81567777 一致性Hash算法介绍,原理,及使 ...
- 11.redis cluster的hash slot算法和一致性 hash 算法、普通hash算法的介绍
分布式寻址算法 hash 算法(大量缓存重建) 一致性 hash 算法(自动缓存迁移)+ 虚拟节点(自动负载均衡) redis cluster 的 hash slot 算法 一.hash 算法 来了一 ...
- 负载均衡算法: 简单轮询算法, 平滑加权轮询, 一致性hash算法, 随机轮询, 加权随机轮询, 最小活跃数算法(基于dubbo) java代码实现
直接上干活 /** * @version 1.0.0 * @@menu <p> * @date 2020/11/17 16:28 */ public class LoadBlance { ...
- LB中使用到的一致性Hash算法的简单实现
1.类的Diagram 2.代码实现 2.1.Node类,每个Node代表集群里面的一个节点或者具体说是某一台物理机器: package consistencyhash; import lombok. ...
- 转载自lanceyan: 一致性hash和solr千万级数据分布式搜索引擎中的应用
一致性hash和solr千万级数据分布式搜索引擎中的应用 互联网创业中大部分人都是草根创业,这个时候没有强劲的服务器,也没有钱去买很昂贵的海量数据库.在这样严峻的条件下,一批又一批的创业者从创业中获得 ...
- 一致性hash算法简介
一致性哈希算法在1997年由麻省理工学院提出的一种分布式哈希(DHT)实现算法,设计目标是为了解决因特网中的热点(Hot spot)问题,初衷和CARP十分类似.一致性哈希修正了CARP使用的简单哈希 ...
随机推荐
- 线程与threading模块
线程 进程内一个相对独立的.可调度的执行单元,是系统独立调度和分派CPU的基本单位.在单个进程中同时运行多个线程完成不同的工作,称为多线程. 同一进程内的多个线程是共享该进程的资源. 创建新的线程开销 ...
- Lua local function与function区别
1 使用function声明的函数为全局函数,在被引用时可以不会因为声明的顺序而找不到 2 使用local function声明的函数为局部函数,在引用的时候必须要在声明的函数后面 例子: 下面这段代 ...
- vue 按需加载
vue 构建单页面应用,但是问题是随着系统的体积变大,js文件也体积太大了,这时候就需要按需要进行加载了 vue-router提供了懒加载的方式 const Foo = resolve => r ...
- DevExpress GridControl 控件点滴
一.常用控件样式 public void setDgv(DevExpress.XtraGrid.Views.Grid.GridView gridView1) { gridView1.OptionsVi ...
- Mysql基本操作语句【重要】
一.对数据库的操作 1. 创建一个库 create database 库名 create database 库名 character set 编码
- LeetCode OJ-- Simplify Path **
https://oj.leetcode.com/problems/simplify-path/ 对linux路径的规范化,属于字符串处理的题目.细节很多. #include <iostream& ...
- LeetCode OJ--Binary Tree Level Order Traversal II
http://oj.leetcode.com/problems/binary-tree-level-order-traversal-ii/ 树的层序遍历,和上一道题相比,对结果做一个顺序调整 reve ...
- js-随机生成16进制颜色
<body onload="color()"></body> <script> function color(){ 方法一: document. ...
- BZOJ 4326 NOIP2015 运输计划(二分答案 + 树上差分思想)
题目链接 BZOJ4326 这个程序在洛谷上TLE了……惨遭卡常 在NOIP赛场上估计只能拿到95分吧= = 把边权转化成点权 首先求出每一条路径的长度 考虑二分答案,$check(now)$ 对于 ...
- luogu P2831 愤怒的小鸟
题目描述 Kiana最近沉迷于一款神奇的游戏无法自拔. 简单来说,这款游戏是在一个平面上进行的. 有一架弹弓位于(0,0)处,每次Kiana可以用它向第一象限发射一只红色的小鸟,小鸟们的飞行轨迹均为形 ...