三分鐘看懂一致性哈希算法

?

一致性哈希算法,作為分布式計算的數據分配參考,比傳統的取模,劃段都好很多。

在電信計費中,可以作為多臺消息接口機和在線計費主機的分配算法,根據session_id來分配,這樣當計費主機動態伸縮的時候,因為session_id緩存缺失而需要放通的會話,會明顯減少。

?

傳統的取模方式

?

例如10條數據,3個節點,如果按照取模的方式,那就是

node a: 0,3,6,9

node b: 1,4,7

node c: 2,5,8

?

當增加一個節點的時候,數據分布就變更為

node a:0,4,8

node b:1,5,9

node c: 2,6

node d: 3,7

?

總結:數據3,4,5,6,7,8,9在增加節點的時候,都需要做搬遷,成本太高

?

一致性哈希方式

最關鍵的區別就是,對節點和數據,都做一次哈希運算,然后比較節點和數據的哈希值,數據取和節點最相近的節點做為存放節點。這樣就保證當節點增加或者減少的時候,影響的數據最少。

還是拿剛剛的例子,(用簡單的字符串的ascii碼做哈希key):

十條數據,算出各自的哈希值

0:192

1:196

2:200

3:204

4:208

5:212

6:216

7:220

8:224

9:228

?

有三個節點,算出各自的哈希值

node a: 203

node g: 209

node z: 228

?

這個時候比較兩者的哈希值,如果大于228,就歸到前面的203,相當于整個哈希值就是一個環,對應的映射結果:

node a: 0,1,2

node g: 3,4

node z: 5,6,7,8,9

?

這個時候加入node n, 就可以算出node n的哈希值:

node n: 216

?

這個時候對應的數據就會做遷移:

node a: 0,1,2

node g: 3,4

node n: 5,6

node z: 7,8,9

?

這個時候只有5和6需要做遷移

另外,這個時候如果只算出三個哈希值,那再跟數據的哈希值比較的時候,很容易分得不均衡,因此就引入了虛擬節點的概念,通過把三個節點加上ID后綴等方式,每個節點算出n個哈希值,均勻的放在哈希環上,這樣對于數據算出的哈希值,能夠比較散列的分布(詳見下面代碼中的replica)

?

通過這種算法做數據分布,在增減節點的時候,可以大大減少數據的遷移規模。

?

下面轉載的哈希代碼,已經將gen_key改成上述描述的用字符串ascii相加的方式,便于測試驗證。

?

?

 
  1. import md5

  2. class HashRing(object):

  3. def __init__(self, nodes=None, replicas=3):

  4. """Manages a hash ring.

  5. `nodes` is a list of objects that have a proper __str__ representation.

  6. `replicas` indicates how many virtual points should be used pr. node,

  7. replicas are required to improve the distribution.

  8. """

  9. self.replicas = replicas

  10. self.ring = dict()

  11. self._sorted_keys = []

  12. if nodes:

  13. for node in nodes:

  14. self.add_node(node)

  15. def add_node(self, node):

  16. """Adds a `node` to the hash ring (including a number of replicas).

  17. """

  18. for i in xrange(0, self.replicas):

  19. key = self.gen_key('%s:%s' % (node, i))

  20. print "node %s-%s key is %ld" % (node, i, key)

  21. self.ring[key] = node

  22. self._sorted_keys.append(key)

  23. self._sorted_keys.sort()

  24. def remove_node(self, node):

  25. """Removes `node` from the hash ring and its replicas.

  26. """

  27. for i in xrange(0, self.replicas):

  28. key = self.gen_key('%s:%s' % (node, i))

  29. del self.ring[key]

  30. self._sorted_keys.remove(key)

  31. def get_node(self, string_key):

  32. """Given a string key a corresponding node in the hash ring is returned.

  33. If the hash ring is empty, `None` is returned.

  34. """

  35. return self.get_node_pos(string_key)[0]

  36. def get_node_pos(self, string_key):

  37. """Given a string key a corresponding node in the hash ring is returned

  38. along with it's position in the ring.

  39. If the hash ring is empty, (`None`, `None`) is returned.

  40. """

  41. if not self.ring:

  42. return None, None

  43. key = self.gen_key(string_key)

  44. nodes = self._sorted_keys

  45. for i in xrange(0, len(nodes)):

  46. node = nodes[i]

  47. if key <= node:

  48. print "string_key %s key %ld" % (string_key, key)

  49. print "get node %s-%d " % (self.ring[node], i)

  50. return self.ring[node], i

  51. return self.ring[nodes[0]], 0

  52. def print_ring(self):

  53. if not self.ring:

  54. return None, None

  55. nodes = self._sorted_keys

  56. for i in xrange(0, len(nodes)):

  57. node = nodes[i]

  58. print "ring slot %d is node %s, hash vale is %s" % (i, self.ring[node], node)

  59. def get_nodes(self, string_key):

  60. """Given a string key it returns the nodes as a generator that can hold the key.

  61. The generator is never ending and iterates through the ring

  62. starting at the correct position.

  63. """

  64. if not self.ring:

  65. yield None, None

  66. node, pos = self.get_node_pos(string_key)

  67. for key in self._sorted_keys[pos:]:

  68. yield self.ring[key]

  69. while True:

  70. for key in self._sorted_keys:

  71. yield self.ring[key]

  72. def gen_key(self, key):

  73. """Given a string key it returns a long value,

  74. this long value represents a place on the hash ring.

  75. md5 is currently used because it mixes well.

  76. """

  77. m = md5.new()

  78. m.update(key)

  79. return long(m.hexdigest(), 16)

  80. """

  81. hash = 0

  82. for i in xrange(0, len(key)):

  83. hash += ord(key[i])

  84. return hash

  85. """

  86. ?
  87. ?
  88. memcache_servers = ['a',

  89. 'g',

  90. 'z']

  91. ring = HashRing(memcache_servers,1)

  92. ring.print_ring()

  93. server = ring.get_node('0000')

  94. server = ring.get_node('1111')

  95. server = ring.get_node('2222')

  96. server = ring.get_node('3333')

  97. server = ring.get_node('4444')

  98. server = ring.get_node('5555')

  99. server = ring.get_node('6666')

  100. server = ring.get_node('7777')

  101. server = ring.get_node('8888')

  102. server = ring.get_node('9999')

  103. ?
  104. print '----------------------------------------------------------'

  105. ?
  106. memcache_servers = ['a',

  107. 'g',

  108. 'n',

  109. 'z']

  110. ring = HashRing(memcache_servers,1)

  111. ring.print_ring()

  112. server = ring.get_node('0000')

  113. server = ring.get_node('1111')

  114. server = ring.get_node('2222')

  115. server = ring.get_node('3333')

  116. server = ring.get_node('4444')

  117. server = ring.get_node('5555')

  118. server = ring.get_node('6666')

  119. server = ring.get_node('7777')

  120. server = ring.get_node('8888')

  121. server = ring.get_node('9999')


