springcloud之负载均衡

1.1 两种负载均衡 ​ 当系统面临大量的用户访问,负载过高的时候,通常会增加服务…

1.1 两种负载均衡

​ 当系统面临大量的用户访问,负载过高的时候,通常会增加服务器数量来进行横向扩展(集群),多个服务器的负载需要均衡,以免出现服务器负载不均衡,部分服务器负载较大,部分服务器负载较小的情况。通过负载均衡,使得集群中服务器的负载保持在稳定高效的状态,从而提高整个系统的处理能力。

软件负载均衡分为:服务端(集中式),客户端。

服务端负载均衡:在客户端和服务端中间使用代理,nginx。

客户端负载均衡:根据自己的情况做负载。Ribbon就是。

客户端负载均衡和服务端负载均衡最大的区别在于 服务端地址列表的存储位置,以及负载算法在哪里

在客户端负载均衡中,所有的客户端节点都有一份自己要访问的服务端地址列表,这些列表统统都是从服务注册中心获取的;

在服务端负载均衡中,客户端节点只知道单一服务代理的地址,服务代理则知道所有服务端的地址。

我们要学的Ribbon使用的是客户端负载均衡。

而在Spring Cloud中我们如果想要使用客户端负载均衡,方法很简单,使用@LoadBalanced注解即可,这样客户端在发起请求的时候会根据负载均衡策略从服务端列表中选择一个服务端,向该服务端发起网络请求,从而实现负载均衡。

上面几种负载均衡,硬件,软件(服务端nginx,客户端ribbon)。目的:将请求分发到其他功能相同的服务。

手动实现,其实也是它的原理,做事的方法。

1.2 概念

Ribbon是Netflix开发的客户端负载均衡器,为Ribbon配置服务提供者地址列表后,Ribbon就可以基于某种负载均衡策略算法,自动地帮助服务消费者去请求 提供者。Ribbon默认为我们提供了很多负载均衡算法,例如轮询、随机等。我们也可以实现自定义负载均衡算法。

《Ribbon流程图》

Ribbon作为Spring Cloud的负载均衡机制的实现,

1.3 Ribbon组成

看官网首页:https://github.com/Netflix/ribbon

ribbon-core: 核心的通用性代码。api一些配置。

ribbon-eureka:基于eureka封装的模块,能快速集成eureka。

ribbon-examples:学习示例。

ribbon-httpclient:基于apache httpClient封装的rest客户端,集成了负载均衡模块,可以直接在项目中使用。

ribbon-loadbalancer:负载均衡模块。

ribbon-transport:基于netty实现多协议的支持。比如http,tcp,udp等。

1.4 编码及测试

在api-driver:ShortMsgServiceImpl中。

调用方:调用服务,通过loadBalance(我们自定义的方法)选出一个服务。

负载均衡方法loadBalance:

引入RestTemplate

测试:yapi 中 api-driver:司机获取验证码

正常执行。

便于理解,下面是基于:RandomRule。基于Ribbon做选择。

ribbon loadbalance 源码:

debug: yapi:api-driver:学习:根据serviceName获取服务端信息

进入方法:

进入loadBalancerClient:

再进入choose

F5,进入getLoadBalancer

再进入:

进入getInstance

进入 super.getInstance

F7往回跳:

Server server = getServer(getLoadBalancer(serviceId), hint);

进入getServer

鼠标放到loadBalancer,看看里面内容。主要看看它的rule属性。

