专栏首页GoLang那点事微服务-如何做好集群中服务器的负载均衡

微服务-如何做好集群中服务器的负载均衡

那些负载均衡的面试题

简单说一下什么是负载均衡?很多人最怕这种概念性问题

你们公司负载均衡用的什么?

为什么用这种?

它的优缺点

有更好的选择吗?

你说这5连问,谁受得了啊,从浅到深,一环扣一环,简直不要了,别怕,仔细阅读本文,这些问题都会迎刃而解。

什么是负载均衡?

俗话解释一下负载均衡:你要在10个餐厅中选一个吃午餐,那么你选的这个过程就是负载均衡的过程,(面试也是可以这么说的)。

正规的行话:负载均衡指的是在一个集群中通过某种硬件设备或者软件算法来选择集群中的一台机器处理当前请求,以达到大量请求的分散给后端集群不同机器处理,从而提升高并发能力和容灾能力。

百度百科:负载均衡建立在现有网络结构之上,它提供了一种廉价有效透明的方法扩展网络设备和服务器的带宽、增加吞吐量、加强网络数据处理能力、提高网络的灵活性和可用性

软硬件负载均衡详解

目前负载均衡总的来说分为三大类:1 硬件设备负载均衡,2 软件算法负载均衡,3 基于DNS的负载均衡 分别介绍一下这三大类的不同和优缺点。

硬件负载均衡解决方案是直接在服务器和外部网络间安装负载均衡设备,这种设备通常称之为负载均衡器,由于专门的设备完成专门的任务,独立于操作系统,整体性能得到大量提高,加上多样化的负载均衡策略,智能化的流量管理,可达到最佳的负载均衡需求,其主要应用在大型服务器集群中,比如F5负载均衡器。

软件负载均衡指的是在服务器的操作系统上安装负载均衡软件,从此服务器发出的请求经软件负载均衡算法路由到后端集群的某一台机器上。

DNS负载均衡一般用于地理位置上的负载均衡,比如你的网站在全国范围内都有海量用户,那么当不同用户访问网站域名时经过DNS判断返回给不同地理位置的用户的不同IP,从而达到就近访问,流量分担,提升用户体验。

他们的优缺点是什么呢?

硬件负载均衡一般只是关注网络流量的负载,至于后端服务器的状态等他不操心,而且成本贵,往往也是单点,但它也有优点,就是性能好,处理能力强,与操作系统无关性。

软件负载均衡比较灵活,可调整性大,与软件算法实现有关系,能够关注应用服务器的状态做汇总统计识别的能力,性价比较高,但受软件安装的服务器性能影响,同时也没硬件的性能好,DNS负载均衡也属于软件负载均衡的一种。

本文主要分析的也是软件负载均衡。

常用的负载均衡算法和实现原理

负载均衡中间件现在很多,大家最熟悉的,也是最出名的就属Nginx了,其次也有很多,比如百度前段时间开源了bfe(百度统一前端),是百度7层流量转发平台,还有apache,各种微服务中间件中的负载均衡算法等

我们主要分析下这些中间件负载均衡策略是怎么实现的?用的什么算法,重点来了

  1. Random 随机
  2. Round Robin 轮询
  3. Weighted Round Robin 加权轮询
  4. Least Connections 最少连接
  5. Latency-Aware 延迟感知(最小延迟,也就是说那台机器性能最好,就用那台)
  6. Source Hashing 源地址散列
  7. Consistency hash 一致性散列(一般在分布式缓存中比较常见 )

随机策略指的是在后端集群机器的IP列表中根据随机数选择一个IP作为此次请求的应答者,当随机算法足够好,足够公平时,在海量请求下,最终后端集群各个机器承载的流量是均衡, 随机策略会导致配置较低的机器Down机,从而可能引起雪崩,一般采用随机算法时建议后端集群机器配置最好同等的,随机策略的性能取决与随机算法的性能。

轮询策略指的是在集群中对所有机器编号,假设10台机器,从0-9,请求来临时从0号机器开始,后续每来一次请求对编号加1,这样一直循环,上面的随机策略其实最后就变成轮询了,这两种策略都不关心机器的负载和运行情况,而且对变量操作会引入锁操作,性能也会下会下降。

加权轮询策略指的是会给后端集群每台机器都分配一个权重,权重高的会承担更多的流量,相反权重低的分配的流量也会少,这种策略允许后端集群机器配置差异化,假设有3台机器(a,b,c),他们的权重分别是(7,2,1),那么10次请求a机器承担7次,b机器承担2次,c机器承担1次,但是这种承担法到底怎么分配呢?有两种情况如下,我们可以看到第一种请求在a的时候,bc完全空闲,而第二种情况相对均匀一些,Nginx的加权轮询策略采用的就是第二种情况

  1. (aaaaaaa,bb,c)
  2. (aabaabaaca)

