浅谈一致性Hash原理及应用

  在讲一致性Hash之前我们先来讨论一个问题。

  问题:现在有亿级用户,每日产生千万级订单,如何将订单进行分片分表?

  小A:我们可以按照手机号的尾数进行分片,同一个尾数的手机号写入同一片/同一表中。

  大佬:我希望通过会员ID来查询这个会员的所有订单信息,按照手机号分片/分表的话,前提是需要该用户的手机号保持不变,并且在查询订单列表时需要提前查询该用户的手机号,利用手机号尾数不太合理。

  小B:按照大佬的思路,我们需要找出一个唯一不变的属性来进行分片/分表。

  大佬:迷之微笑~

  小B:(信心十足)会员在我们这边保持不变的就是会员ID(int),我们可以通过会员ID的尾数进行分片/分表

  小C:尽然我们可以用会员ID尾数进行分片/分表,那就用取模的方式来进行分片/分表,通过取模的方式可以达到很好的平衡性。示意图如下:

   640?wx_fmt=png

  大佬:嗯嗯嗯,在不考虑会员冷热度的情况下小B和小C说的方案绝佳;但是往往我们的会员有冷热度和僵尸会员,通过取模的方式往往会出现某个分片数据异常高,部分分片数据异常低,导致平衡倾斜。示意图如下:

  640?wx_fmt=png

  大佬:当出现某个分片/分表达到极限时我们需要添加片/表,此时发现我们无法正常添加片/表。因为一旦添加片/或表的时候会导致绝大部分数据错乱,按照原先的取模方式是无法正常获取数据的。示意图如下

  640?wx_fmt=png

 

 

添加分片/分表前4,5,6会员的订单分别存储在A,B,C上,当添加了片/表的时候在按照(会员ID%N)方式取模去取数据4,5,6会员的订单数据时发现无法取到订单数据,因为此时4,5,6这三位会员数据分布存在了D,E,A上,具体示意图如下: 

  640?wx_fmt=png

  大佬:所以通过取模的方式也会存在缺陷;好了接下来我们来利用一致hash原理的方式来解决分片/分表的问题。

 首先什么是一致性哈希算法?一致性哈希算法(Consistent Hashing Algorithm)是一种分布式算法,常用于负载均衡。Memcached client也选择这种算法,解决将key-value均匀分配到众多Memcached server上的问题。它可以取代传统的取模操作,解决了取模操作无法应对增删Memcached Server的问题(增删server会导致同一个key,在get操作时分配不到数据真正存储的server,命中率会急剧下降)。

   还以上述问题为例,假如我们有10片,我们利用Hash算法将每一片算出一个Hash值,而这些Hash点将被虚拟分布在Hash圆环上,理论视图如下:  

  640?wx_fmt=png

  按照顺时针的方向,每个点与点之间的弧形属于每个起点片的容量,然后按照同样的Hash计算方法对每个会员ID进行Hash计算得出每个Hash值然后按照区间进行落片/表,以保证数据均匀分布。

如果此时需要在B和C之间新增一片/表(B1)的话,就不会出现按照取模形式导致数据几乎全部错乱的情况,仅仅是影响了(B1,C)之间的数据,这样我们清洗出来也就比较方便,也不会出现数据大批量

瘫痪。

  但是如果我们仅仅是将片/表进行计算出Hash值之后,这些点分布并不是那么的均匀,比如就会下面的这种情况,导致区间倾斜。如图

640?wx_fmt=png

  这个时候虚拟节点就此诞生,下面让我们来看一下虚拟节点在一致性Hash中的作用。当我们在Hash环上新增若干个点,那么每个点之间的距离就会接近相等。按照这个思路我们可以新增若干个

片/表,但是成本有限,我们通过复制多个A、B、C的副本({A1-An},{B1-Bn},{C1-Cn})一起参与计算,按照顺时针的方向进行数据分布,按照下图示意:

  640?wx_fmt=png

此时A=[A,C1)&[A1,C2)&[A2,B4)&[A3,A4)&[A4,B1);B=[B,A1)&[B2,C)&[B3,C3)&[B4,C4)&[B1,A);C=[C1,B)&[C2,B2)&[C,B3)&[B3,C3)&[C4,A3);由图可以看出分布点越密集,平衡性约好。

using System;

using System.Collections.Generic;

using System.Data.HashFunction;

using System.Data.HashFunction.xxHash;

using System.Linq;


namespace HashTest

{

    public class ConsistentHash

    {

        /// <summary>

        /// 虚拟节点数

        /// </summary>

        private static readonly int VirturalNodeNum = 10;


        /// <summary>

        /// 服务器IP

        /// </summary>

        private static readonly string[] Nodes = { "192.168.1.1", "192.168.1.2", "192.168.1.3"};


        /// <summary>

        /// 按照一致性Hash进行分组

        /// </summary>

        private static readonly IDictionary<uint, string> ConsistentHashNodes = new Dictionary<uint, string>();


        private static uint[] _nodeKeys = null;

               

        public static void ComputeNode()