?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/387029.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/387029.shtml
英文地址,請注明出處:http://en.pswp.cn/news/387029.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

數據結構09圖

第七章 圖 Graph 7.1 圖的定義和術語 頂點 Vertex V 是頂點的有窮非空集合&#xff0c;頂點數 |V| n VR 兩個頂點之間關系的集合&#xff0c;邊數 |VR| e 有向圖 Digraph <v, w> Arc v Tail / Inital node w Head / Terminal node 無向圖 Undigraph <v, w> 必…

JVM調優-GC參數

一、Throughput收集器(吞吐量) -XX:UseParallelGC -XX:UseParallelOldGC *參數調整&#xff1a;通過調整堆大小&#xff0c;減少GC停頓時間&#xff0c;增大吞吐量 增強堆大小可以減少Full GC頻率&#xff0c;但卻會增加停頓時間 1.手動調整 -Xmn -Xms -XX:NewRatioN 手動指…

aspnetcore源碼學習(一)

---恢復內容開始--- 筆者從事netcore相關項目開發已經大半年了&#xff0c;從netcore 1.0到現在3.0大概經過了3年左右的時間&#xff0c;記得netcore剛出來的時候國內相關的學習資料缺乏&#xff0c;限制于外語不大熟練的限制國外的相關書籍看起來相當吃力&#xff0c;于是在當…

評估一個垃圾收集(GC)

在實踐中我們發現對于大多數的應用領域&#xff0c;評估一個垃圾收集(GC)算法如何根據如下兩個標準&#xff1a; 吞吐量越高算法越好暫停時間越短算法越好 首先讓我們來明確垃圾收集(GC)中的兩個術語:吞吐量(throughput)和暫停時間(pause times)。 JVM在專門的線程(GC threads…

python數據分析常用包之Scipy

Scipy轉載于:https://www.cnblogs.com/jacky912/p/10697853.html

docker容器狀態跟蹤及疑惑