最少连接策略会关注后端集群各个服务器当前的连接数,选择一个最少连接数的机器应答当前请求,这种策略实际上关注各个服务器的负载情况,选择负载最低的机器处理请求,尽可能的提高各个机器的利用率,相对来说比较灵活和智能,实现上也会复杂一些。

延迟感知策略和最少连接是一样的思想,延迟感知追求极致的性能或者说用户体验,总是挑选能够最快的返回执行结果的机器来访问,但坏处是当都所有客户端都认为某台服务器最快时,那么所有请求都发送这台服务反而可能造成服务压力过大,性能降低。

源地址散列策略能够让同一客户端的请求或者同一用户的请求总是请求在后端同一台机器上,这种算法根据客户端IP求出Hash值然后对端集群总数求余得到值就是服务器集合的下标,一般这种算法用于缓存命中,或者同一会话请求等,但这种算法也有一定的缺点,某一用户访问量(黑产)非常高时可能造成服务端压力过大或者后端服务Down掉,那么客户端就会无法访问,所以也需要一定的降级策略。

一致性散列是在源地址散列的基础上发展得来的,什么意思呢?后端集群有3台机器(a,b,c),客户端经过散列对服务器总数取余后总是请求到a机器,那么当后端集群新增或者减少一台机器时,客户端散列后对服务器总数取余后就不再是原来的那台机器了,这样原来所有的请求散列后对应的后台机器都发生了变化,一致性散列就是解决这种问题的.

实现一个负载均衡算法

我们挑选上面一种策略用代码来实现一下,以便让大家更深入的理解,选择一个面试常问的策略,1、加权轮询算法,这个也比较多,Nginx中默认的算法

加权轮询算法每台服务器有三个权重:初始配置的权重,当前权重,有效权重,其中初始配置权重和有效权重是不变的,默认情况有效权重等于初始配置权重,当配置文件的初始配置权重改变时,会触发有效权重改变,只有当前权重是动态变化的。

每次请求到来时都从服务器列表中选择一个当前权重最高的,之后将选择出来的服务器当前权重减去所有服务器权重的和重新赋值给该服务器当前权重,这种算法通过不断递减当前权重使得所有服务器都有机会服务请求,比较平滑,代码实现如下

首先定义一个结构体,加权轮询算法的核心要素必须有服务器初始配置权重,当前权重(权重在实际运行时可能发生变化)

type SeverWeight struct {
 
 //配置的权重
 
 ConfigWeight int
 
 //当前权重
 
 CurrentWeight int
 
 //有效权重(值等于ConfigWeight,不过该字段使用一个配置属性,供前端修改使用)
 
 EffectiveWeight int
 
 //服务器ip
 
 Ip string
 
}
 
//加权轮询算法
 
type WeightedRoundRobin struct {
 
 //机器ip和对应的权重
 
 IpAndWeightedConfig map[string]int
 
 //服务器和权重信息
 
 SwSlice []*SeverWeight
 
}
 

根据配置信息创建负责均衡对象,初始化各个字段的值

//初始化加权轮询对象
 
func NewWeightedRoundRobin(iwc map[string]int) *WeightedRoundRobin {
 
 if iwc == nil {
 
 return nil
 
 }
 
 SwSlice := make([]*SeverWeight, 0)
 
 for k, v := range iwc {
 
      sw := &SeverWeight{ConfigWeight: v, CurrentWeight: 0,
 
 EffectiveWeight: v, Ip: k}
 
 SwSlice = append(SwSlice, sw)
 
 }
 
 return &WeightedRoundRobin{IpAndWeightedConfig: iwc, SwSlice: SwSlice}
 
}
 

这个方法是核心,调用这个方法来决定选择哪个服务器提供服务,方法的核心逻辑是选择当前权重最大的服务器提供服务,当前权重不断在变化,每次当前权重的值都等于当前值加上有效值减去所有服务器的有效权重和(这个算法就是不断递减当前服务器的当前权重值,使得按照均匀的变化让所有服务器都能提供服务)

