六种常见负载均衡算法(Go语言实现)

引言

你说妹子太多了,压力有点大,身体有点吃不消,有点支持不住了。
因而乎,你找了几个兄弟说:哥们,帮忙分担一下压力呗。因而你开始把这些妹子推向你兄弟的魔爪,把妹子一个个的介绍给你不一样的兄弟,而且尽力撮合他们。PS: 固然本身得留点。算法

这大概就是负载均衡,你既充当着负载均衡器, 也充当着服务器, 你的兄弟就是个服务器。你的压力相比之下减小了不少,这就是负载均衡的做用。json

用专业术语来讲:后端

  • 负载均衡创建在现有网络结构之上,它提供了一种廉价有效透明的方法扩展网络设备和服务器的带宽、增长吞吐量、增强网络数据处理能力、提升网络的灵活性和可用性。
  • 负载均衡(Load Balance)其意思就是分摊到多个操做单元上进行执行,例如Web服务器、FTP服务器、企业关键应用服务器和其它关键任务服务器等,从而共同完成工做任务。

简单点来讲:服务器

  • 其实就是请求太多,一台服务器处理不过来,把它分摊到多台服务器处理。

那么如何将请求分摊到多台服务器?网络

接下来一一介绍常见的几种负载均衡算法。负载均衡

轮询法

  • 将请求按顺序轮流地分配到后端服务器上,它均衡地对待后端的每一台服务器,而不关心服务器实际的链接数和当前的系统负载。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eAolzy2P-1619539822631)(https://www.classmatelin.top/images/20210427234214.png)]dom

  • Go语言实现示例以下:函数

    /** * Author: ClassmateLin * Site: https://www.classmatelin.top * mail: classmatelin.site@gmail.com * Date: 2021/4/26 21:32 */
    
    package main
    
    import (
    	"fmt"
    )
    
    type RoundRobin struct { 
    	servers []string
    	current int
    }
    
    /** 获取下一个服务器 */
    func (R *RoundRobin) next() string { 
    	R.current++
    	R.current = R.current % len(R.servers) // 访问到最后一个服务器以后,重置会第一台。 5%5=0。
    	return R.servers[R.current]
    }
    
    func main() { 
    
    	r := &RoundRobin{ 
    		servers: []string{ "192.168.10", "192.168.11", "192.168.12"},
    		current: -1,
    	}
    	
    	for i := 0; i < 10; i++ { 
    		fmt.Printf("| %d | %s |\n", i + 1, r.next())
    	}
    }

加权轮询法

  • 每台后端服务器的配置可能不太同样,有些性能好,能处理的请求多, 有些则性能比较差,能处理的请求较少。性能

  • 它们的抗压能力不相同,所以按顺序的分配服务器的话致使性能好的服务器没法发挥最大做用,性能差的服务器压力太大。spa

  • 那么加权轮询法能够解决这个问题,给性能好的服务器分配较高的权重,性能差的服务器分配较低的权重。

  • go语言实现的平滑的加权轮询法:

/** * @Author: ClassmateLin * @Site: https://www.classmatelin.top * @Email: classmatelin.site@gmail.com * @Date: 2021/4/27 22:44 */

package main

import "fmt"

type Server struct { 
	host string  // 主机地址
	weight int // 配置的权重
	currentWeight int  // 当前权重
}

func getSever(servers []*Server) (s *Server)  { 

	allWeight := 0 // 总权重

	for _, server := range servers { 
		if server == nil { 
			return nil
		}
		// 每一轮选择都用自身的权重加到当前权重
		allWeight += server.weight
		server.currentWeight += server.weight

		// 当前未选中节点或当前节点比以前选中的节点权重高,那么更新当前选中的节点
		if s == nil || server.currentWeight > s.currentWeight{ 
			s = server
		}
	}

	s.currentWeight -= allWeight

	return
}


func main() { 
	servers := []*Server{ 
		{ "192.168.10.10", 5, 0},
		{ "192.168.10.11", 2, 0},
		{ "192.168.10.12", 1, 0},
	}

	for i := 0; i < 20; i++ { 
		server := getSever(servers)

		if server == nil { 
			continue
		}

		fmt.Printf("| %s | %d |\n", server.host, server.weight)
	}
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eVhLqR1j-1619539822633)(https://www.classmatelin.top/images/20210427233715.png)]

  • 平滑是指什么?例若有如下三台服务器:
A: { host:"192.168.10.10", "weight": 3}
B: { host:"192.168.10.11", "weight": 1}
C: { host:"192.168.10.12", "weight": 1}

若是出现的序列为AAABC, 可能会给第一台机器形成压力过大。若是出现的序列为ABACA,避免同时形成同一台服务器压力过大的问题,就是平滑的。)

随机法

  • 随机法就是经过随机算法,从服务器列表中随机地选取一台服务器进行访问。随着客户端调用服务器的次数增长到必定数量级别,每台服务器的平均访问次数跟轮询法的次数相近,也就是说趋近于轮询法。

  • go实现示例:

/** * @Author: ClassmateLin * @Site: https://www.classmatelin.top * @Email: classmatelin.site@gmail.com * @Date: 2021/4/27 22:44 */

package main

import (
	"fmt"
	"math/rand"
)

type Random struct { 
	servers []string
}

func (R *Random) next() string { 
	return R.servers[rand.Intn(len(R.servers))]
}

func main()  { 
	r := Random{ 
		servers: []string{ "192.168.10.10", "192.168.10.11", "192.168.10.12"},
	}

	for i := 0; i < 10; i++ { 
		fmt.Println(r.next())
	}
}

加权随机法

  • 加权随机法根据后端机器的配置,系统的负载分配不一样的权重,按照权重进行随机选取,与加权轮询法类似。

  • go语言实现示例:

 
  
 

源地址哈希法

  • 源地址哈希法是根据请求来源的地址,经过哈希函数计算获得的一个数值,用该数值对服务器列表的大小进行取模运算,获得的结果即是客服端要访问服务器的序号。

  • 采用源地址哈希法进行负载均衡,同一源地址的请求,当服务器列表不变时,它每次都会映射到同一台服务器进行访问。

  • go语言实现示例:

 
  
 

最小数链接法

  • 最小链接数法是根据服务器当前的链接状况进行负载均衡的,当请求到来时,会选取当前链接数最少的一台服务器来处理请求。

  • 由此也能够延伸出,根据服务器CPU 占用最少,根据单位时间内处理请求的效率高低等进行服务器选择。

  • go语言实现示例:

相关文章
相关标签/搜索