一、 1 def status_test():2 container client.containers.create("comp")3 print ("create: ", container.status)4 container.start()5 print ("start: ", container.status)6 container.pause()7 print ("paus…

CAP和BASE理論

幾個名詞解釋&#xff1a; 網絡分區&#xff1a;俗稱“腦裂”。當網絡發生異常情況&#xff0c;導致分布式系統中部分節點之間的網絡延時不斷變大&#xff0c;最終導致組成分布式系統的所有節點中&#xff0c;只有部分節點之間能夠進行正常通信&#xff0c;而另一些節點則不能…

Mysql案例5:取得平均薪資最高的部門的部門名稱

一、要求&#xff1a;查詢平均薪水最高部門的部門編號 二、背景&#xff1a;當前數據庫有employee表和department表&#xff0c;數據分別如下&#xff1a; employee表&#xff1a; department表&#xff1a; 三、難點&#xff1a; 1、需要考慮最高平均薪資可能在多個部門同時出…

Spring 處理過程分析

一、處理過程分析 1、首先&#xff0c;Tomcat每次啟動時都會加載并解析/WEB-INF/web.xml文件&#xff0c;所以可以先從web.xml找突破口&#xff0c;主要代碼如下&#xff1a;<servlet ><servlet-name >spring-mvc</servlet-name><!-- servlet類 --><…

python全棧開發中級班全程筆記(第二模塊、第四章)(常用模塊導入)

python全棧開發筆記第二模塊 第四章 &#xff1a;常用模塊&#xff08;第二部分&#xff09; 一、os 模塊的 詳解 1、os.getcwd() &#xff1a;得到當前工作目錄&#xff0c;即當前python解釋器所在目錄路徑 import os j os.getcwd() # 返回當前pyt…

基于 Spring Cloud 完整的微服務架構實戰

本項目是一個基于 Spring Boot、Spring Cloud、Spring Oauth2 和 Spring Cloud Netflix 等框架構建的微服務項目。 作者&#xff1a;Sheldon地址&#xff1a;https://github.com/zhangxd1989 技術棧 Spring boot - 微服務的入門級微框架&#xff0c;用來簡化 Spring 應用的初…

mysql Invalid use of group function的解決辦法

錯誤語句&#xff1a;SELECT s.SID, s.Sname, AVG(a.score)FROM student sLEFT JOIN sc a ON s.SID a.SID WHERE AVG(a.score) > 60GROUP BY s.SID正確語句&#xff1a; SELECTs.SID,s.Sname,AVG(a.score)FROMstudent sLEFT JOIN sc a ON s.SID a.SID GROUP BYs.SID HAVIN…

ipython notebook 中 wavefile, display, Audio的使用

基于ipython notebook的 wavefile以及display, Audio的使用首先是使用的庫使用 wavfile 讀取.wav文件使用display,Audio播放聲音最近在做聲音信號處理的時候&#xff0c;使用了ipython notebook。發現相較于matlab&#xff0c;python在有關生成wave文件和播放音頻需要利用到sci…

spring 設計模式

設計模式作為工作學習中的枕邊書&#xff0c;卻時常處于勤說不用的尷尬境地&#xff0c;也不是我們時常忘記&#xff0c;只是一直沒有記憶。 今天&#xff0c;螃蟹在IT學習者網站就設計模式的內在價值做一番探討&#xff0c;并以spring為例進行講解&#xff0c;只有領略了其設計…

Ansible-----循環

with_dict迭代字典項 使用"with_dict"可以迭代字典項。迭代時&#xff0c;使用"item.key"表示字典的key&#xff0c;"item.value"表示字典的值。 ---- hosts: localhosttasks:- debug: msg"{{item.key}} & {{item.value}}"with_di…

ROS(Robot Operating System)筆記 : 1.使用launch file在gazebo中生成urdf機器人

ROS(Robot Operating System) 1.使用launch file在gazebo中生成urdf機器人 最近接觸了ROS(Robot Operating System),發現單單學習官網http://wiki.ros.org/上的教程&#xff0c;在實際操作過程中仍然會遭遇許多困難。這一系列關于ROS的文章記錄了ROS學習過程中可能遇到的問題…

[asp.net] 利用WebClient上傳圖片到遠程服務

一、客戶端 1.頁面 <form id"Form1" method"post" runat"server" enctype"multipart/form-data">     <input id"MyFile" type"file" runat"server" />     <br />     …

ROS project part 1: Ubuntu中安裝opencv包以及相應的依賴

首先在ubuntu linux上安裝opencv $ sudo apt-get install python-opencv使用ipython 驗證 opencv的安裝 $ import cv2 as cv $ print(cv.__version__)查看當前的ubuntu 版本 $ cat /etc/issue查看當前python版本 下列代碼分別用于查看python3 python2的已安裝版本 $ python…

FastReport4.6程序員手冊_翻譯

一、使用TfrxReport 組件工作1、加載并存儲報表默認情況下&#xff0c;報表窗體同項目窗體構存儲在同一個DFM文件中。多數情況下&#xff0c;無須再操作&#xff0c;因而你就不必采用特殊方法加載報表。如果你決定在文件中存儲報表窗體或者是數據庫的Blob字段&#xff08;他提供…

Python音頻信號處理 1.短時傅里葉變換及其逆變換

短時傅里葉變換及其逆變換 本篇文章主要記錄了使用python進行短時傅里葉變換&#xff0c;分析頻譜&#xff0c;以及通過頻譜實現在頻域內降低底噪的代碼及分析&#xff0c;希望可以給同樣在學習信號處理的大家一點幫助&#xff0c;也希望大家對我的文章多提意見建議。 一. 短…