负载均衡原理分析与源码解读

2023-11-16

上一篇文章一起学习了Resolver的原理和源码分析,本篇继续和大家一起学习下和Resolver关系密切的Balancer的相关内容。这里说的负载均衡主要指数据中心内的负载均衡,即RPC间的负载均衡。

传送门 服务发现原理分析与源码解读

基于go-zero v1.3.5grpc-go v1.47.0

负载均衡

每一个被调用服务都会有多个实例,那么服务的调用方应该将请求,发向被调用服务的哪一个服务实例,这就是负载均衡的业务场景。

负载均衡的第一个关键点是公平性,即负载均衡需要关注被调用服务实例组之间的公平性,不要出现旱的旱死,涝的涝死的情况。

负载均衡的第二个关键点是正确性,即对于有状态的服务来说,负载均衡需要关心请求的状态,将请求调度到能处理它的后端实例上,不要出现不能处理和错误处理的情况。

无状态的负载均衡

无状态的负载均衡是我们日常工作中接触比较多的负载均衡模型,它指的是参与负载均衡的后端实例是无状态的,所有的后端实例都是对等的,一个请求不论发向哪一个实例,都会得到相同的并且正确的处理结果,所以无状态的负载均衡策略不需要关心请求的状态。下面介绍两种无状态负载均衡算法。

轮询

轮询的负载均衡策略非常简单,只需要将请求按顺序分配给多个实例,不用再做其他的处理。例如,轮询策略会将第一个请求分配给第一个实例,然后将下一个请求分配给第二个实例,这样依次分配下去,分配完一轮之后,再回到开头分配给第一个实例,再依次分配。轮询在路由时,不利用请求的状态信息,属于无状态的负载均衡策略,所以它不能用于有状态实例的负载均衡器,否则正确性会出现问题。在公平性方面,因为轮询策略只是按顺序分配请求,所以适用于请求的工作负载和实例的处理能力差异都较小的情况。

权重轮询

权重轮询的负载均衡策略是将每一个后端实例分配一个权重,分配请求的数量和实例的权重成正比轮询。例如有两个实例 A,B,假设我们设置 A 的权重为 20,B 的权重为 80,那么负载均衡会将 20% 的请求数量分配给 A,80 % 的请求数量分配给 B。权重轮询在路由时,不利用请求的状态信息,属于无状态的负载均衡策略,所以它也不能用于有状态实例的负载均衡器,否则正确性会出现问题。在公平性方面,因为权重策略会按实例的权重比例来分配请求数,所以,我们可以利用它解决实例的处理能力差异的问题,认为它的公平性比轮询策略要好。

有状态负载均衡

有状态负载均衡是指,在负载均衡策略中会保存服务端的一些状态,然后根据这些状态按照一定的算法选择出对应的实例。

P2C+EWMA

在go-zero中默认使用的是P2C的负载均衡算法。该算法的原理比较简单,即随机从所有可用节点中选择两个节点,然后计算这两个节点的负载情况,选择负载较低的一个节点来服务本次请求。为了避免某些节点一直得不到选择导致不平衡,会在超过一定的时间后强制选择一次。

在该复杂均衡算法中,多出采用了EWMA指数移动加权平均的算法,表示是一段时间内的均值。该算法相对于算数平均来说对于突然的网络抖动没有那么敏感,突然的抖动不会体现在请求的lag中,从而可以让算法更加均衡。

go-zero/zrpc/internal/balancer/p2c/p2c.go:133

atomic.StoreUint64(&c.lag, uint64(float64(olag)*w+float64(lag)*(1-w)))

go-zero/zrpc/internal/balancer/p2c/p2c.go:139

atomic.StoreUint64(&c.success, uint64(float64(osucc)*w+float64(success)*(1-w)))

系数w是一个时间衰减值,即两次请求的间隔越大,则系数w就越小。

go-zero/zrpc/internal/balancer/p2c/p2c.go:124

w := math.Exp(float64(-td) / float64(decayTime))

节点的load值是通过该连接的请求延迟 lag 和当前请求数 inflight 的乘积所得,如果请求的延迟越大或者当前正在处理的请求数越多表明该节点的负载越高。

go-zero/zrpc/internal/balancer/p2c/p2c.go:199

