写点什么

架構師訓練營第 1 期 - 第 05 周作業

用户头像
Panda
关注
发布于: 2020 年 10 月 26 日

1.用你熟悉的编程语言实现一致性 hash 算法

import hashlibimport randomimport statistics as stats
def _getVirtualNodes(number): samples = random.sample(range(0, 0xffffffff), number) return samples
def _hash(key): hashcode = int(hashlib.md5(key.encode('utf-8')).hexdigest(), 16) & 0xffffffff return hashcode
def _findInRing(item, ring): length = len(ring) middle = length // 2
if item > ring[-1] or item < ring[0]: return ring[0] if item == ring[middle - 1]: return ring[middle - 1] if item == ring[middle]: return ring[middle] if item < ring[middle - 1]: return _findInRing(item, ring[0: middle]) if item > ring[middle]: return _findInRing(item, ring[middle + 1:])
return ring[middle]
class Node: def __init__(self, name, virtualSets): self._name = name self._virtualNodes = virtualSets self._accessCounter = 0
def access(self): self._accessCounter += 1
def getVirtualNodeSet(self): return self._virtualNodes
def getAmount(self): return self._accessCounter
class ConsistencyHash: def __init__(self, virtualNodeNum = 0): self._virtualNodeNum = virtualNodeNum self._nodeList = [] self._nodes = dict() self._virtulaNodeMap = dict() self._totalNodes = set() self._ring = []
def _print(self): print('Node: {}'.format(self._nodeList)) print('vMap: {}'.format(self._virtulaNodeMap)) print('total: {}'.format(self._totalNodes)) print('ring: {}'.format(self._ring)) self._printAccess()
def _printTotalNodes(self): print('Total: {}'.format(len(self._totalNodes))) def _printAccess(self): for item in self._nodeList: node = self._nodes[item] print('{} : {}'.format(node._name, node._accessCounter))
def addNode(self, node): virtualNodes = _getVirtualNodes(self._virtualNodeNum + 1) for item in virtualNodes: self._virtulaNodeMap[item] = node
self._nodes[node] = Node(node, set(virtualNodes)) self._nodeList.append(node) self._totalNodes = self._totalNodes | set(virtualNodes) self._ring = sorted(self._totalNodes)
def removeNode(self, node):
if not node in self._nodeList: return removeSet = self._nodes[node].getVirtualNodeSet()
for key in removeSet: del self._virtulaNodeMap[key]
self._totalNodes = self._totalNodes - removeSet self._ring = sorted(self._totalNodes) del self._nodes[node] self._nodeList.remove(node)
def access(self, key): hashCode = _hash(key) whichNode = _findInRing(hashCode, self._ring) node = self._virtulaNodeMap[whichNode] self._nodes[node].access()
def calculateSTD(self): valueList = [] for item in self._nodeList: valueList.append(self._nodes[item]._accessCounter)
stdev = stats.stdev(valueList) return stdev
if __name__ == '__main__':
random.seed(1000) virtualNodeNum = [0, 50, 100, 150, 200, 250, 300] NodeNumber = 10 testTimes = 1000000
for item in virtualNodeNum:
print("Virtual Node Number: {}".format(item)) chash = ConsistencyHash(item)
for node in range(0, NodeNumber): chash.addNode("Node" + str(node))
chash._printTotalNodes() for times in range(0, testTimes): chash.access("key" + str(times)) chash._printAccess() stdev = chash.calculateSTD() print("std: {}\n".format(stdev))
复制代码
  • class Node : 紀錄服務器節點資訊

  • 紀錄被訪問的次數

  • 紀錄所有虛擬節點的值

  • class ConsistencyHash 實作一致性 hash 演算法

  • 在建構式代入需額外產生虛擬節點的個數

  • 在 0 ~ (2^32 - 1) 範圍內隨機產生虛擬節點的值

  • 不用 hash function 產生

  • 利用隨機取 sample 應該能分布更平均

  • 建立一個 dictionary (self._virtulaNodeMap) 來映射虛擬節點到真正節點

  • 虛擬節點的值當 Key

  • 真正節點的名稱(IP 或者 唯一值均可)當 value

  • 建立一個 dictionary (self._nodes) 來映射真正節點名稱到真正節點資訊(Node)

  • 真正節點名稱當 Key

  • Node object 當 value

  • addNode()

  • 產生需要的虛擬節點值

  • 建立虛擬節點到真正節點的映射關係

  • 將其加入一個 set 中 (self._totalNodes)

  • 在將此 set 排序,並把排序結果存入 self._ring 中

  • removeNode()

  • 反 AddNode() 其道而行

  • access()

  • 利用 _hash() 求 Key 的 hash code

  • 利用 _findInRing() 查找最近的虛擬節點值

  • 由最近的虛擬節點值及 self._virtulaNodeMap 找到真正節點的名稱

  • 由真正節點的名稱及 self._nodes 真正節點的 object

  • 在由真正節的 object 紀錄訪問次數

  • calculateSTD()

  • 計算標準差

