<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
	<channel>
		<title>算法 on 易哥</title>
		<link>https://yeecode.top/tags/%E7%AE%97%E6%B3%95/</link>
		<description>Recent content in 算法 on 易哥</description>
		<generator>Hugo</generator>
		<language>zh-cn</language>
		
		
		
		
			<lastBuildDate>Sun, 16 Dec 2018 00:00:00 +0000</lastBuildDate>
		
			<atom:link href="https://yeecode.top/tags/%E7%AE%97%E6%B3%95/index.xml" rel="self" type="application/rss+xml" />
			<item>
				<title>一致性Hash算法的缩容扩容分析</title>
				<link>https://yeecode.top/blog/18/</link>
				<pubDate>Sun, 16 Dec 2018 00:00:00 +0000</pubDate>
				<guid>https://yeecode.top/blog/18/</guid>
				<description>&lt;h2 id=&#34;背景&#34;&gt;背景&lt;/h2&gt;&#xA;&lt;p&gt;之前的文章我们已经分析过，一致性Hash算法能够在Hash输出空间发生变化时，引起最小的变动。&lt;/p&gt;&#xA;&lt;p&gt;以上篇文章的例子来讲，增加或者移除一台服务器时，对原有的服务器和用户之间的映射关系产生的影响最小。&lt;/p&gt;&#xA;&lt;p&gt;本文我们讨论使用了一致性Hash算法后，扩容和缩容具体会产生怎样的影响，以及在扩容缩容时应该如何做来减少影响。&lt;/p&gt;&#xA;&lt;h2 id=&#34;扩容分析&#34;&gt;扩容分析&lt;/h2&gt;&#xA;&lt;p&gt;如果扩容增加一台服务器X，如下图：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://yeecode.top/blog/18/pic/203_hu_d41aae35b3b4df32.webp&#34; alt=&#34;图片&#34; width=&#34;741&#34; height=&#34;759&#34; loading=&#34;eager&#34; decoding=&#34;async&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;我们发现，该扩容对对象A、B、D无影响，只有对象C会被重定位到新的Node X。&lt;/p&gt;&#xA;&lt;p&gt;因此，在扩容时，仅仅影响扩容服务器所在的位置的后面一台服务器，原本分配到它身上的请求被分流了，使得它的请求减少。&lt;/p&gt;&#xA;&lt;p&gt;而对于新增加的服务器，接入了其后面一台服务器的部分流量。&lt;/p&gt;&#xA;&lt;p&gt;在实际生产中，使用了一致性Hash算法后，如果需要增加一台服务器X，只需要将其插入位置后面的服务器C的内容拷贝到服务器X上一份即可。&lt;/p&gt;&#xA;&lt;p&gt;更精细化的操作可以将服务器C的数据按照新的Hash输出结果分摊到服务器C和服务器X这两台服务器上，这样可以避免数据冗余，但操作相对繁杂一些。&lt;/p&gt;&#xA;&lt;h2 id=&#34;缩容分析&#34;&gt;缩容分析&lt;/h2&gt;&#xA;&lt;p&gt;假如服务器C被缩容摘除，则对数据对象A、B、D不会产生任何影响。只有C对象被重定位到服务器D上。&lt;/p&gt;&#xA;&lt;p&gt;而事实上，C对象对应的Node C不存在了，因此无论如何C都会受到影响。同时，会对服务器D产生影响，因为原本分配到服务器C上的流量会被转到它的身上，使其压力增大。&lt;/p&gt;&#xA;&lt;p&gt;在具体生产操作中，如果需要缩容服务器C，则需要将该服务器C的内容拷贝到其后面的服务器D上。这样，由服务器C转接过来的流量还可以访问到对应的数据。&lt;/p&gt;</description>
			</item>
			<item>
				<title>什么是一致性Hash算法？</title>
				<link>https://yeecode.top/blog/17/</link>
				<pubDate>Sat, 24 Nov 2018 00:00:00 +0000</pubDate>
				<guid>https://yeecode.top/blog/17/</guid>
				<description>&lt;h2 id=&#34;hash算法&#34;&gt;Hash算法&lt;/h2&gt;&#xA;&lt;p&gt;说起Hash算法，我们都是熟悉的，它是一种摘要算法，即根据原有的内容产生一个简短的摘要结果。摘要结果跟原内容是相关的，原内容的改变（极大概率）会导致摘要内容的改变。这里说的极大概率会改变是因为这取决于该Hash算法的输出空间的大小：输出空间小了，则可能出现改变后的Hash结果与原Hash结果恰好相等的情况；而输出空间越大，上述情况发生的概率则越小。&lt;/p&gt;&#xA;&lt;p&gt;假设输入输出都是一个数字，那么我们可以定义一个简单的Hash算法：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;private final int size = 7;&#xA;&#xA;public int simpleHash(int value) {&#xA;    return value%size;&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;当一个值value输入时，该算法会输出0到6之间的自然数。&lt;/p&gt;&#xA;&lt;h2 id=&#34;hash算法的使用与问题&#34;&gt;Hash算法的使用与问题&lt;/h2&gt;&#xA;&lt;p&gt;Hash算法的使用非常广泛，例如对一段信息生成Hash值后，可以作为校验信息是否发生变更的依据；通过Hash算法，将请求均匀地分配到应用服务器上；使用Hash算法，确保同样的用户总是访问同一个服务器等。&lt;/p&gt;&#xA;&lt;p&gt;但是，Hash算法也存在一定的局限性。例如，我们有0-6共7台服务器，通过我们上一节的Hash算法将用户id(自然数)作为输入，得到一个服务器编号。然后将用户的信息近似均匀地分配到这7台服务器上，从而实现负载均衡。&lt;/p&gt;&#xA;&lt;p&gt;假如这时5号服务器出现故障，我们要将其下线，于是：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;private final int size = 6;&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;这时我们发现，用户id输入后，该Hash算法输出的结果与原来相差极大，使得大量用户无法访问到原来的服务器，这并不是我们想见到的。例如，28号用户，原来28%7=0，映射到0号服务器，现在则映射到了28%6=4，映射到了4号服务器。而原来的0号服务器是存在的，该28号用户应依旧分配到0号服务器才对。&lt;/p&gt;&#xA;&lt;p&gt;当然，随着用户增多，我们增加一台服务器时，也会引发相同的问题。此时一般需要进行重新Hash操作，对各个服务器上的数据进行重新分配，此操作几乎涉及所有服务器上的所有数据，工作量极大。&lt;/p&gt;&#xA;&lt;h2 id=&#34;一致性hash算法&#34;&gt;一致性Hash算法&lt;/h2&gt;&#xA;&lt;p&gt;在分布式系统中，扩容缩容操作极为常见，如果频繁进行重Hash操作显然是不可取的，一是消耗太大，而是可能引发服务的中断。此时，就要采用一致性Hash算法。&lt;/p&gt;&#xA;&lt;p&gt;一致性Hash算法（Consistent Hashing）是一种hash算法，它能够在Hash输出空间发生变化时，引起最小的变动。以我们的例子来讲，增加或者移除一台服务器时，对原有的服务器和用户之间的映射关系产生的影响最小。&lt;/p&gt;&#xA;&lt;p&gt;好的一致性Hash算法应该能够满足以下要求：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;平衡性：这是Hash算法的基本要求，是指哈希的结果均匀地分配在整个输出空间中。&lt;/li&gt;&#xA;&lt;li&gt;单调性：当发生数据节点变动时，对于相同的数据始终映射到相同的缓冲节点中或者新增加的缓冲节点中，避免无法找到原来的数据。&lt;/li&gt;&#xA;&lt;li&gt;稳定性：当出现节点坏掉或热点访问而需要动态扩容时，尽量减少数据的移动。显然一般的Hash方法不满足这一点。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;原理&#34;&gt;原理&lt;/h2&gt;&#xA;&lt;p&gt;一致性哈希算法最早在论文《Consistent Hashing and Random Trees: Distributed Caching Protocols for Relieving Hot Spots on the World Wide Web》中提出。具体思路就是一致性哈希将整个哈希输出空间设置为一个环形区域。例如，该环形区域用数字0-2^32-1表示，沿顺时针方向值不断增大，0与2^32重合。整个哈希空间环如下：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://yeecode.top/blog/17/pic/001_hu_357783e309a80fbd.webp&#34; alt=&#34;图片&#34; width=&#34;537&#34; height=&#34;525&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;接下来，我们将服务器进行Hash。可以使用服务器的编号或者ip等作为输入，得到一个输出值，映射在输出空间的环形区域上。假设它们的位置如下：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://yeecode.top/blog/17/pic/201_hu_ed4f1144147dad9d.webp&#34; alt=&#34;图片&#34; width=&#34;805&#34; height=&#34;795&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;对于用户数据，同样进行Hash操作，映射在环形区域上。然后，让该值沿着顺时针方向移动，遇到的第一个服务器就是它分配的服务器。例如有A、B、C、D四个数据对象，经过一致性哈希计算后，在环空间上的位置如下：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://yeecode.top/blog/17/pic/202_hu_d11fca1816491525.webp&#34; alt=&#34;图片&#34; width=&#34;746&#34; height=&#34;775&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;则根据刚才的规则，数据A会被分配到Node A上，B被分配到Node B上，C被分配到Node C上，D被分配到Node D上。&lt;/p&gt;</description>
			</item>
	</channel>
</rss>
