[go微服务-27] 负载均衡如何提高系统可用性?
引言
负载均衡能够将大量的请求,根据负载均衡算法,分发到多台服务器上进行处理,使得所有服务器负载都维持在高效稳定的状态
负载均衡概念
互联网应用在其发展初期往往采用单实例部署,单机单实例的服务已经无法应对用户的请求并且单机单实例存在单点错误问题
软件负载均衡和硬件负载均衡
软件负载均衡:又分为客户端负载均衡和服务端负载均衡
软件负载均衡
使用独立的负载均衡软件来实现请求的分发,它配置较为简单并且使用成本不高,能够满足大多数的负载均衡要求,但是软件所部署服务器的性能,会成为整个系统吞吐量的瓶颈,并且还会产生单点错误
硬件负载均衡
依赖于特殊的负载均衡硬件设备来分发请求到不同的服务实例,它能够提供更高的性能、更加多样化的负载均衡策略,和更加细粒度的流量管理更好地满足整体系统所需的负载均衡要求,但是成本极高,需要专门的硬件设备
F5负载均衡器、Nginx和 LVS
几乎所有的主流Web服务器都支持基于反向代理的负载均衡,Web服务器实现反向代理负载均衡的核心机制,就是转发HTTP请求到不同的服务实例
客户端负载均衡和服务端负载均衡的核心差异在于,谁感知可用服务列表,进行负载均衡操作,客户端进行上述操作的就是客户端负载均衡,反之则是服务端负载均衡
客户端负载均衡
服务端负载均衡
负载均衡算法简介
负载均衡算法——定义了如何将请求分散到服务实例的规则优秀的负载均衡算法,能够使服务集群中各服务的负载处于高效稳定的状态
随机法
随机从可用服务列表中选取一个服务实例来分发请求,一定程度上保证了请求的分散性,无法顾及请求分配是否与服务实例的负载能力相符合存在偶发的毛刺问题
轮询法或者加权轮询法
将请求轮流分配给现有可用服务列表中的每一个服务实例,适用于集群中服务实例的,负载能力大致相同且请求处理能力差异不大的场景
Hash 法或者一致性Hash 法
该算法根据请求的某些属性(比如说userld)。使用Hash算法将其分散到不同服务实例中
最小连接数法
该算法将请求分配到当前可用服务列表中,正在处理最少请求的服务实例上
负载均衡算法实现
完全随机算法
带权重的平滑轮询算法
完全随机算法
//随机负载均衡
func (loadBalance RandomLoadBalance) SelectService(services [common.Servicelnstance)(*common.Servicelnstance, error) {
if services == nil || len(services) ==0{
return nil, errors.New("service instances are not exist")
}
return services[rand.Intn(len(services))], nil
}
完全随机策略可以把请求完全分发到不同的服务实例上,大致可以将所有流量平均分给各个实例,往往需要根据服务实例的负载能力,分发相匹配的请求数量
带权重的平滑轮询算法
带权重的平滑轮询算法,是前面介绍的带权重的轮询算法的优化版本,它会根据各个服务实例的权重比例,将请求平滑地分配到各个服务实例中
根据服务实例结构体(Servicelnstance)中的权重值Weight和当前权重值CurWeight这两个属性值进行计算
//权重平滑负载均衡
func (loadBalance WeightRoundRobinLoadBalance) SelectService(services[]common.Servicelnstance)(best*common.Servicelnstance, err error){
if services == nil || len(services)==0{
return nil, errors.New("service instances are not exist")
}
total :=0
for i := 0; i<len(services);
i++{
w := services[i]
if w ==nil {
continue
}
w.CurWeight += w.Weight
total += w.Weight
if best == nil|| w.CurWeight > best.CurWeight {
best = w
}
}
if best == nil{
return nil, nil
}
best.CurWeight -= total
return best, nil
}
小结
介绍了负载均衡产生的背景和相关概念,然后介绍了负载均衡的分类和具体算法,最后我们还提供了两种常见负载均衡算法的具体实现。
通过负载均衡,使得集群中服务实例的负载保持在稳定高效的状态,从而提高了整个系统的处理能力