进入loadBalancer.chooseServer(

进入super.chooseServer(key);

走到: return rule.choose(key);

进入choose

在进入:choose

重点:

最后获取到服务。

上面是选择服务的过程。和我们前面手写过比较:都是随机数选出一个服务。

将yml中service-sms的配置 随机规则去掉,则ILoadBalancer的 rule就变了。

再debug一次。

核心类:ILoadBalancer

里面包括了所有的 服务提供者集群 的:ip和端口。service-sms:8002,8003

每个服务都有一个ILoadBalancer,ILoadBalancer里面有该服务列表

每个服务

Map<服务名,ILoadBalancer>

ILoadBalancer详解:(Ribbon最核心)

服务列表来源

打开:com.netflix.loadbalancer.ILoadBalancer。

它是定义负载均衡操作过程的接口。通过SpringClientFactory的getLoadBalancer方法获取(前面跟踪源码看到的)。

ILoadBalancer的实例实在RibbonClientConfiguration中配置的。

通过下面两种方式:1.默认RibbonClientConfiguration(下面) 2自定义。

ILoadBalancer的默认的实现类是:ZoneAwareLoadBalancer。

Rule默认:com.netflix.loadbalancer.ZoneAvoidanceRule@34b82630

配置说明:

ILoadBalance的接口代表负载均衡器的操作,比如有添加服务器操作、选择服务器操作、获取所有的服务器列表、获取可用的服务器列表等等。

上面方法:实现了:

饥饿模式,debug项目启动时,会进入如下方法:可以在此处debug。打断点。

得到所有服务,对应的服务列表。借助eurekaClient。

服务列表:DynamicServerListLoadBalancer

最终会存储到:

处理无用的服务

两种方法:

​ 1.更新机制,更新最新的服务。

DynamicServerListLoadBalancer.

从eureka获得一系列 server。不知道server挂了没有。用定时任务,间隔去ping

执行:

有个实现类:

判断状态。

总结:上两种机制不能同时发生。

选择算法

IRule。默认是什么?

com.netflix.loadbalancer.ZoneAvoidanceRule@505fb311:区域内轮询。

还有几个,看IRule的实现类就知道。

IRule负载均衡策略:通过实现该接口定义自己的负载均衡策略。它的choose方法就是从一堆服务器列表中按规则选出一个服务器。

默认实现:

ZoneAvoidanceRule(区域权衡策略):复合判断Server所在区域的性能和Server的可用性,轮询选择服务器。

其他规则:

BestAvailableRule(最低并发策略):会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务。逐个找服务,如果断路器打开,则忽略。

RoundRobinRule(轮询策略):以简单轮询选择一个服务器。按顺序循环选择一个server。

RandomRule(随机策略):随机选择一个服务器。

AvailabilityFilteringRule(可用过滤策略):会先过滤掉多次访问故障而处于断路器跳闸状态的服务和过滤并发的连接数量超过阀值得服务,然后对剩余的服务列表安装轮询策略进行访问。

WeightedResponseTimeRule(响应时间加权策略):据平均响应时间计算所有的服务的权重,响应时间越快服务权重越大,容易被选中的概率就越高。刚启动时,如果统计信息不中,则使用RoundRobinRule(轮询)策略,等统计的信息足够了会自动的切换到WeightedResponseTimeRule。响应时间长,权重低,被选择的概率低。反之,同样道理。此策略综合了各种因素(网络,磁盘,IO等),这些因素直接影响响应时间。

RetryRule(重试策略):先按照RoundRobinRule(轮询)的策略获取服务,如果获取的服务失败则在指定的时间会进行重试,进行获取可用的服务。如多次获取某个服务失败,就不会再次获取该服务。主要是在一个时间段内,如果选择一个服务不成功,就继续找可用的服务,直到超时。

如果要用其他负载均衡策略:只需要更改。

Iloadbalancer,irule,choose()。

上面是我们手写的。还没用的ribbon的简单写法。

api-driver:用ribbon

在eureka-client中使用Ribbon时, 不需要引入jar包,因为erueka-client已经包括ribbon的jar包了。点进去看看。

用@LoadBalance修饰RestTemplate可以实现负载均衡。

由于RestTemplate的Bean实例化方法restTemplate被@LoadBalanced修饰,所以当调用restTemplate的postForObject方法发送HTTP请求时,会使用Ribbon进行负载均衡。

默认情况下,虚拟主机名=服务名称,虚拟主机名最好不要用"_"。

虚拟主机名可以配置:

通过前面的例子,我们可知:

1.5 @LoadBalanced原理源码

debug走,会走到

上面方法,负载均衡选出一个server。回忆上面的ribbon的源码。

给RestTemplate增加了拦截器。在请求之前,将请求的地址进行替换(根据具体的负载策略选择请求地址,将服务名替换成 ip:port)。然后再进行调用。

进入拦截器:final LoadBalancerInterceptor loadBalancerInterceptor

点:return this.loadBalancer.execute(serviceName,
this.requestFactory.createRequest(request, body, execution));进去

再点return execute(serviceId, ribbonServer, request);

总结:由于加了@LoadBalanced注解,使用RestTemplateCustomizer对所有标注了@LoadBalanced的RestTemplate Bean添加了一个LoadBalancerInterceptor拦截器。利用RestTempllate的拦截器,spring可以对restTemplate bean进行定制,加入loadbalance拦截器进行ip:port的替换,也就是将请求的地址中的服务逻辑名转为具体的服务地址。

ILoadBalancer 承接 eureka 和 ribbon。获取服务地址列表,选择一个。

每个服务都有ILoadBalancer。

选择服务用 IRule(负载均衡策略)。

1.6 自定义Ribbon配置

IRule

Spring Cloud默认的Ribbon配置类是:org.springframework.cloud.netflix.ribbon.RibbonClientConfiguration。

全局:

单个服务配置:

org.springframework.cloud.netflix.ribbon.PropertiesFactory。中

相应配置如下:

只看标数字的步骤。

PS:修改扫描包配置,使不扫描RibbonConfiguration所在的包com.online.taxi.passenger.ribbonconfig。

针对服务定ribbon策略:

给所有服务定ribbon策略:

属性配置方式优先级高于Java代码。

1.7 Ribbon脱离Eureka

为service-sms设置 请求的网络地址列表。

Ribbon可以和服务注册中心Eureka一起工作,从服务注册中心获取服务端的地址信息,也可以在配置文件中使用listOfServers字段来设置服务端地址。

1.8 饥饿加载

Spring Cloud默认是懒加载,指定名称的Ribbon Client第一次请求时,对应的上下文才会被加载,所以第一次访问慢。

改成以上饥饿加载后,将在启动时加载对应的程序上下文,从而提高首次请求的访问速度。

测试:

PS:除了和RestTemplate进行配套使用之外,Ribbon还默认被集成到了OpenFeign中,当使用@FeignClient时,OpenFeign默认使用Ribbon来进行网络请求的负载均衡。

1.9 自定义负载均衡策略

或者下面配置也可以实现。

依旧启动service-sms-8002,8003的提供者。

查看chooseName后,都是 8002

思考:如何按照流量分发(60%到A,40%到B)?答案在下面。

负载均衡实际上是做请求分发的:将60%流量分发到A,将40%到B,可以更复杂。大家发挥想象。

1.10 小结

微服务可以用服务端负载均衡吗?

坏处:先得找到负载均衡服务器,怎么找,需要ip和端口,和微服务 悖论了(因为首先得用客户端负载均衡,到达服务端负载均衡后,再解析后续地址,为什么不一步到位呢? 还能减少一个服务。)。就算找到了,然后再增加一层 服务名到ip的解析。如果有服务端负载均衡的话,需要客户端先请求一个服务端负载均衡,然后负载均衡再去找具体ip,如果服务端负载均衡挂了,就瘫痪了。

本文来自网络,不代表软粉网立场,转载请注明出处:https://www.rfff.net/p/4602.html

作者: HUI

发表评论

您的电子邮箱地址不会被公开。

返回顶部