hashring.go 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. package loadbalancer
  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() *HashRing {
  32. spots := DefaultVirualSpots
  33. h := &HashRing{
  34. virualSpots: spots,
  35. weights: make(map[string]int),
  36. }
  37. return h
  38. }
  39. //AddNodes add nodes to hash ring
  40. func (h *HashRing) AddNodes(nodeWeight map[string]int) {
  41. h.mu.Lock()
  42. defer h.mu.Unlock()
  43. for nodeKey, w := range nodeWeight {
  44. h.weights[nodeKey] = w
  45. }
  46. h.generate()
  47. }
  48. //AddNode add node to hash ring
  49. func (h *HashRing) AddNode(nodeKey string, weight int) {
  50. h.mu.Lock()
  51. defer h.mu.Unlock()
  52. h.weights[nodeKey] = weight
  53. h.generate()
  54. }
  55. //RemoveNode remove node
  56. func (h *HashRing) RemoveNode(nodeKey string) {
  57. h.mu.Lock()
  58. defer h.mu.Unlock()
  59. delete(h.weights, nodeKey)
  60. h.generate()
  61. }
  62. //UpdateNode update node with weight
  63. func (h *HashRing) UpdateNode(nodeKey string, weight int) {
  64. h.mu.Lock()
  65. defer h.mu.Unlock()
  66. h.weights[nodeKey] = weight
  67. h.generate()
  68. }
  69. func (h *HashRing) generate() {
  70. var totalW int
  71. for _, w := range h.weights {
  72. totalW += w
  73. }
  74. totalVirtualSpots := h.virualSpots * len(h.weights)
  75. h.nodes = nodesArray{}
  76. for nodeKey, w := range h.weights {
  77. spots := int(math.Floor(float64(w) / float64(totalW) * float64(totalVirtualSpots)))
  78. for i := 1; i <= spots; i++ {
  79. hash := sha1.New()
  80. hash.Write([]byte(nodeKey + ":" + strconv.Itoa(i)))
  81. hashBytes := hash.Sum(nil)
  82. n := node{
  83. nodeKey: nodeKey,
  84. spotValue: genValue(hashBytes[6:10]),
  85. }
  86. h.nodes = append(h.nodes, n)
  87. hash.Reset()
  88. }
  89. }
  90. h.nodes.Sort()
  91. }
  92. func genValue(bs []byte) uint32 {
  93. if len(bs) < 4 {
  94. return 0
  95. }
  96. v := (uint32(bs[3]) << 24) | (uint32(bs[2]) << 16) | (uint32(bs[1]) << 8) | (uint32(bs[0]))
  97. return v
  98. }
  99. //GetNode get node with key
  100. func (h *HashRing) GetNode(s string) string {
  101. h.mu.RLock()
  102. defer h.mu.RUnlock()
  103. if len(h.nodes) == 0 {
  104. return ""
  105. }
  106. hash := sha1.New()
  107. hash.Write([]byte(s))
  108. hashBytes := hash.Sum(nil)
  109. v := genValue(hashBytes[6:10])
  110. i := sort.Search(len(h.nodes), func(i int) bool { return h.nodes[i].spotValue >= v })
  111. if i == len(h.nodes) {
  112. i = 0
  113. }
  114. return h.nodes[i].nodeKey
  115. }