golang实现一致性哈希算法

谈谈一致性哈希算法及其 Golang 实现(含负载均衡算法概述) 文章目录一、概述二、负载均衡算法2.1 概述2.2 轮询算法2.3 随机算法2.4 随机轮询算法2.5 加权轮询算法2.6 哈希算法三、一致性哈希算法3.1 适用场景3.2 算法思想四、代码实现(Golang)4.1 主要属性和函数4.2 使用方法4.3 存在的问题五、源码地址六、内容总结 一、概述   本篇博文我们将会谈一谈一些的常见负载均衡算法,然后重点讨论一下 一致性哈希算法 的适用范围和算... 阅读详情
package main


import (
	"crypto/sha1"
	"sync"
	"math"
	"sort"
	"strconv"
	"fmt"
)

const (
	node1 = "192.168.1.1"
	node2 = "192.168.1.2"
	node3 = "192.168.1.3"
)


const (
	//DefaultVirualSpots default virual spots
	DefaultVirualSpots = 400
)

//节点信息
type node struct {
	nodeKey   string    //节点的key
	spotValue uint32  //节点的槽位值
}

type nodesArray []node

func (p nodesArray) Len() int           { return len(p) }
func (p nodesArray) Less(i, j int) bool { return p[i].spotValue < p[j].spotValue }
func (p nodesArray) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }
func (p nodesArray) Sort()              { sort.Sort(p) }

//HashRing store nodes and weigths
type HashRing struct {
	virualSpots int   //虚拟节点
	nodes       nodesArray  //节点数组(槽位)
	weights     map[string]int  //节点信息对应其权重
	mu          sync.RWMutex
}

//NewHashRing create a hash ring with virual spots
//初始化Hash环
func NewHashRing() *HashRing {
	spots := DefaultVirualSpots

	h := &HashRing{
		virualSpots: spots,
		weights:     make(map[string]int),
	}
	return h
}

//AddNodes add nodes to hash ring
//用于向hash环中添加节点信息nodes
func (h *HashRing) AddNodes(nodeWeight map[string]int) {
	h.mu.Lock()
	defer h.mu.Unlock()
	for nodeKey, w := range nodeWeight {
		h.weights[nodeKey] = w
	}
	h.generate()
}

//AddNode add node to hash ring
//向hash环中添加一个节点信息
func (h *HashRing) AddNode(nodeKey string, weight int) {
	h.mu.Lock()
	defer h.mu.Unlock()
	h.weights[nodeKey] = weight
	h.generate()
}

//RemoveNode remove node
//根据节点的key(nodeKey)从hash环上删除
func (h *HashRing) RemoveNode(nodeKey string) {
	h.mu.Lock()
	defer h.mu.Unlock()
	delete(h.weights, nodeKey)
	h.generate()
}

//UpdateNode update node with weight
//更新hash环上某个节点的信息
func (h *HashRing) UpdateNode(nodeKey string, weight int) {
	h.mu.Lock()
	defer h.mu.Unlock()
	h.weights[nodeKey] = weight
	h.generate()
}



//重新计算并生成hash环中的nodes
func (h *HashRing) generate() {
	var totalW int  //所有节点总的权重
	for _, w := range h.weights {
		totalW += w
	}

	totalVirtualSpots := h.virualSpots * len(h.weights)  //总的虚拟节点(槽位)
	h.nodes = nodesArray{}

	for nodeKey, w := range h.weights {
		spots := int(math.Floor(float64(w) / float64(totalW) * float64(totalVirtualSpots)))  //计算出该节点的槽位数
		for i := 1; i <= spots; i++ { //计算出该节点的hash值并添加到nodes中
			hash := sha1.New()
			hash.Write([]byte(nodeKey + ":" + strconv.Itoa(i)))
			hashBytes := hash.Sum(nil)
			n := node{
				nodeKey:   nodeKey,
				spotValue: genValue(hashBytes[6:10]),
			}
			h.nodes = append(h.nodes, n)
			hash.Reset()
		}
	}
	h.nodes.Sort()  //对nodes进行排序
}

//将bs转成uint32
func genValue(bs []byte) uint32 {
	if len(bs) < 4 {
		return 0
	}
	v := (uint32(bs[3]) << 24) | (uint32(bs[2]) << 16) | (uint32(bs[1]) << 8) | (uint32(bs[0]))
	return v
}