        {

            foreach (var node in Nodes)

            {

                AddNode(node);

            }

        }


        private static void AddNode(string node)

        {

            for (int i = 0; i < VirturalNodeNum; i++)

            {

                var key = node + ":" + i;

                var hashValue = ComputeHash(key);

                if (!ConsistentHashNodes.ContainsKey(hashValue))

                {

                    ConsistentHashNodes.Add(hashValue, node);

                }

            }


            _nodeKeys = ConsistentHashNodes.Keys.ToArray();

        }


        private static uint ComputeHash(string virturalNode)

        {

            var hashFunction = xxHashFactory.Instance.Create();

            var hashValue = hashFunction.ComputeHash(virturalNode);

            return BitConverter.ToUInt32(hashValue.Hash, 0);

        }


        public static string Get(string item)

        {

            var hashValue = ComputeHash(item);

            var index = GetClockwiseNearestNode(hashValue);

            return ConsistentHashNodes[_nodeKeys[index]];

        }


        private static int GetClockwiseNearestNode(uint hash)

        {

            int begin = 0;

            int end = _nodeKeys.Length - 1;


            if (_nodeKeys[end] < hash || _nodeKeys[0] > hash)

            {

                return 0;

            }


            while ((end - begin) > 1)

            {

                var mid = (end + begin) / 2;

                if (_nodeKeys[mid] >= hash) end = mid;

                else begin = mid;

            }


            return end;

        }

    }

}

原文地址:https://www.cnblogs.com/xialihua1023/p/10304932.html


.NET社区新闻,深度好文,欢迎访问公众号文章汇总 http://www.csharpkit.com

640?wx_fmt=jpeg


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/317608.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

cf1512 G - Short Task

cf1512 G - Short Task 题意&#xff1a; 给一个c&#xff0c;求n&#xff0c;使得n的因数和为c 题解&#xff1a; 求因数和的裸题 我们直接预处理所有数的因数和 筛法求因数和 讲解博客 代码&#xff1a; 埃式筛nloglog&#xff08;1e7&#xff09; 1500ms #include<…

AT2675 [AGC018F] Two Trees (构造+二分图染色+并查集)

description 戳我看题目 solution 正解说是欧拉回路&#xff0c;但是于私而言非常难懂&#xff0c;如果有兴趣可以看香香mm的博客 定义一个点如果有偶数个儿子&#xff0c;就为奇点&#xff1b;如果有奇数个儿子&#xff0c;就为偶点 对于一个点的每个子树自身是满足mod21mo…

YbtOJ-连通的图【结论,线性基】

正题 题目大意 给出nnn个点nk−1nk-1nk−1条边的一张图&#xff0c;求有多少种删除若干条边的方案使得图依旧联通。 1≤n≤105,1≤k≤101\leq n\leq 10^5,1\leq k\leq 101≤n≤105,1≤k≤10 解题思路 注意到kkk很小&#xff0c;我们考虑先搞出一棵dfsdfsdfs树然后剩下的做非树…

模板:容斥优化多重方案背包

所谓容斥优化多重方案背包&#xff0c;就是利用容斥去优化统计方案的多重背包 &#xff08;逃&#xff09; 前言 考场上因为不会这个玩意活活把100分正解挂成了70 qwq 思想还是很妙的 就是先当完全背包做&#xff0c;然后扣去多统计的情况 注意扣去的使用k1个i的方案数是上一…

如何定义开发完成?(Definition of Done)

最近在拜读郑晔的10x程序员工作法&#xff0c;收益良多&#xff0c;文中提出一个概念叫DoD&#xff08;Definition of Done&#xff09;给我的感触颇深。这让我联想到实际工作过程中&#xff0c;经常遇到的扯皮、争吵等各种场景&#xff0c;其实就和这个DoD分不开。一、场景描述…

【正睿2021寒假省选第二轮集训 day 1】串 (后缀自动机+记忆化)

description 定义一个字符串的子串是这个字符串的某个连续区间的字符组成的串。比如&#xff0c;“djq"的子串是"d”,“j”,“q”,“dj”,“jq”,和"djq"。 定义F(a,b)为最长在字符串bb中至少出现一次的字符串a的子串&#xff0c;例如&#xff1a; F(“d…

YbtOJ-序列计数【组合数学,莫队】

正题 题目大意 求有多少个长度在l,rl,rl,r之间&#xff0c;值域是[1,n][1,n][1,n]的严格上升子序列 1≤T,n≤105,1≤l≤r≤1051\leq T,n\leq 10^5,1\leq l\leq r\leq 10^51≤T,n≤105,1≤l≤r≤105 解题思路 先转换成两个前缀和的差&#xff0c;那么相当于我们要快速求 ∑i0m…

欧拉筛法的应用

[数论]-----欧拉筛法的应用 文章目录1.求1~n之间的所有质数2.求1~n之间所有自然数的欧拉函数φ&#xff08;x&#xff09;3.求1~n之间的每个数的因子个数详细推导&#xff1a;代码&#xff1a;4.求1~n之间每个数的因数和详细的推导&#xff1a;代码&#xff1a;筛法求莫比乌斯函…

