一致性哈希库
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

137 lines
2.7 KiB

  1. package hashring
  2. import (
  3. "crypto/sha1"
  4. "sync"
  5. // "hash"
  6. "math"
  7. "sort"
  8. "strconv"
  9. )
  10. const (
  11. //DefaultVirualSpots default virual spots
  12. DefaultVirualSpots = 400
  13. )
  14. type node struct {
  15. nodeKey string
  16. spotValue uint32
  17. }
  18. type nodesArray []node
  19. func (p nodesArray) Len() int { return len(p) }
  20. func (p nodesArray) Less(i, j int) bool { return p[i].spotValue < p[j].spotValue }
  21. func (p nodesArray) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
  22. func (p nodesArray) Sort() { sort.Sort(p) }
  23. //HashRing store nodes and weigths
  24. type HashRing struct {
  25. virualSpots int
  26. nodes nodesArray
  27. weights map[string]int
  28. mu sync.RWMutex
  29. }
  30. //NewHashRing create a hash ring with virual spots
  31. func NewHashRing(spots int) *HashRing {
  32. if spots == 0 {
  33. spots = DefaultVirualSpots
  34. }
  35. h := &HashRing{
  36. virualSpots: spots,
  37. weights: make(map[string]int),
  38. }
  39. return h
  40. }
  41. //AddNodes add nodes to hash ring
  42. func (h *HashRing) AddNodes(nodeWeight map[string]int) {
  43. h.mu.Lock()
  44. defer h.mu.Unlock()
  45. for nodeKey, w := range nodeWeight {
  46. h.weights[nodeKey] = w
  47. }
  48. h.generate()
  49. }
  50. //AddNode add node to hash ring
  51. func (h *HashRing) AddNode(nodeKey string, weight int) {
  52. h.mu.Lock()
  53. defer h.mu.Unlock()
  54. h.weights[nodeKey] = weight
  55. h.generate()
  56. }
  57. //RemoveNode remove node
  58. func (h *HashRing) RemoveNode(nodeKey string) {
  59. h.mu.Lock()
  60. defer h.mu.Unlock()
  61. delete(h.weights, nodeKey)
  62. h.generate()
  63. }
  64. //UpdateNode update node with weight
  65. func (h *HashRing) UpdateNode(nodeKey string, weight int) {
  66. h.mu.Lock()
  67. defer h.mu.Unlock()
  68. h.weights[nodeKey] = weight
  69. h.generate()
  70. }
  71. func (h *HashRing) generate() {
  72. var totalW int
  73. for _, w := range h.weights {
  74. totalW += w
  75. }
  76. totalVirtualSpots := h.virualSpots * len(h.weights)
  77. h.nodes = nodesArray{}
  78. for nodeKey, w := range h.weights {
  79. spots := int(math.Floor(float64(w) / float64(totalW) * float64(totalVirtualSpots)))
  80. for i := 1; i <= spots; i++ {
  81. hash := sha1.New()
  82. hash.Write([]byte(nodeKey + ":" + strconv.Itoa(i)))
  83. hashBytes := hash.Sum(nil)
  84. n := node{
  85. nodeKey: nodeKey,
  86. spotValue: genValue(hashBytes[6:10]),
  87. }
  88. h.nodes = append(h.nodes, n)
  89. hash.Reset()
  90. }
  91. }
  92. h.nodes.Sort()
  93. }
  94. func genValue(bs []byte) uint32 {
  95. if len(bs) < 4 {
  96. return 0
  97. }
  98. v := (uint32(bs[3]) << 24) | (uint32(bs[2]) << 16) | (uint32(bs[1]) << 8) | (uint32(bs[0]))
  99. return v
  100. }
  101. //GetNode get node with key
  102. func (h *HashRing) GetNode(s string) string {
  103. h.mu.RLock()
  104. defer h.mu.RUnlock()
  105. if len(h.nodes) == 0 {
  106. return ""
  107. }
  108. hash := sha1.New()
  109. hash.Write([]byte(s))
  110. hashBytes := hash.Sum(nil)
  111. v := genValue(hashBytes[6:10])
  112. i := sort.Search(len(h.nodes), func(i int) bool { return h.nodes[i].spotValue >= v })
  113. if i == len(h.nodes) {
  114. i = 0
  115. }
  116. return h.nodes[i].nodeKey
  117. }