//GetNode get node with key
//根据key获取对应的节点名称
func (h *HashRing) GetNode(s string) string {
	h.mu.RLock()
	defer h.mu.RUnlock()
	if len(h.nodes) == 0 {
		return ""
	}


	hash := sha1.New()
	hash.Write([]byte(s))
	hashBytes := hash.Sum(nil)
	//获取nodes中第一个槽位(节点)的值大于该key对应的hash值的槽位(节点)索引
	i := sort.Search(len(h.nodes), func(i int) bool { return h.nodes[i].spotValue >= genValue(hashBytes) })

	if i == len(h.nodes) {
		i = 0
	}
	return h.nodes[i].nodeKey
}

 

测试函数

func main() {
	nodeWeight := make(map[string]int)
	nodeWeight[node1] = 2
	nodeWeight[node2] = 2
	nodeWeight[node3] = 3

	hash := NewHashRing()

	hash.AddNodes(nodeWeight)

	m := make(map[string]int)

	var nodeMatch string

	for i := 0 ; i < 1000 ; i++ {
		nodeMatch = hash.GetNode(strconv.Itoa(i))
		count  := m[nodeMatch]
		m[nodeMatch] = count+1
	}

	fmt.Println(m)

	fmt.Println("node1 shut down")
	hash.RemoveNode(node1)


	m = make(map[string]int)
	for i := 0 ; i < 1000 ; i++ {
		nodeMatch = hash.GetNode(strconv.Itoa(i))
		count  := m[nodeMatch]
		m[nodeMatch] = count+1
	}

	fmt.Println(m)
}

 

运行结果:

map[192.168.1.1:291 192.168.1.2:276 192.168.1.3:433]
node1 shut down
map[192.168.1.2:393 192.168.1.3:607]

 

从以上运行结果看出请求到各服务的权重和设置的权重是一致的

以上内容主要整理至微服务实战课程,可以微信扫码学习

微服务

 

go语言实现一致性哈希算法(附完整源码) 下面是一个Go语言实现的一致性哈希算法的完整源码,带虚拟节点,支持节点添加、删除、查找,适合分布式缓存、负载均衡等场景。代码清晰易懂,适合学习和实际工程使用。 阅读详情

相关推荐

Golang中实现分布式map的思路

在单机环境中,Go的map类型可以高效存储键值对,但当数据量超过单机内存限制,或需要更高的读写并发能力时,就需要将数据分布到多台机器上,形成“分布式Map”。本文将聚焦如何用Go语言实现一个基础版的分布式Map,覆盖数据分片、节点通信、副本容错等核心功能,不涉及超大规模集群的复杂优化(如跨数据中心同步)。用生活案例解释分布式Map的关键概念(分片、一致性哈希等)用数学公式和Go代码详解一致性哈希算法手把手实现一个包含节点发现、数据分片、副本同步的分布式Map讨论实际应用中的优化方向和挑战。

AI Agent Harness Engineering 886

Golang实现一致性Hash算法

golang实现一致性Hash算法

何忆清风 2062

consistent:一个Go库,该库实现一致性哈希和有界负载的一致性哈希