P5787 二分图 /【模板】线段树分治(线段树分治、并查集)

关于什么是合理的实现 解析 本题把并查集写在了题面上 然而&#xff0c;我却一直沉浸在一个及其通用的判断二分图的方法中&#xff1a; 一个图是二分图的充要条件是它没有奇环 怎么维护这个玩意&#xff1f;带权并查集&#xff01; 怎么套线段树分治&#xff1f;可持久化&…

全新尝试|ComponentOne WinForm和.NET Core 3.0

在微软 Build 2018 开发者大会上&#xff0c;.NET 团队公布了 .NET Core 的下一个主要版本 .NET Core 3.0 的规划蓝图&#xff1a;.NET Core 3将开始支持 Windows 桌面应用程序&#xff0c;包括 Windows Form、Windows Presentation Framework&#xff08;WPF&#xff09;和UWP…

[bzoj3625][Codeforces Round #250]小朋友和二叉树 (生成函数)

description 我们的小朋友很喜欢计算机科学&#xff0c;而且尤其喜欢二叉树。 考虑一个含有n个互异正整数的序列c[1],c[2],…,c[n]。如果一棵带点权的有根二叉树满足其所有顶点的权值都在集合{c[1],c[2],…,c[n]}中&#xff0c;我们的小朋友就会将其称作神犇的。并且他认为&am…

11.9模拟:总结

140pts 30100100 qwq 昨天有点被“写完这题就睡”坑到 所以今天状态不太好&#xff1f; 努力给自己找理由.jpg 最大的损失应该就是T1被降智了吧 那其实才是本场最水的一题 看到1e18的数据范围应该刻意往矩乘上想一想的 但我出门就走错了路 利用杨辉三角推了个大式子 从推出那个…

H - Tunnel Warfare HDU - 1540

H - Tunnel Warfare HDU - 1540 题意&#xff1a; n个数顺序排列&#xff0c;左右数相连&#xff0c; 现在有三个操作&#xff1a; 1.摧毁一个位置上的数 2.回复上一次摧毁的数 3.查询包含该位置的最长连续区间长度 题解&#xff1a; 有两个方法&#xff0c;第一个是区间的…

CF802C-Heidi and Library(hard)【费用流】

正题 题目链接:https://www.luogu.com.cn/problem/CF802C 题目大意 你有一个可以放kkk本书的书架&#xff0c;第iii天要求书架上有第aia_iai​种书&#xff0c;购买第iii种书的价格为cic_ici​。 求满足nnn天要求的最小花费。 1≤n,k≤80,1≤ci≤1061\leq n,k\leq 80,1\leq …

2019年1月已到,Java 8 要收费了吗?

根据此前开源中国发起的 Java 版本使用调查&#xff0c;国内的 Java 主力版本仍是 Java 8&#xff0c;有近 70% 的用户表示仍在使用 Java 8。所以对于「Java 8 是否要收费」这个问题&#xff0c;十分有必要阐述清楚&#xff0c;以消除不必要的恐慌。首先要明确一点&#xff0c;…

[NOI2007] 货币兑换 (dp+李超树维护凸包)

description 小Y最近在一家金券交易所工作。该金券交易所只发行交易两种金券&#xff1a;A纪念券&#xff08;以下简称A券&#xff09;和 B纪念券&#xff08;以下简称B券&#xff09;。每个持有金券的顾客都有一个自己的帐户。金券的数目可以是一个实数。每天随着市场的起伏波…

CF1379F1 Chess Strikes Back (easy version)(鸽笼原理、线段树)

解析 很神奇的一道题 关键在于把22的正方形看成一个单位的转化 由于每个22最多有一个国王 因此每个2*2都一定有一个国王 这是本题的关键 个人感觉这个思想很像鸽笼原理 至于后面的线段树就水到渠成了 代码 #include<bits/stdc.h> using namespace std; #define ll l…

[ZJOI2008]树的统计

[ZJOI2008]树的统计 题意&#xff1a; 题解&#xff1a; 树链剖分模板题&#xff0c;好久没打都忘了 代码&#xff1a; #include <algorithm> #include <cstdio> #include <cstring> #define lc o << 1 #define rc o << 1 | 1 const int max…

AT3860-[AGC020F]Arcs on a Circle【dp】

正题 题目链接:https://www.luogu.com.cn/problem/AT3860 题目大意 有一个周长为mmm的圆&#xff0c;nnn条线段&#xff0c;第iii条长度为aia_iai​&#xff0c;将线段贴在圆的随机位置上&#xff0c;求整个圆都被覆盖的概率。 1≤n≤6,1≤m≤501\leq n\leq 6,1\leq m\le 501…

带你学习AOP框架之Aspect.Core[1]

在软件业&#xff0c;AOP为Aspect Oriented Programming的缩写&#xff0c;意为&#xff1a;面向切面编程&#xff0c;通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续&#xff0c;是软件开发中的一个热点&#xff0c;是函数式编程的一种衍生…