微服务-若何做好集群中服务器的负载平衡

那些负载平衡的面试题

简单说一下什么是负载平衡?许多人最怕这种观点性问题

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

为什么用这种?

它的优瑕玷

有更好的选择吗?

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

什么是负载平衡?

俗话解释一下负载平衡:你要在10个餐厅中选一个吃午餐,那么你选的这个历程就是负载平衡的历程,(面试也是可以这么说的)。
正规的行话:负载平衡指的是在一个集群中通过某种硬件装备或者软件算法来选择集群中的一台机械处置当前请求,以到达大量请求的涣散给后端集群差别机械处置,从而提升高并发能力和容灾能力。
百度百科:负载平衡建立在现有网络结构之上,它提供了一种廉价有用透明的方式扩展网络装备和服务器的带宽、增添吞吐量、增强网络数据处置能力、提高网络的天真性和可用性

软硬件负载平衡详解

现在负载平衡总的来说分为三大类:1 硬件装备负载平衡,2 软件算法负载平衡,3 基于DNS的负载平衡 划分先容一下这三大类的差别和优瑕玷。

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

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

DNS负载平衡一样平常用于地理位置上的负载平衡,好比你的网站在全国范围内都有海量用户,那么当差别用户接见网站域名时经由DNS判断返回给差别地理位置的用户的差别IP,从而到达就近接见,流量分管,提升用户体验。

他们的优瑕玷是什么呢?

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

软件负载平衡对照天真,可调整性大,与软件算法实现有关系,能够关注应用服务器的状态做汇总统计试其余能力,性价对照高,但受软件安装的服务器性能影响,同时也没硬件的性能好,DNS负载平衡也属于软件负载平衡的一种。

本文主要剖析的也是软件负载平衡。

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

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

我们主要剖析下这些中间件负载平衡计谋是怎么实现的?用的什么算法,重点来了

.net core 依赖注入, autofac 简单使用

  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地址如下:

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

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

原创文章,作者:28x0新闻网,如若转载,请注明出处:https://www.28x0.com/archives/2972.html