2.编写测试用例测试这个算法,测试 100 万 KV 数据,10 个服务器节点的情况下,计算这些 KV 数据在服务器上分布数量的标准差,以评估算法的存储负载不均衡性。

  • 測試程式分別利用不同的虛擬節點個數來看標準差的變化

  • 由 0 至 300,每隔 50 個測一次

  • 可以看到結果是越多虛擬節點,標準差有漸漸下降的趨勢

  • 各真正節點被訪問的次數漸漸接近平均值

  • 表示虛擬節點真的會幫助平衡訪問各個真正節點的次數

  • 結果輸出

Virtual Node Number: 0Total: 10Node0 : 16943Node1 : 35334Node2 : 201906Node3 : 90880Node4 : 36281Node5 : 40391Node6 : 187821Node7 : 284787Node8 : 39047Node9 : 66610std: 91803.1902144776
Virtual Node Number: 50Total: 510Node0 : 83331Node1 : 84561Node2 : 97911Node3 : 111888Node4 : 106906Node5 : 102734Node6 : 97407Node7 : 100956Node8 : 120820Node9 : 93486std: 11549.97123613542
Virtual Node Number: 100Total: 1010Node0 : 95377Node1 : 112775Node2 : 101001Node3 : 99933Node4 : 103810Node5 : 107343Node6 : 100501Node7 : 90792Node8 : 89866Node9 : 98602std: 7021.440323909492
Virtual Node Number: 150Total: 1510Node0 : 99590Node1 : 97402Node2 : 100919Node3 : 95228Node4 : 107010Node5 : 82151Node6 : 93076Node7 : 114068Node8 : 99885Node9 : 110671std: 9177.236427402557
Virtual Node Number: 200Total: 2010Node0 : 95526Node1 : 104073Node2 : 95615Node3 : 93491Node4 : 96833Node5 : 102843Node6 : 104968Node7 : 103629Node8 : 97838Node9 : 105184std: 4542.5471807003705
Virtual Node Number: 250Total: 2510Node0 : 92298Node1 : 102988Node2 : 99222Node3 : 101529Node4 : 94474Node5 : 108023Node6 : 104040Node7 : 99544Node8 : 97332Node9 : 100550std: 4595.25767624745
Virtual Node Number: 300Total: 3010Node0 : 110876Node1 : 102029Node2 : 104024Node3 : 93199Node4 : 103776Node5 : 107025Node6 : 94396Node7 : 92084Node8 : 101545Node9 : 91046std: 6872.555791778712
复制代码


发布于: 2020 年 10 月 26 日阅读数: 29
用户头像

Panda

关注

还未添加个人签名 2015.06.29 加入

还未添加个人简介

评论

发布
暂无评论
架構師訓練營第 1 期 - 第 05 周作業