func (wrr *WeightedRoundRobin) Select() (sw *SeverWeight) {
 
   total := 0 //统计所有服务器权重和
 
 for _, v := range wrr.SwSlice { //遍历服务器
 
 //当前权重加上有效权重
 
      v.CurrentWeight += v.EffectiveWeight
 
      total += v.EffectiveWeight
 
 //当配置值修改的时候的,有效权重循序渐进的增加
 
 if v.EffectiveWeight < v.ConfigWeight {
 
         v.EffectiveWeight++
 
 }
 
 //把权重最大的赋值给sw(sw是需要返回的对象)
 
 if sw == nil || v.CurrentWeight > sw.CurrentWeight {
 
         sw = v
 
 }
 
 }
 
 //当前返回对象的权重-所有服务器权重和
 
   sw.CurrentWeight = sw.CurrentWeight - total
 
 return sw
 
}
 

我们再来看一下执行的测试结果,根据测试结果相信大家就能够明白了,根据下面结果我们确实能够看到返回的服务器IP是均匀的,比较平滑,不会让权重低的服务器一直等待。

func TestNewWeightedRoundRobin(t *testing.T) {
 
 //服务器ip和权重配置
 
   config :=map[string]int{"10.1": 7, "10.2": 2, "10.3": 1}
 
   wrr := NewWeightedRoundRobin(config)
 
 //发送10次请求
 
 for i := 0; i < 10; i++ {
 
      sw := wrr.Select()
 
      t.Log(sw.Ip)//打印每次请求IP
 
 }
 
}
 
//结果:[10.1,10.1,10.2,10.1,10.1,10.3,10.1,10.1,10.2,10.1]
 

整个代码我已提交到github上,大家可以github上下载下来实际运行一下,加深理解,我的github地址如下:

github.com/sunpengwei1992/go_common/blob/master/algorithm/load_balance.go

任何一种算法深入研究后都能引出一堆问题来,都可以单独写一篇文章出来,本篇重点是在让大家知道这些算法,以至于见到后不会陌生,需要大家在工作中不断探索,不断升级自己的认知,提高思维能力。

本文分享自微信公众号 - GoLang那点事(aweiaichitudou),作者:那小子阿伟

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-03-27

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • gRPC-Server启动,深入源码探究,一起弄懂它

    gRPC已经断断续续写了七篇文章了,但基本都是属于gRPC的使用上,旨在帮助大家如何使用gRPC,了解gRPC的功能以及特性,并通过示例代码让大家能快速入门,对...

    阿伟
  • gRPC拦截器那点事,希望帮到你

    上一篇介绍了gRPC的接口认证,我们客户端需要实现gRPC提供的接口,然后在服务端业务接口实现中通过metadata获取认证信息,进行判断,那么当我们有几十个,...

    阿伟
  • gRPC注册中心,常用的注册中心你懂了吗?AP还是CP

    gRPC是一个跨语言的微服务框架,但gRPC本身不支持微服务框架生态圈的一些功能,比如注册中心,限流,熔断等,今天我们就看看如何利用gRPC提供的接口实现简单的...

    阿伟
  • 算法即动画!在线交互式可视化平台,GitHub超2万星

    视觉信息占全部感觉信息的80%以上。科学家发现,人类和灵长类动物的大脑皮层内有至少32个区域(即占大脑皮层一半以上的区域)参与视觉信息处理。

    新智元
  • 当你们在用算法获取流量和金钱时,微博和知乎是这样做的

    昨天,我的一条微博创造了自2010年注册以来的记录:阅读量超过1000万,且还在继续增长——然而我的微博粉丝,却只有1万人,出现这样的情况,是因为微博的Time...

    罗超频道
  • Python 版 LeetCode 刷题笔记 #5 无重复字符的最长子串(下)

    给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。 示例:

    TTTEED
  • 技术帖:解析今日头条公开的推荐算法

    1月11日,北京今日头条总部,一场问诊算法、建言算法的“让算法公开透明”分享会正在进行,雷锋网(公众号:雷锋网)观察到,包括BAT等在内的诸多科技公司算法工程师...

    小莹莹
  • NetFlix百万美金数据建模大奖的故事

    我常对学生讲,互联网真是个好东西,它为年轻人提供了绝佳的施展舞台和成功的技术条件,那里有无穷的宝藏,数不清的成功机会。有不少学生听了这个说法并不理解,他们往往认...

    小莹莹
  • 网页切片算法的若干问题

    这是我研究网页切片算法的一个汇总想法。     之前我写过:一种面向搜索引擎的网页分块、切片的原理,实现和演示 ,随着工作的深入,逐渐碰到以下问题: ...

    田春峰-JCJC错别字检测
  • 排序之冒泡排序

      本篇博客是在伍迷兄的博客基础上进行的,其博客地址点击就可以进去,里面好博客很多,我的排序算法都来自于此;一些数据结构方面的概念我就不多阐述了,伍迷兄的博客中...

扫码关注云+社区

领取腾讯云代金券