负载均衡策略
1.轮询策略
轮询策略:RoundRobinRule,按照一定的顺序依次调用服务实例。比如一共有 3 个服务,第一次调用服务 1,第二次调用服务 2,第三次调用服务 3,依次类推。此策略的配置设置如下:
格式是:{服务名称}.ribbon.NFLoadBalancerRuleClassName
,值就是IRule的实现类。
spring-provider: # nacos中的服务id
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RoundRobinRule #设置负载均衡
2.权重策略
权重策略:WeightedResponseTimeRule,根据每个服务提供者的响应时间分配一个权重,响应时间越长,权重越小,被选中的可能性也就越低。它的实现原理是,刚开始使用轮询策略并开启一个计时器,每一段时间收集一次所有服务提供者的平均响应时间,然后再给每个服务提供者附上一个权重,权重越高被选中的概率也越大。此策略的配置设置如下:
spring-provider: # nacos中的服务id
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.WeightedResponseTimeRule
3.随机策略
随机策略:RandomRule,从服务提供者的列表中随机选择一个服务实例。此策略的配置设置如下:
spring-provider: # nacos中的服务id
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
4.最小连接数策略
最小连接数策略:BestAvailableRule,也叫最小并发数策略,它是遍历服务提供者列表,选取连接数最小的⼀个服务实例。如果有相同的最小连接数,那么会调用轮询策略进行选取。此策略的配置设置如下:
spring-provider: # nacos中的服务id
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.BestAvailableRule #设置负载均衡
5.重试策略
重试策略:RetryRule,按照轮询策略来获取服务,如果获取的服务实例为 null 或已经失效,则在指定的时间之内不断地进行重试来获取服务,如果超过指定时间依然没获取到服务实例则返回 null。此策略的配置设置如下:
ribbon:
ConnectTimeout: 2000 # 请求连接的超时时间
ReadTimeout: 5000 # 请求处理的超时时间
spring-provider: # nacos 中的服务 id
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule #设置负载均衡
6.可用性敏感策略
可用敏感性策略:AvailabilityFilteringRule,先过滤掉非健康的服务实例,然后再选择连接数较小的服务实例。此策略的配置设置如下:
spring-provider: # nacos中的服务id
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.AvailabilityFilteringRule
7.区域敏感策略
区域敏感策略:ZoneAvoidanceRule,根据服务所在区域(zone)的性能和服务的可用性来选择服务实例,在没有区域的环境下,该策略和轮询策略类似。此策略的配置设置如下:
spring-provider: # nacos中的服务id
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.ZoneAvoidanceRule
Ribbon与Nginx的区别
Nginx是基于服务端的负载均衡,客户端所有请求统一交给 nginx,由 nginx 进行实现负载均衡请求转发,Nginx保持服务清单的同时,也负责负载均衡算法。
Ribbon是从 eureka 注册中心服务器端上获取服务注册信息列表,缓存到本地,然后在本地实现轮询负载均衡策略,Ribbon不负责出来服务清单。
- Nginx适合于服务器端实现负载均衡比如 Tomcat 。
- Ribbon适合与在微服务中RPC远程调用实现本地服务负载均衡,比如 Dubbo、SpringCloud 中都是采用本地负载均衡。
- Ribbon是一个基于 HTTP 和 TCP 客户端的负载均衡器,可以在客户端配置 ribbonServerList(服务端列表),然后轮询请求以实现均衡负载。
- springcloud的 nginx性能好,但ribbon可以剔除不健康节点,nginx剔除节点比较复杂。ribbon还可以配合熔断器一起工作。
Hystrix容错组件
雪崩问题
微服务中,服务间调用关系错综复杂,一个请求,可能需要调用多个微服务接口才能实现,服务又可能调用其它服务 ,形成非常复杂的调用链路。如果此时,某个服务出现异常,请求阻塞,用户不会得到响应,则tomcat的这个线程不会释放,于是越来越多的用户请求到来,越来越多的线程会阻塞。服务器支持的线程和并发数有限,请求一直阻塞,会导致服务器资源耗尽,从而导致所有其它服务都不可用,形成雪崩效应。
解决手段:
-
线程隔离(线程池隔离、信号量隔离)
-
服务熔断
线程池隔离
默认情况下 Hystrix 是使用线程池作为隔离策略,请求的每个接口都准备了独立的线程池,请求相同接口的线程池相同(从线程池中取出的一个线程里执行该请求),请求不同的接口会创建不同的线程池,如:用户请求/provider接口,那么hystrix就为这个接口创建一个线程池,池里可以规定多少个线程和一个缓存队列(假如说:池里有10个线程,队列大小100,那么这个并发量最大就是110,如果第111个请求也请求该接口时,如果没有线程被回收,队列也放不下,那么直接会降级)。
信号量隔离
底层使用原子计算器技术,针对每个服务(接口)都设置自己独立的阈值,比如设置每个服务接口最多同时只能访问50次,超出后则进行服务降级处理,当客户端需向依赖服务发起请求时, 计数器+1,请求返回成功后 计数器-1。
信号量隔离主要是通过控制并发请求量,防止请求线程大面积阻塞,从而达到限流和防止雪崩的目的
使用场景
线程池隔离:请求并发量大,并且耗时长(请求耗时长一般是计算量大,读数据库),采用线程池隔离,这样的话,可以保证大量的容器线程可用,不会由于服务原因,一直处于阻塞状态或等待状态,快速失败返回。
信号量隔离:请求并发量大,并且耗时短(请求耗时短可能是计算量小,读缓存),采用信号量隔离,因为这类服务的返回通常会非常快,不会占用容器线程太长时间,而且也减少了线程切换的一些开销,提高了缓存服务的效率。
服务熔断
熔断器3个状态:
-
Closed:关闭状态,所有请求都正常访问。
-
Open:打开状态,所有请求都会被降级。Hystrix会对请求情况计数,当一定时间内失败请求百分比达到阈值,则触发熔断,断路器会完全打开。默认失败比例的阈值是50%,请求次数最少不低于20次。默认是 五秒之内请求20次 如果有10次失败(50%),则请求不能正常访问。
-
Half Open:半开状态。open状态不是永久的,打开后会进入休眠时间(默认是5S)。随后断路器会自动进入半开状态。此时会释放部分请求通过,若这些请求都是健康的,则会完全关闭断路器,否则继续保持打开,再次进行休眠计时。
依赖文件
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>