func (c *subConn) load() int64 {
  // plus one to avoid multiply zero
  lag := int64(math.Sqrt(float64(atomic.LoadUint64(&c.lag) + 1)))
  load := lag * (atomic.LoadInt64(&c.inflight) + 1)
  if load == 0 {
    return penalty
  }

  return load
}

源码分析

如下源码会涉及go-zero和gRPC,请根据给出的代码路径进行区分

在gRPC中,Balancer和Resolver一样也可以自定义,同样也是通过Register方法进行注册

grpc-go/balancer/balancer.go:53

func Register(b Builder) {
  m[strings.ToLower(b.Name())] = b
}

Register的参数Builder为接口,在Builder接口中,Build方法的第一个参数ClientConn也为接口,Build方法的返回值Balancer同样也是接口,定义如下:

可以看出,要想实现自定义的Balancer的话,就必须要实现balancer.Builder接口。

在了解了gRPC提供的Balancer的注册方式之后,我们看一下go-zero是在什么地方进行Balancer注册的

go-zero/zrpc/internal/balancer/p2c/p2c.go:36

func init() {
  balancer.Register(newBuilder())
}

在go-zero中并没有实现 balancer.Builder 接口,而是使用gRPC提供的 base.baseBuilder 进行注册,base.baseBui

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

负载均衡原理分析与源码解读 的相关文章

  • 在 Go 中获取机器 epsilon 的最简单方法

    在 Go 中获取机器 epsilon 的最简单方法是什么 浮点数的其他方面 例如精度 最小指数 最大指数 摆动等 又如何呢 我意识到有一个 math const 包 其中包含不同浮点类型的最大值和最小值 http golang org sr
  • IntelliJ 2017.1.2 GOLANG 调试不适用于包中的断点

    我的应用程序由一个 main go 文件和一些包组成 当在 main go 中命中断点时 IntelliJ 按预期工作 显示变量值等 但是 当在不同的包中设置断点时 除了被命中之外 不会显示任何变量 并且不会跳过 进入功能按预期工作 被击中
  • 带 cookie 身份验证的 Gorilla websocket

    这是我的设置 我正在构建一个带有用户登录的服务 使用 Negroni 和 Gorilla 登录后 用户会获得一个会话 cookie 服务器使用该会话 cookie 来授权受保护的端点 受保护的端点之一允许用户 客户端与服务器打开 Webso
  • 在 Go 中使用 init() 函数真的很糟糕吗?

    几天前我开始了一个新的 go 项目 我使用 golangci lint 使我的代码具有良好的风格 我发现 gochecknoinits 是 golangci lint 的 linter 之一 它告诉我不要使用 init 在我看来 为了方便起
  • Cgo 生成的源无法在 MVC 上编译

    我有一个用 CGo 制作的共享库 它在 Linux 和 Android 上链接得很好 但是 当使用 Microsoft Visual Studio 2017 在 Windows 10 上进行编译时 出现以下错误 Microsoft R Pr
  • Go 中数组的嵌套结构

    我已经开始使用https mholt github io json to go https mholt github io json to go 将 API JSON 转换为 go 结构 我真的很喜欢它 但是我对如何初始化如下所示的报告定义
  • Google Cloud Kubernetes 上任务队列的替代方案

    我发现任务队列主要用于App Engine标准环境 我正在将现有服务从 App Engine 迁移到 Kubernetes 任务队列的一个好的替代方案是什么 推送队列是当前正在使用的队列 我在线阅读文档并浏览了此链接 何时使用 PubSub
  • 有没有一种方法可以在不停机的情况下更新 net/http 服务器中的 TLS 证书?

    我有一个简单的 https 服务器 提供一个简单的页面 如下所示 为简洁起见 没有错误处理 package main import crypto tls fmt net http func main mux http NewServeMux
  • 当涉及多个渠道时,select 如何工作?

    我发现在多个非缓冲通道上使用 select 时 例如 select case lt chana case lt chanb 即使两个通道都有数据 但在处理此选择时 case chana 和 case chanb 的跟注不平衡 package
  • 为什么奇数的切片容量与偶数的切片行为不同

    我注意到 当容量为奇数时 切片的容量会以不同的方式表现 更具体地说 当向切片添加元素时 切片的容量为doubled当原始容量为偶数时 但当原容量为奇数时 容量为增加一 然后加倍 例子 s make int 28 28 s append s
  • 是否可以获取有关 Golang 中调用者函数的信息?

    是否可以获取有关 Golang 中调用者函数的信息 例如 如果我有 func foo Do something func main foo 我怎样才能得到那个foo已被呼叫来自main 我可以用其他语言实现这一点 例如在 C 中我只需要使用
  • GAE Go — 如何对不存在的实体键使用 GetMulti?

    我发现自己需要做一个GetMulti使用键数组进行操作 其中某些实体存在 但有些实体不存在 我当前的代码 如下 返回错误 datastore no such entity err datastore GetMulti c keys info
  • GoQt 致命错误:QAbstractAnimation:没有这样的文件或目录

    我尝试编译 Qt 来开发桌面应用程序 我按照 Qt 网站上的官方 wiki 指南的说明进行操作 当我尝试go run示例文件夹中的示例 我收到错误 去运行 home pinkya rabbit workspace go1programs s
  • GOPATH值设置

    我用go1 3 1 windows amd64 msi安装go 安装后GOROOT是默认设置 我发现 D Programs Go bin 在 PATH 中 然后我创建一个 GOPATH 环境变量 使用 go get 命令时 出现错误 软件包
  • 如何在特定文件夹中运行 shell 命令

    我可以用这个out err exec Command git log Output 获取将在与可执行位置相同的路径中运行的命令的输出 如何指定要在哪个文件夹中运行命令 exec Command https golang org pkg os
  • 鸭子在 Go 中打字

    我想写一个Join函数接受任意对象String 方法 package main import fmt strings type myint int func i myint String string return fmt Sprintf
  • 匿名结构和空结构

    http play golang org p vhaKi5uVmm http play golang org p vhaKi5uVmm package main import fmt var battle make chan string
  • 如何在 Go 中将环境变量传递给测试用例

    在为 Go 编写测试用例时 传递需要提供给测试的环境变量的标准方法是什么 例如 我们不想在测试用例的源代码中嵌入密码 处理这个问题最标准的方法是什么 我们让测试用例寻找配置文件吗 还有别的事吗 看来我偶然发现了答案 将其添加到测试用例中可以
  • 解组转义 XML

    在 Go 中 我将如何解码此 XML 响应 我尝试过建立一个自定义UnMarshal方法在我的Answerstruct 但我运气不太好
  • 为什么我不能将左大括号放在下一行?

    当我尝试编译以下代码时遇到奇怪的错误 package main import fmt fmt func main var arr 3 int for i 0 i lt 3 i fmt Printf d arr i 错误如下 unexpect

