本文主要是介绍LoadBalance-Ribbon-Feign,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
文章目录
- 理论
- 1 负载均衡产生的背景
- Ribbon
- demo
- Feign
- OpenFeign
- demo
- 超时控制
理论
原文
另外一篇原理
负载均衡-LVS、HAProxy、Nginx、F5
1 负载均衡产生的背景
LB(Load Balance,负载均衡)是一种集群技术,它将特定的业务(网络服务、网络流量等)分担给多台网络设备(包括服务器、防火墙等)或多条链路,从而提高了业务处理能力,保证了业务的高可靠性。
负载均衡技术具有一下优势:
(1)高性能:负载均衡技术将业务较均衡的分担到多台设备或链路上,从而提高了整个系统的性能;
(2)可扩展性:负载均衡技术可以方便的增加集群中设备或链路的数量,在不降低业务质量的前提下满足不断增长的业务需求;
(3)高可靠性:单个甚至多个设备或链路法神故障也不会导致业务中断,提高了整个系统的可靠性;
(4)可管理性:大量的管理共组都集中在使用负载均衡技术的设备上,设备集群或链路集群只需要维护通过的配置即可;
(5)透明性:对用户而言,集群等于一个或多个高可靠性、高性能的设备或链路,用户感知不到,也不关心具体的网络结构,增加或减少设备或链路数量都不会影响正常的业务。
负载均衡技术分类:
(1) 服务器负载均衡:在数据中心等组网环境中,可以采用服务器负载均衡,将网络服务分担给多台服务器进行处理,提高数据中心的业务处理能力;
(2) 链路负载均衡:在有多个运营商出接口的组网环境中,可以采用出方向多链路动态负载均衡,实现链路的动态选择,提高服务的可靠性;
(3) 防火墙负载均衡:在防火墙处理能力成为瓶颈的组网环境中,可以采用防火墙负载均衡,将网络流量分担给多台防火墙设备,提高防火桥的处理能力;
Ribbon
Ribbon+RestTemplate调用
- 是什么?
Spring Cloud Ribbon主要功能是提供 客户端的软件负载均衡算法和服务调用 。
Ribbon客户端组件提供一系列完善的配置项,如连接超时,重试等。 就是在配置文件中列出 Load Balance 后面所有机器,Ribbon会自动帮助你基于某种规则 (如简单轮询,随机连接等)去连接这些机器。
我们很容易使用Ribbon实现自定义的负载均衡算法。
- 负载均衡区别
负载均衡(Load Balance)是将用户的请求平摊的分配到多个服务上,从而达到HA(高可用),常见的负载均衡有 Nginx,LVS,硬件F5等。
本地负载均衡vs 服务器负载均衡
Ribbon 是本地负载均衡,客户端发来的请求由Ribbon统一决定发往那个服务端的微服务。在微服务调用接口时,在注册中心上获取注册信息服务列表之后缓存在JVM本地,从而实现本地RPC远程服务调用技术。
Nginx 是服务端负载均衡:客户端所有请求都会交给nginx,然后由nginx实现请求转发,即负载均衡是由服务端实现的。
集中式负载均衡vs进程内负载均衡
目前业界主流的负载均衡方案可分成两类:
第一类:集中式负载均衡, 即在consumer和provider之间使用独立的负载均衡设施(可以是硬件,如F5, 也可以是软件,如nginx), 由该设施负责把 访问请求 通过某种策略转发至provider;
第二类:进程内负载均衡,将负载均衡逻辑集成到consumer,consumer从服务注册中心获知有哪些地址可用,然后自己再从这些地址中选择出一个合适的provider。
Ribbon就属于后者,它只是一个类库,集成于consumer进程,consumer通过它来获取到provider的地址。
demo
1、服务发现的 jar 中已经包含了负载均衡的ribbon和loadbalance,无需引入依赖。
2、在cloud-consumer-order80服务的主启动类上加上@RibbonClient
@RibbonClient(name = “CLOUD-PAYMENT-SERVICE”,configuration=MySelfRule.class)
name=“提供提供服务的微服务名称”,configuration=负载均衡算法
3、然后写一个Config,加上 @LoadBalanced
@Configuration
public class ApplicationContextConfig
{@Bean@LoadBalancedpublic RestTemplate getRestTemplate(){return new RestTemplate();}
}
4、Controller层:
@Resourceprivate RestTemplate restTemplate;@Resourceprivate LoadBalancer loadBalancer;@Resourceprivate DiscoveryClient discoveryClient;@GetMapping(value = "/consumer/payment/lb")public String getPaymentLB(){List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");if(instances == null || instances.size() <= 0){return null;}ServiceInstance serviceInstance = loadBalancer.instances(instances);URI uri = serviceInstance.getUri();return restTemplate.getForObject(uri+"/payment/lb",String.class);}
Ribbon工作时有两步:
先选择 EurekaServer,优先选择统一区域负载较少的 server
再根据用户指定的策略,从server取到的服务注册列表中选择一个地址。
Ribbon 的七种负载均衡算法:
RoundRobinRule 轮询
RandomRule 随机
RetryRule 先按照RoundRobinRule的 策略获取服务,如果获取服务失败则在指定时间里进行重试,获取可用服务
WeightedResponseTimeRule 对RoundRobinRule的扩展,响应速度越快,实例选择权重越大 ,越容易被选择
BestAvailableRule 会先过滤掉由于多次访问故障而处于断路器 跳闸状态的服务,然后选择一个并发一个最小的服务
BestAvaibilityFilteringRule 先过滤掉故障实例,再选择并发量较小的实例
ZoneAvoidanceRule 默认规则,符合server所在区域的性能和server的可用性选择服务器
Ribbon 重试机制
在集群环境中,用多个节点来提供服务,难免会有某个节点出现故障。用 Nginx 做负载均衡的时候,如果你的应用是无状态的、可以滚动发布的,也就是需要一台台去重启应用,这样对用户的影响其实是比较小的,因为 Nginx 在转发请求失败后会重新将该请求转发到别的实例上去。
由于 Eureka 是基于 AP 原则构建的,牺牲了数据的一致性,每个 Eureka 服务都会保存注册的服务信息,当注册的客户端与 Eureka 的心跳无法保持时,有可能是网络原因,也有可能是服务挂掉了。
在这种情况下,Eureka 中还会在一段时间内保存注册信息。这个时候客户端就有可能拿到已经挂掉了的服务信息,故 Ribbon 就有可能拿到已经失效了的服务信息,这样就会导致发生失败的请求。
这种问题我们可以利用重试机制来避免。重试机制就是当 Ribbon 发现请求的服务不可到达时,重新请求另外的服务。
# 对当前实例的重试次数
ribbon.maxAutoRetries=1
# 切换实例的重试次数
ribbon.maxAutoRetriesNextServer=3
# 对所有操作请求都进行重试
ribbon.okToRetryOnAllOperations=true
# 对Http响应码进行重试
ribbon.retryableStatusCodes=500,404,502
Feign
目前,在Spring cloud 中服务之间通过restful方式调用有两种方式
- restTemplate+Ribbon
- feign
怎么理解Feign和Ribbon及二者的区别?
feign是声明式的web service客户端,记住是客户端微服务,它让微服务之间的调用变得类似controller调用service。Spring Cloud集成了Ribbon和Eureka,可在使用Feign时提供负载均衡的http客户端。
Spring Cloud Netflix 的微服务都是以 HTTP 接口的形式暴露的,所以可以用 Apache 的 HttpClient 或 Spring 的 RestTemplate 去調用
而 Feign 是一個使用起來更加方便的 HTTP 客戶端,它用起來就好像調用本地方法一樣,完全感覺不到是調用的遠程方法
发布到注册中心的服务方接口,是 HTTP 的,也可以不用 Ribbon 或者 Feign,直接浏览器一样能够访问
只不过 Ribbon 或者 Feign 调用起来要方便一些,最重要的是:它俩都支持软负载均衡
注意:spring-cloud-starter-feign 里面已经包含了 spring-cloud-starter-ribbon(Feign 中也使用了 Ribbon)
从实践上看,采用feign的方式更优雅(feign内部也使用了ribbon做负载均衡)。
OpenFeign
Feign是声明性Web服务客户端。它使编写Web服务客户端更加容易。 要使用Feign,请创建一个接口并对其进行注释。 它具有可插入的注释支持,包括Feign注释和JAX-RS注释。 Feign还支持可插拔编码器和解码器。 Spring Cloud添加了对Spring MVC注释的支持,并支持使用HttpMessageConvertersSpring Web中默认使用的注释。Spring Cloud集成了Ribbon和Eureka以及Spring Cloud LoadBalancer,以在使用Feign时提供负载平衡的http客户端。
- 作用
声明式方式定义Web服务客户端;
通过集成Ribbon或Eureka实现负载均衡的HTTP客户端。
就是我们不用再去写RestTemplate 调用微服务接口了,直接用接口调用就可以了
1.1 与Feign 区别
Feign是Springcloud组件中的一个轻量级Restful的HTTP服务客户端,Feign内置了Ribbon,用来做客户端负载均衡,去调用服务注册中心的服务。Feign的使用方式是:使用Feign的注解定义接口,调用这个接口,就可以调用服务注册中心的服务
OpenFeign是springcloud在Feign的基础上支持了SpringMVC的注解,如@RequestMapping等等。OpenFeign的@FeignClient可以解析SpringMVC的@RequestMapping注解下的接口,并通过动态代理的方式产生实现类,实现类中做负载均衡并调用其他服务。
demo
新建cloud-consumer-feign-order80工程
<!--openfeign--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId></dependency><!--需要Ribbon的jar包--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency>
server:port: 80eureka:client:register-with-eureka: falseservice-url:defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/
#设置feign客户端超时时间(OpenFeign默认支持ribbon)
ribbon:
#指的是建立连接所用的时间,适用于网络状况正常的情况下,两端连接所用的时间ReadTimeout: 5000
#指的是建立连接后从服务器读取到可用资源所用的时间ConnectTimeout: 5000
主启动类:
@SpringBootApplication
@EnableFeignClients
public class OrderFeignMain80
{public static void main(String[] args) {SpringApplication.run(OrderFeignMain80.class, args);}
}
现在要调用cloud-provider-payment8001/8002接口,那么其业务逻辑接口暴露什么,我就调用什么。
cloud-provider-payment8001的service接口:
public interface PaymentService
{public int create(Payment payment);public Payment getPaymentById(@Param("id") Long id);
}
则cloud-consumer-feign-order80对应的service接口如下,填入cloud-provider-payment8001的
create方法的方法签名
@service
//Controller层的请求过来了后,就去注册中心找名字叫CLOUD-PAYMENT-SERVICE的服务(即所有的provider-payment服务)
@FeignClient(value = "CLOUD-PAYMENT-SERVICE")
public interface PaymentFeignService
{@PostMapping(value = "/payment/create")public CommonResult create(Payment payment);@GetMapping(value = "/payment/get/{id}")public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id);
}
cloud-consumer-feign-order80的Controller:
@RestController
@Slf4j
public class OrderFeignController
{@Resourceprivate PaymentFeignService paymentFeignService;@GetMapping(value = "/consumer/payment/get/{id}")public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id){return paymentFeignService.getPaymentById(id);}@GetMapping(value = "/consumer/payment/feign/timeout")public String paymentFeignTimeout(){// OpenFeign客户端一般默认等待1秒钟return paymentFeignService.paymentFeignTimeout();}
}
调用流程原理:
测试:
超时控制
Feign底层用Ribbon实现负载均衡,所以使用的是Ribbon的超时控制,默认等待1s。
测试超时:
在PaymentFeignService下添加
@GetMapping(value = "/payment/feign/timeout")String paymentFeignTimeout();
在cloud-provider-payment8001的Controller中添加下面的方法,故意超时3s
@GetMapping(value = "/payment/feign/timeout")public String paymentFeignTimeout(){// 业务逻辑处理正确,但是需要耗费3秒钟try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); }return serverPort;}
测试超时:
可以通过配置文件自定义超时时间,如下:
#设置feign客户端超时时间(OpenFeign默认支持ribbon)
ribbon:
#指的是建立连接所用的时间,适用于网络状况正常的情况下,两端连接所用的时间ReadTimeout: 5000
#指的是建立连接后从服务器读取到可用资源所用的时间ConnectTimeout: 5000
这篇关于LoadBalance-Ribbon-Feign的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!