golang学习笔记20——golang微服务负载均衡的问题与解决方案
- 推荐学习文档
- golang应用级os框架,欢迎star
- golang应用级os框架使用案例,欢迎star
- 案例:基于golang开发的一款超有个性的旅游计划app经历
- golang实战大纲
- golang优秀开发常用开源库汇总
- 想学习更多golang知识,这里有免费的golang学习笔记专栏
文章目录
- 引言
- 负载均衡的基本概念
- 1.什么是负载均衡
- 2.常见的负载均衡算法
- Golang 微服务负载均衡中的问题
- 1.动态服务实例增减
- 2.负载均衡算法的选择与优化
- 3.处理服务实例的故障
- 总结
引言
在微服务架构中,负载均衡是确保系统高性能、高可用性的关键组件。当使用 Golang 构建微服务时,负载均衡的实现也面临着一些挑战和问题。本文将深入探讨这些问题,并结合代码示例展示如何解决。
负载均衡的基本概念
1.什么是负载均衡
负载均衡是将网络流量均匀地分配到多个后端服务实例上的过程。其目的是提高系统的整体性能、可用性和可扩展性。
2.常见的负载均衡算法
- 轮询(Round Robin):按顺序依次将请求分配到各个服务实例。
- 随机(Random):随机选择一个服务实例来处理请求。
- 加权轮询(Weighted Round Robin):根据服务实例的权重分配请求,权重高的实例会获得更多的请求。
- 一致性哈希(Consistent Hashing):根据请求的某些特征(如客户端 IP 等)计算哈希值,将请求分配到对应的服务实例,以减少缓存失效等问题。
Golang 微服务负载均衡中的问题
1.动态服务实例增减
在微服务环境中,服务实例可能会动态地增加或减少,例如由于自动伸缩或者服务故障等原因。传统的静态负载均衡算法无法及时适应这种变化。
- 解决方案
- 使用服务发现机制与负载均衡相结合。当服务实例发生变化时,及时更新负载均衡器中的服务实例列表。
- 代码示例(使用 Go 语言的net/http和简单的服务发现机制):
package mainimport ("log""net/http""sync""time"
)// 服务实例结构体
type ServiceInstance struct {addr string
}// 负载均衡器结构体
type LoadBalancer struct {instances []ServiceInstancemu sync.Mutex
}// 添加服务实例
func (lb *LoadBalancer) AddInstance(addr string) {lb.mu.Lock()defer lb.mu.Unlock()lb.instances = append(lb.instances, ServiceInstance{addr})
}// 删除服务实例
func (lb *LoadBalancer) RemoveInstance(addr string) {lb.mu.Lock()defer lb.mu.Unlock()for i, instance := range lb.instances {if instance.addr == addr {lb.instances = append(lb.instances[:i], lb.instances[i+1:]...)break}}
}// 简单的轮询负载均衡
func (lb *LoadBalancer) RoundRobin() *ServiceInstance {lb.mu.Lock()defer lb.mu.Unlock()if len(lb.instances) == 0 {return nil}instance := lb.instances[0]lb.instances = append(lb.instances[1:], instance)return &instance
}// 模拟服务发现,定期更新服务实例
func (lb *LoadBalancer) ServiceDiscovery() {// 模拟发现新服务实例go func() {for {time.Sleep(5 * time.Second)lb.AddInstance("new-service:8080")}}()// 模拟服务实例下线go func() {for {time.Sleep(10 * time.Second)if len(lb.instances) > 0 {lb.RemoveInstance(lb.instances[0].addr)}}}()
}// 处理请求的函数
func handleRequest(w http.ResponseWriter, r *http.Request) {// 获取负载均衡器实例var lb LoadBalancerinstance := lb.RoundRobin()if instance == nil {log.Println("没有可用的服务实例")w.WriteHeader(http.StatusServiceUnavailable)return}log.Println("将请求转发到", instance.addr)// 这里可以添加实际的转发逻辑
}func main() {// 初始化负载均衡器var lb LoadBalancer// 添加一些初始服务实例lb.AddInstance("service1:8080")lb.AddInstance("service2:8080")// 启动服务发现go lb.ServiceDiscovery()// 启动 HTTP 服务http.HandleFunc("/", handleRequest)log.Fatal(http.ListenAndServe(":8000", nil))
}
2.负载均衡算法的选择与优化
不同的业务场景对负载均衡算法有不同的需求。例如,对于有状态的服务,一致性哈希算法可能更合适;对于无状态的服务,轮询或加权轮询可能就足够了。选择不合适的算法会导致性能瓶颈或者资源浪费。
- 解决方案
- 根据服务的特性(如是否有状态、处理能力等)和业务需求(如响应时间要求、吞吐量要求等)选择合适的负载均衡算法。
- 对负载均衡算法进行优化。例如,在加权轮询中,可以根据服务实例的实时负载动态调整权重。
- 以下是一个加权轮询的优化示例:
package mainimport ("log""math/rand""sync""time"
)// 加权服务实例结构体
type WeightedServiceInstance struct {addr stringweight intcurrent int
}// 加权负载均衡器结构体
type WeightedLoadBalancer struct {instances []WeightedServiceInstancemu sync.Mutex
}// 添加加权服务实例
func (wl *WeightedLoadBalancer) AddInstance(addr string, weight int) {wl.mu.Lock()defer wl.mu.Unlock()wl.instances = append(wl.instances, WeightedServiceInstance{addr, weight, 0})
}// 加权轮询负载均衡
func (wl *WeightedLoadBalancer) WeightedRoundRobin() *WeightedServiceInstance {wl.mu.Lock()defer wl.mu.Unlock()totalWeight := 0for _, instance := range wl.instances {totalWeight += instance.weight}rand.Seed(time.Now().UnixNano())randomValue := rand.Intn(totalWeight)for _, instance := range wl.instances {if randomValue < instance.current+instance.weight {instance.current += totalWeightreturn &instance}instance.current += instance.weight}return nil
}// 根据负载动态调整权重
func (wl *WeightedLoadBalancer) AdjustWeights() {// 模拟获取服务实例的负载信息// 根据负载信息调整权重// 这里可以添加实际的监控和调整逻辑
}func main() {var wl WeightedLoadBalancerwl.AddInstance("service1:8080", 3)wl.AddInstance("service2:8080", 2)// 定期调整权重go func() {for {time.Sleep(3 * time.Second)wl.AdjustWeights()}}()for i := 0; i < 10; i++ {instance := wl.WeightedRoundRobin()if instance == nil {log.Println("没有可用的服务实例")} else {log.Println("将请求转发到", instance.addr)}}
}
3.处理服务实例的故障
当某个服务实例出现故障时,如果负载均衡器仍然将请求分配到该故障实例,会导致请求失败和用户体验下降。
- 解决方案
- 结合健康检查机制与负载均衡。负载均衡器定期对服务实例进行健康检查,将故障实例从可用实例列表中移除。
- 示例代码(在前面的负载均衡器基础上添加健康检查):
package mainimport ("log""net/http""sync""time"
)// 服务实例结构体
type ServiceInstance struct {addr stringhealthy bool
}// 负载均衡器结构体
type LoadBalancer struct {instances []ServiceInstancemu sync.Mutex
}// 添加服务实例
func (lb *LoadBalancer) AddInstance(addr string) {lb.mu.Lock()defer lb.mu.Unlock()lb.instances = append(lb.instances, ServiceInstance{addr, true})
}// 删除服务实例
func (lb *LoadBalancer) RemoveInstance(addr string) {lb.mu.Lock()defer lb.mu.Unlock()for i, instance := range lb.instances {if instance.addr == addr {lb.instances = append(lb.instances[:i], lb.instances[i+1:]...)break}}
}// 简单的轮询负载均衡
func (lb *LoadBalancer) RoundRobin() *ServiceInstance {lb.mu.Lock()defer lb.mu.Unlock()for {if len(lb.instances) == 0 {return nil}instance := lb.instances[0]if instance.healthy {lb.instances = append(lb.instances[1:], instance)return &instance} else {// 移除不健康的实例lb.instances = append(lb.instances[1:])}}
}// 健康检查函数
func (lb *LoadBalancer) HealthCheck() {for {time.Sleep(2 * time.Second)lb.mu.Lock()for i, instance := range lb.instances {// 模拟健康检查,这里可以替换为实际的检查逻辑if!instance.healthy {log.Println("服务实例", instance.addr, "不健康,移除")lb.instances = append(lb.instances[:i], lb.instances[i+1:]...)}}lb.mu.Unlock()}
}// 处理请求的函数
func handleRequest(w http.ResponseWriter, r *http.Request) {// 获取负载均衡器实例var lb LoadBalancerinstance := lb.RoundRobin()if instance == nil {log.Println("没有可用的服务实例")w.WriteHeader(http.StatusServiceUnavailable)return}log.Println("将请求转发到", instance.addr)// 这里可以添加实际的转发逻辑
}func main() {// 初始化负载均衡器var lb LoadBalancer// 添加一些初始服务实例lb.AddInstance("service1:8080")lb.AddInstance("service2:8080")// 启动健康检查go lb.HealthCheck()// 启动 HTTP 服务http.HandleFunc("/", handleRequest)log.Fatal(http.ListenAndServe(":8000", nil))
}
总结
在 Golang 微服务架构中,负载均衡是一个复杂但至关重要的问题。通过解决动态服务实例增减、选择和优化负载均衡算法以及处理服务实例故障等问题,可以构建更加高效、稳定的微服务系统。
关注我看更多有意思的文章哦!👉👉
相关文章:
golang学习笔记20——golang微服务负载均衡的问题与解决方案
推荐学习文档 golang应用级os框架,欢迎stargolang应用级os框架使用案例,欢迎star案例:基于golang开发的一款超有个性的旅游计划app经历golang实战大纲golang优秀开发常用开源库汇总想学习更多golang知识,这里有免费的golang学习笔…...
基于微信小程序的健身房管理系统
作者:计算机学姐 开发技术:SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等,“文末源码”。 专栏推荐:前后端分离项目源码、SpringBoot项目源码、SSM项目源码 系统展示 基于微信小程序JavaSpringBootVueMySQL的健…...
【裸机装机系列】6.kali(ubuntu)-图形界面优化-让linux更适合你的使用习惯
接下来就是图形化界面操作的部分了。会用少量截图来说明,图太多会影响阅读体验,直接文字来描述过程吧。 1> 入口 任务栏左上角——> 开始菜单——> settings——> settings manager 大部分配置都会在这里面设置。 2> 设置里面分的4大…...
新的突破,如何让AI与人类对话变得“顺滑”:Moshi背后的黑科技
你有没有想过,当我们跟智能音箱、客服机器人或者语音助手对话时,它们是怎么“听懂”我们说的话,又是怎么迅速给出回应的?就好像你对着Siri、Alexa说一句:“给我订个披萨”,它立刻明白你想要干嘛,然后帮你下单。背后的技术其实比我们想象的要复杂得多,但现在,有了Moshi…...
torch.embedding 报错 IndexError: index out of range in self
文章目录 1. 报错2. 原因3. 解决方法 1. 报错 torch.embedding 报错: IndexError: index out of range in self2. 原因 首先看下正常情况: import torch import torch.nn.functional as Finputs torch.tensor([[1, 2, 4, 5], [4, 3, 2, 9]]) embedd…...
rocky9虚拟机配置双网卡的详细过程
编辑虚拟机配置->添加->选择网络适配器->确认->打开虚拟机 1.ip add查看第二个网卡的名称,我这里是ens36 2.cd到网卡的配置文件目录 cd /etc/NetworkManager/system-connections/ ls3.复制一份网卡的配置文件并改名为ens36.nmconnection(根据自己的第…...
索引的介绍
目录 1.索引的介绍 1.1 什么是索引 1.2 为什么要使用索引 2.索引应该选择哪种数据结构 3.MYSQL中的页 3.1为什么要使用页 3.2页文件头和页文件尾 3.3 页主体 3.3页目录 3.4数据页头 4.B在MYSQL索引中的应用 4.1计算三层树高的B树可以存放多少条记录 5.索引分类 5.1 主…...
Web后端服务平台解析漏洞与修复、文件包含漏洞详解
免责申明 本文仅是用于学习检测自己搭建的Web后端服务平台解析漏洞、文件包含漏洞的相关原理,请勿用在非法途径上,若将其用于非法目的,所造成的一切后果由您自行承担,产生的一切风险和后果与笔者无关;本文开始前请认真详细学习《中华人民共和国网络安全法》及其所在国…...
树莓派介绍与可安装的操作系统
引言 自 2012 年问世以来,树莓派(Raspberry Pi) 已成为全球最受欢迎的微型单板计算机之一。最初,树莓派的目标是为学校和发展中国家的学生提供一个廉价的计算平台,以促进计算机科学教育。然而,凭借其低成本…...
Qt常用控件——QTextEdit
文章目录 QTextEdit核心属性和信号同步显示示例信号示例 QTextEdit核心属性和信号 QTextEdit表示多行输入框,是一个富文本和markdown编辑器,并且能在内存超出编辑框范围时自动提供滚动条。 QPlainTexEdit是纯文本,QTextEdit不仅表示纯文本&a…...
docker-compose 部署 flink [支持pyflink]
下载 flink 镜像 [rootlocalhost ~]# docker pull flink Using default tag: latest latest: Pulling from library/flink 762bedf4b1b7: Pull complete 95f9bd9906fa: Pull complete a880dee0d8e9: Pull complete 8c5deab9cbd6: Pull complete 56c142282fae: Pull comple…...
C++中string类的模拟实现
目录 1.string类的结构 2.默认成员函数 2.1.默认构造函数 2.2拷贝构造函数 2.3赋值运算符重载 2.4析构函数 3.迭代器(Iterators) 4.string类的空间操作(Capacity) 4.1size() 4.2capacity() 4.3clear() 4.4reserve() 5.元素访问(Element access) 6.string类的修…...
C++函数在库中的地址
本文讲述C如何直接调用动态库dll或者so中的函数。 首先我们准备一个被调用库,这个库里面有两个函数,分别是C98 与 C11 下的,名称是run2和run1。 被调用库 相关介绍请看之前的文章《函数指针与库之间的通信讲解》。 //dll_ex_im.h #ifndef…...
图像生成大模型imagen
要生成图像,可以使用深度学习模型,比如 OpenAI 的 DALLE、Google 的 Imagen 等。由于这些模型通常需要较大的计算资源和训练数据,下面是一些如何使用这些模型的基本步骤和方法。 使用预训练图像生成模型 选择模型: 常用的模型包括…...
Redis集群知识及实战
1. 为什么使用集群 在哨兵模式中,仍然只有一个Master节点。当并发写请求较大时,哨兵模式并不能缓解写压力。我们知道只有主节点才具有写能力,那如果在一个集群中,能够配置多个主节点,是不是就可以缓解写压力了呢&…...
数据报表轻松管理,强大“后台”不可少
在数据驱动的时代,制作一份高效、精准的数据报表成为企业管理和决策的重要手段。但要做好数据报表,不仅需要一款功能强大的报表工具,还必须有一个强有力的“后台”管理系统来支撑。那么,为什么报表工具需要一个管理后台࿱…...
简易CPU设计入门:本CPU项目的指令格式
在这一节里面,主要是理论知识,基本上不讲代码。不过,本项目的代码包,大家还是需要下载的。 本项目的代码包的下载方法,参考下面的链接所指示的文章。 下载本项目代码 本节,其实是要讲本项目CPU的指令集。…...
Datawhile 组队学习Tiny-universe Task01
Task01:LLama3模型讲解 仓库链接:GitHub - datawhalechina/tiny-universe: 《大模型白盒子构建指南》:一个全手搓的Tiny-Universe 参考博客:LLaMA的解读与其微调(含LLaMA 2):Alpaca-LoRA/Vicuna/BELLE/中文LLaMA/姜子…...
MCU与SOC的区别
自动驾驶中 MCU 与 SoC 的区别 在自动驾驶系统中,**MCU(微控制单元,Microcontroller Unit)和SoC(系统级芯片,System on Chip)**都是关键的电子元件,但它们在性能、功能和应用领域等…...
51单片机-DS18B20(温度传感器)AT24C02(存储芯片) IIC通信-实验2-温度实时监测(可设置阈值)
作者:王开心 座右铭:刻苦专研,百折不挠,千磨万击还坚韧,任尔东西南北风!干就完了!(可交流技术) 主要利用DS18B20芯片去采集温度,通过采集的温度能够自动保存…...
内存分配函数malloc kmalloc vmalloc
内存分配函数malloc kmalloc vmalloc malloc实现步骤: 1)请求大小调整:首先,malloc 需要调整用户请求的大小,以适应内部数据结构(例如,可能需要存储额外的元数据)。通常,这包括对齐调整,确保分配的内存地址满足特定硬件要求(如对齐到8字节或16字节边界)。 2)空闲…...
在鸿蒙HarmonyOS 5中实现抖音风格的点赞功能
下面我将详细介绍如何使用HarmonyOS SDK在HarmonyOS 5中实现类似抖音的点赞功能,包括动画效果、数据同步和交互优化。 1. 基础点赞功能实现 1.1 创建数据模型 // VideoModel.ets export class VideoModel {id: string "";title: string ""…...
ssc377d修改flash分区大小
1、flash的分区默认分配16M、 / # df -h Filesystem Size Used Available Use% Mounted on /dev/root 1.9M 1.9M 0 100% / /dev/mtdblock4 3.0M...
渲染学进阶内容——模型
最近在写模组的时候发现渲染器里面离不开模型的定义,在渲染的第二篇文章中简单的讲解了一下关于模型部分的内容,其实不管是方块还是方块实体,都离不开模型的内容 🧱 一、CubeListBuilder 功能解析 CubeListBuilder 是 Minecraft Java 版模型系统的核心构建器,用于动态创…...
Python实现prophet 理论及参数优化
文章目录 Prophet理论及模型参数介绍Python代码完整实现prophet 添加外部数据进行模型优化 之前初步学习prophet的时候,写过一篇简单实现,后期随着对该模型的深入研究,本次记录涉及到prophet 的公式以及参数调优,从公式可以更直观…...
Frozen-Flask :将 Flask 应用“冻结”为静态文件
Frozen-Flask 是一个用于将 Flask 应用“冻结”为静态文件的 Python 扩展。它的核心用途是:将一个 Flask Web 应用生成成纯静态 HTML 文件,从而可以部署到静态网站托管服务上,如 GitHub Pages、Netlify 或任何支持静态文件的网站服务器。 &am…...
使用van-uploader 的UI组件,结合vue2如何实现图片上传组件的封装
以下是基于 vant-ui(适配 Vue2 版本 )实现截图中照片上传预览、删除功能,并封装成可复用组件的完整代码,包含样式和逻辑实现,可直接在 Vue2 项目中使用: 1. 封装的图片上传组件 ImageUploader.vue <te…...
《C++ 模板》
目录 函数模板 类模板 非类型模板参数 模板特化 函数模板特化 类模板的特化 模板,就像一个模具,里面可以将不同类型的材料做成一个形状,其分为函数模板和类模板。 函数模板 函数模板可以简化函数重载的代码。格式:templa…...
【Redis】笔记|第8节|大厂高并发缓存架构实战与优化
缓存架构 代码结构 代码详情 功能点: 多级缓存,先查本地缓存,再查Redis,最后才查数据库热点数据重建逻辑使用分布式锁,二次查询更新缓存采用读写锁提升性能采用Redis的发布订阅机制通知所有实例更新本地缓存适用读多…...
【从零开始学习JVM | 第四篇】类加载器和双亲委派机制(高频面试题)
前言: 双亲委派机制对于面试这块来说非常重要,在实际开发中也是经常遇见需要打破双亲委派的需求,今天我们一起来探索一下什么是双亲委派机制,在此之前我们先介绍一下类的加载器。 目录 编辑 前言: 类加载器 1. …...
