一致性哈希库
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.

118 lines
2.2 KiB

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