随机推荐

  • 人人都看得懂的正则表达式教程

    编写验证规则最流行和最简单的方法就是正则表达式了 但唯一的一个问题是正则表达式的语法太隐晦了 让人蛋疼无比 很多开发者为了在项目中应用复杂的验证 经常要使用一些小抄来记住正则式的复杂语法和各种常用命令 在这篇文章中 我将试图让大家明白什么是
  • uboot 设置环境变量

    1 使用命令 ipconfig 查看 windows 系统的 IP 2 使用命令 ifconfig 查看虚拟机 ubuntu 系统的 IP 3 串口登录 fs4412 的uboot 4 在uboot中输入命令 print 打印当前环境变量
  • 如何将栈中的元素输出

    首先需要写一个出栈函数 得到栈顶的值 才能将其输出 bool Pop SqStack s ElemType e if s gt top 1 return false e s gt data s gt top s gt top return
  • android启动优化

    主题 我们今天讨论的主题是 使用第三方工具 CPU Profile 来优化app的启动时间 背景 想要进行app的启动优化有一点必须要知道的就是Android的启动流程和启动状态 启动流程 Android的启动流程相关的知识点 各位可以去查
  • MySQL索引1

    索引最大作用就是提高对表中数据的查询速度 就像书的目录那样重要 可以快速查到所需的知识 上面是11万多条数据的表 使用语句查询 如 耗时 0 108s 再比如 用时 0 004s 接下来创建索引 在t book上右键 选择管理索引 选择新建
  • 基于vue 2.X和高德地图的vue-amap组件获取经纬度

    今天我就讲了一下怎么通过vue和高德地图开发的vue amap组件来获取经纬度 这是vue amap的官网文档 https elemefe github io vue amap 这是我的码云项目的地址 http git oschina ne
  • MySQL函数和存储过程

    MySQL流程控制函数 1 IF函数 IF expr1 expr2 expr3 如果expr1是真 返回expr2 否则返回expr3 SELECT name IF age gt 18 成年 未成年 FROM user 2 IFNULL函数
  • 给Qt程序添加管理员权限总结(一定有你没见过的方式)

    当我们写了一个Qt程序 程序会在C盘某些目录下创建文件时 会发现代码没有问题 但是就是创建失败 而当我们对程序右键 以管理员权限运行时 又可以正常创建文件 此时 说明我们的程序默认不具备管理员权限 故而无法对某些目录进行写入 根据我们的编译
  • 温酒读Qt:QObject 序篇

    一 醉言醉语话夏娃 跟Qt框架打了这么久交道 Qt貌似对我的半斤八两知根知底 我对Qt的认知却还不到半斤八两 o o 或许你知道Qt的meta object和属性系统 或许你在写代码时无数次显示或者隐示的继承了QObject 不管人家是否乐
  • 数据库数据恢复-SQL SERVER数据库分区被格式化的数据恢复方案

    SQL SERVER数据库故障类型 1 SQL SERVER数据库文件被删除 2 SQL SERVER数据库所在分区格式化 3 SQL SERVER数据库文件大小变为 0 4 使用备份还原数据库时覆盖原数据库 SQL SERVER数据库故障
  • Sublime Text 中Anaconda 插件的Python语法配置

    在Ubuntu环境下Sublime Text 配置Anaconda 插件自动检查Python3语法 在Ubuntu16 04环境下使用Sublime Text 写Python3程序 已安装了Anaconda 插件包 通过配置Anaconda
  • Fabric java sdk 1.4简明教程

    在超级账本Fabric区块链中 应用通过节点的RPC协议接口访问链码 Java应用可以使用官方提供的Fabric sdk java开发包来实现对链码的访问 开发包封装了Fabric区块链的GRPC链码访问协议 有利于开发人员聚焦于业务逻辑
  • TCP报文的交互过程

    TCP建立连接和断开连接的过程如下图所示 在TCP 协议提供可靠的连接服务时 采用三次握手建立一个连接 采用四次握手来关闭一个连接 建立TCP连接的三次握手 第一次握手 建立连接时 客户端发送 SYN 包到服务器 等待服务器确认 第二次握手
  • Docker的简介、镜像及优化

    1 docker的安装 1 配置yum源 vim etc yum repo d docker ce repo 编辑内容 vim etc yum repo d CentOS Base repo 编辑内容 2 安装docker yum inst
  • 医疗保健行业中的区块链

    区块链技术是世界上最重要和最具颠覆性的技术之一 多个行业正在采用区块链技术来创新其运作方式 希望采用区块链的行业之一是医疗保健行业 在本指南中 我们将熟悉区块链 特别是有助于打破这个行业原有桎梏的功能 此外 我们将研究医疗行业的未来将会是什
  • 推荐系统实践(八)----评分预测

    目前为止都是在讨论 T o p N TopN TopN 推荐 即给定一个用户 如何给他生成一个长度为 N N
  • JVM 内存模型

    JVM 内存模型 1 JVM 内存模型共分为5个区 Java虚拟机栈 本地方法栈 堆 程序计数器 方法区 元空间 2 各个区各自的作用 a 本地方法栈 用于管理本地方法的调用 里面并没有我们写的代码逻辑 其由native修饰 由 C 语言实
  • 卷积神经网络之-Lenet

    更多内容请关注 机器视觉CV 公众号 原文地址 前言 Lenet 是一系列网络的合称 包括 Lenet1 Lenet5 由 Yann LeCun 等人在1990 年 Handwritten Digit Recognition with a
  • 一个将XM音频导入小宇宙的工具

    这个喜马拉雅语音导出工具 能够帮助你导出喜马拉雅中的音频节目 下载后的音频文件 可以复制到小宇宙设备文件夹里面 这样我们就可以用小宇宙播放我们导入的音频文件啦 windows电脑版 https jscs lanzouw com imVZ40
  • 负载均衡原理分析与源码解读

    上一篇文章一起学习了Resolver的原理和源码分析 本篇继续和大家一起学习下和Resolver关系密切的Balancer的相关内容 这里说的负载均衡主要指数据中心内的负载均衡 即RPC间的负载均衡 传送门 服务发现原理分析与源码解读 基于