包装一致 一致性哈希和有界负载的一致性哈希的Golang实现。 一致的哈希示例 package main import ( "log" "github.com/lafikl/consistent" ) func main () { c := consistent . New () // adds the hosts to the ring c . Add ( "127.0.0.1:8000" ) c . Add ( "92.0.0.1:8000" ) // Returns the host that owns `key`. // // As described in https://en.wikipedia.org/wiki/Consistent_hashing // // It returns ErrNoHosts if the ring has no host

Golang 一致性Hash算法实现

❝一致性 hash 算法是在分布式应用中使用广泛。其主要作用是为了解决服务中的热点问题。例如在分布式数据存储,比如Redis缓存集群、有状态的任务作业等,通过其解决请求的热点问题,并且可...

weixin_46825193的博客 775

Power Peofiler Kit II 的功耗工具简单上手入门使用

这里仅仅简单记录一下Power Peofiler Kit II 的简单使用,使之快速上手使用起来。官网说明:https://www.nordicsemi.cn/tools/ppk2/上位机软件默认你已经下载好了。

久新的博客 2185

学习心得——COMSOL Multiphysics with MATLAB联合仿真及寻优计算

学习心得——COMSOL Multiphysics with MATLAB联合仿真及寻优计算

weixin_41678956的博客 8658

golang分布式缓存项目 Day4 一致性哈希

golang分布式缓存项目 Day4 一致性哈希

m0_62112384的博客 1024

SpringCloud 2025王炸更新!GraalVM原生镜像启动速度提升90%实战

在当今云原生和Serverless架构盛行的时代,应用的启动速度已成为衡量技术栈竞争力的关键指标。传统SpringCloud应用由于依赖JVM的动态类加载、反射等机制,启动时间通常超过30秒,在Kubernetes滚动更新和函数计算场景下成为显著性能瓶颈。2025年,SpringCloud迎来里程碑式更新,通过深度集成GraalVM原生镜像技术,实现了启动速度提升90%的惊人突破,让SpringCloud应用正式进入"秒级启动"时代。

小筱在线博客 1100

数据结构STL——golang实现一致性哈希consistentHash

github仓库存储地址:https://github.com/hlccd/goSTL 概述 ​ 一致性哈希(consistent hash),与一致性哈希相对的是不一致性哈希,但常见的所有的哈希几乎都是不一致的,即哈希桶的容量的不固定的,可以根据需求进行扩容和缩容,不一致性哈希可以提高空间的利用率,但相应的,当进行扩容和缩容操作时需要对桶内存储的所有元素重新计算哈希值,这在某些情况是十分麻烦的事情,特别是在分布式存储的环境下,此时每个哈希结点就相当于一个机器,文件分布在哪台机器由哈希算法来决定,这个系统

l2975的博客 830

python爬取《你好, 李焕英》豆瓣评论数据

# 导入工具包 import requests from bs4 import BeautifulSoup import time import pandas as pd import numpy as np # 请求头 headers={'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.190 Safari/537.36'} # =

python技巧分享 3457

git连接华为软件开发云

我用的是github客户端的git shell 连接。用git bash也可以github客户端下载地址:https://desktop.github.com/1.在华为软件开发云上创建代码仓库2.在本地创建密钥SSH密钥帮助文档公钥是代码托管服务(CodeHub)识别您的用户身份的一种认证方式,通过公钥,您可以将本地git项目与代码托管服务(CodeHub)建立联系, 然后您就可以很方便的将本地...

sigmeta的博客 2114

Golang 实现集群与一致性 Hash

单台服务器的CPU和内存等资源总是有限的,随着数据量和访问量的增加单台服务器很容易遇到瓶颈。利用多台机器建立分布式系统,分工处理是提高系统容量和吞吐量的常用方法。使用更多机器来提高系统容量的方式称为系统横向扩容。与之相对的,提高单台机器性能被称为纵向扩容。由于无法在单台机器上无限提高硬件配置且硬件价格与性能的关系并非线性的,所以建立分布式系统进行横向扩容是更为经济实用的选择。我们采用一致性 hash 算法 key 分散到不同的服务器,客户端可以连接到服务集群中任意一个节点。

金戈鐡馬 656

S7-1200g2运动控制实战:从轴组配置到程序调试

本文详细介绍了S7-1200g2运动控制功能的实战应用,从轴组配置到程序调试的全流程。通过TIA Portal中的工艺对象配置,实现单轴、同步轴组等运动控制模型,并分享常见问题排查与性能优化经验,帮助工程师快速掌握中小型自动化设备的运动控制技术。

weixin_28698059的博客 591

27.4 一致性哈希算法的golang实现和迁移率测试

circle map[uint32]string // 索引和key的mapmembers map[string]bool // 快速查找key的setsortedHashes uints // 索引的有序数组replicas int // 虚拟节点数count int64 // 节点总数sync.RWMutex // 读写锁一致性哈希算法的golang实现使用uint32封装索引排序的结构定义一致性哈希环数据结构选择哈希函数完成Add、Remove、Get方法。

福大大架构师每日一题 991

看完这篇你就能讲解LLC软开关:一文秒懂 ZVS 和 ZCS 到底啥意思!

想要 MOS 管ZVS 好实现➜ 把工作频率保持在 fr1 或更高。想让整流二极管也ZCS 实现➜ 频率就别高过 fr1。设计磁性元件时,一定要计算好 Lr、Lm、Cr 的值,这直接决定你 fr、fr1 是多少!LLC 的软开关技术不是“魔法”,是电感电容+频率控制的精妙组合;fr1 就像黄金分割点,整流和开关都能“刚刚好”;不是所有软开关都能同时实现,要看你在频率曲线的哪一段!

weixin_43199439的博客 1546

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

一致性哈希算法 mysql_一致性哈希算法 CARP 原理解析, 附 Golang 实现

一致性哈希算法 CARP 原理解析, 附 Golang 实现在后端服务开发的过程中, 遇到了这样一个问题: 需要在 mysql 前面部署 redis 做一层缓存, 要求 redis 是集群部署, 并且每台 redis 节点只缓存总数据量的 1/N, N 为 redis 的个数.看到这里大家都能想到到一个方法是使用 hash(key)%N 来选取 redis 进行 value 的存取, 这种方式当然...

weixin_32018379的博客 323

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

golang 实现一致性哈希算法

golang 实现一致性哈希算法

phone1126的专栏 529

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

GoLang实现一致性哈希算法

直接上代码,windows7,go1.7下直接运行。package mainimport ( "fmt" "sort" "strconv" "hash/crc32" "sync" )const DEFAULT_REPLICAS = 160type HashRing []uint32func (c HashRing) Len() int { return

xiongwenwu的专栏 2921

Go实现一致性哈希算法

想象有一个圆,该圆由 2^32 个数字点组成,这样的环也叫做 哈希环。再假设有3个服务器 a, b, c,此时分别对 a,b,c 服务器进行哈希计算再用 2^32 取模,那结果肯定能对应到环上的某个点。再用同样的方法,对需要缓存的图片进行哈希计算和取模,也肯定能对应到环上的某个点。此时,按顺时针方向找,找到的第一个缓存服务器,就将该图片数据缓存到该服务器上。

哥斯拉啊啊啊哦的博客 713

go语言实现一致性哈希算法(附带源码)

go语言实现一致性哈希算法(附带源码)

欢迎来到我的博客!这里是一个专注于计算机技术的分享平台,涵盖编程开发、算法研究、系统架构、软件工程等多个领域。无论你是初学者还是资深开发者,都能在这里找到有价值的内容。 1715

一致性哈希算法和Go语言实现

一致性哈希算法,当我第一次听到这个名字的时候,感觉特别高深。而它往往会和分布式系统相关,准确的说,是分布式缓存。 在Web服务中,缓存是介于数据库和服务端程序之间的一个东西。在网站的业务还不是很大的时候,一般不会需要这个东西,每次都可以从数据库中查询获得数据,但是随着网站的访问量增大,每次请求都访问数据库的话,数据库的压力就会非常大,导致响应变慢,于是就需要一种缓存数据库,它们的存储结构一般比较...

weixin_34037515的博客 220

【亲测免费】 Maglev: Google Maglev 哈希算法的 Golang 实现

Maglev: Google Maglev 哈希算法的 Golang 实现 项目基础介绍和主要编程语言 Maglev 是一个由 Google 开发的网络负载均衡器,它是一个运行在普通 Linux 服务器上的大型分布式软件系统。与传统的硬件网络负载均衡器不同,Maglev 不需要专门的物理机架部署,其容量可以通过添加或移除服务器轻松调整。该项目是 Google Maglev 哈希算法的 Golang...

gitblog_01046的博客 484

一致性哈希算法 CARP 原理解析, 附 Golang 实现

一致性哈希算法 CARP 原理解析, 附 Golang 实现 在后端服务开发的过程中, 遇到了这样一个问题: 需要在 mysql 前面部署 redis 做一层缓存, 要求 redis 是集群部署, 并且每台 redis 节点只缓存总数据量的 1/N, N 为 redis 的个数. 看到这里大家都能想到到一个方法是使用 hash(key)%...

weixin_34324081的博客 346
上一篇: 图解一致性哈希算法的基本原理
下一篇: Golang基于etcd实现服务注册和发现功能
思维的深度
博客等级 码龄11年 2万+粉丝 391原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值