IT评测·应用市场-qidao123.com

标题: SpringCloud - 新版镌汰 Ribbon,在 OpenFeign 中整合 LoadBalancer 负载均 [打印本页]

作者: 徐锦洪    时间: 2024-6-22 17:33
标题: SpringCloud - 新版镌汰 Ribbon,在 OpenFeign 中整合 LoadBalancer 负载均
目录

一、LoadBalancer 负载均衡
1.1、前言
1.2、LoadBalancer 负载均衡底层实现原理
二、整合 OpenFeign + LoadBalancer
2.1、所需依赖
2.2、具体实现
 2.3、自界说负载均衡策略


一、LoadBalancer 负载均衡


1.1、前言

在 2020 年从前的 SpringCloud 采用 Ribbon 作为负载均衡,但是 2020 年之后,SpringCloud 吧 Ribbon 移除了,而是利用自己编写的 LoadBalancer 替换.
   因此,假如在没有参加 LoadBalancer 依赖的环境下,利用 RestTemplate 或 OpenFeign 远程调用,就会报以下错误:
  

这就是在告诉你 LoadBalancing是未界说的(OpenFeign 中引入的依赖会利用 LoadBalancing),然后问你是不是忘记参加 spring-cloud-starter-loadbalancer 依赖.

1.2、LoadBalancer 负载均衡底层实现原理

a)在添加了 @LoadBalanced 注解之后,会启用拦截器对我们发起的服务调用请求举行拦截(留意,这里是针对我们发起的请求举行拦截),叫做 LoadBalancerInterceptor,它实现了 ClientHttpRequestInterceptor 接口:
  1. @FunctionalInterface
  2. public interface ClientHttpRequestInterceptor {
  3.     ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException;
  4. }
复制代码
 intercept 方法如下:
  1. public ClientHttpResponse intercept(final HttpRequest request, final byte[] body, final ClientHttpRequestExecution execution) throws IOException {
  2.     URI originalUri = request.getURI();
  3.     String serviceName = originalUri.getHost();
  4.     Assert.state(serviceName != null, "Request URI does not contain a valid hostname: " + originalUri);
  5.     return (ClientHttpResponse)this.loadBalancer.execute(serviceName, this.requestFactory.createRequest(request, body, execution));
  6. }
复制代码
紧张就是这里的 intercept 方法拦截的请求.
b)这个拦截用具体做了什么事变呢,我们知道,被拦截的请求地点,并不是一个有效的主机地点,而是服务名称,因此需要通过 服务注册中心(Nacos)才能得到需要访问的主机地点.
loadBalancer.execute() 就是在获取请求对应的服务实例信息.
  1. //从上面给进来了服务的名称和具体的请求实体
  2. public <T> T execute(String serviceId, LoadBalancerRequest<T> request) throws IOException {
  3.     String hint = this.getHint(serviceId);
  4.     LoadBalancerRequestAdapter<T, DefaultRequestContext> lbRequest = new LoadBalancerRequestAdapter(request, new DefaultRequestContext(request, hint));
  5.     Set<LoadBalancerLifecycle> supportedLifecycleProcessors = this.getSupportedLifecycleProcessors(serviceId);
  6.     supportedLifecycleProcessors.forEach((lifecycle) -> {
  7.         lifecycle.onStart(lbRequest);
  8.     });
  9.           //可以看到在这里会调用choose方法自动获取对应的服务实例信息
  10.     ServiceInstance serviceInstance = this.choose(serviceId, lbRequest);
  11.     if (serviceInstance == null) {
  12.         supportedLifecycleProcessors.forEach((lifecycle) -> {
  13.             lifecycle.onComplete(new CompletionContext(Status.DISCARD, lbRequest, new EmptyResponse()));
  14.         });
  15.               //没有发现任何此服务的实例就抛异常(之前的测试中可能已经遇到了)
  16.         throw new IllegalStateException("No instances available for " + serviceId);
  17.     } else {
  18.               //成功获取到对应服务的实例,这时就可以发起HTTP请求获取信息了
  19.         return this.execute(serviceId, serviceInstance, lbRequest);
  20.     }
  21. }
复制代码
 
c)因此,现实上,在举行负载均衡的时间,会向服务的注册中心(Nacos)发起一个请求,选择一个可用的服务(假如有多个),然后返回此服务的主机地点等信息.

二、整合 OpenFeign + LoadBalancer


2.1、所需依赖

在需要举行远程调用的服务中引入openfeign 和 loadbalancer 依赖
  1.         <dependency>
  2.             <groupId>org.springframework.cloud</groupId>
  3.             <artifactId>spring-cloud-starter-openfeign</artifactId>
  4.         </dependency>
  5.         <dependency>
  6.             <groupId>org.springframework.cloud</groupId>
  7.             <artifactId>spring-cloud-starter-loadbalancer</artifactId>
  8.         </dependency>
复制代码
2.2、具体实现

a)启动类中添加 @EnableFeignClients 注解
  1. @SpringBootApplication
  2. @EnableFeignClients
  3. public class UserApplication {
  4.     public static void main(String[] args) {
  5.         SpringApplication.run(UserApplication.class, args);
  6.     }
  7. }
复制代码
b)比方,在 user 微服务中调用 article 微服务接口,那么就需要在 user 为服务中创建一个 article 的客户端.
  1. @FeignClient("article")
  2. public interface ArticleClient {
  3.     @GetMapping("/article/start")
  4.     String userStart();
  5. }
复制代码
服务提供者:
  1. @RestController
  2. @RequestMapping("/article")
  3. public class ArticleController {
  4.     @GetMapping("/start")
  5.     public String userStart() {
  6.         System.out.println("article 被远程调用了!");
  7.         return "article ok ~";
  8.     }
  9. }
复制代码
服务消耗者:
  1. @RestController
  2. @RequestMapping("/user")
  3. public class UserController {
  4.     @Autowired
  5.     private ArticleClient articleClient;
  6.     @GetMapping("/start")
  7.     public String userStart() {
  8.         String result = articleClient.userStart();
  9.         return "user ok ~\n" + result;
  10.     }
  11. }
复制代码
c)访问 user 服务接口,可以看到乐成举行了远程调用

d)连续访问 10 次,可以发现,在 OpenFeign 的声明式客户端中,不用加 @LoadBalancer 注解也会实现默认的 “轮询” 负载均衡策略(RestTemplate 方式必须加).

 

在 BlockingLoadBalancerClient 中添加断点,就可以看到我们指定的策略默认是轮询(RoundRobin):



 2.3、自界说负载均衡策略

LoadBalancer默认提供了两种负载均衡策略:

现在希望修改默认的负载均衡策略为随机分配策略,就需要创建随机分配策略的设置类(不用加 @Configuration):
  1. //这里不用加 @Configuration 注解
  2. public class LoadBalancerConfig {
  3.     //将官方提供的 RandomLoadBalancer 注册为Bean
  4.     @Bean
  5.     public ReactorLoadBalancer<ServiceInstance> randomLoadBalancer(Environment environment, LoadBalancerClientFactory loadBalancerClientFactory){
  6.         String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
  7.         return new RandomLoadBalancer(loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class), name);
  8.     }
  9. }
复制代码
通过 @LoadBalancerClient(value = "服务名", configuration = LoadBalancerConfig.class)  指定负载均衡策略为随机.
  1. @FeignClient("article")
  2. @LoadBalancerClient(value = "article", configuration = LoadBalancerConfig.class) //指定负载均衡策略为随机
  3. public interface ArticleClient {
  4. //    @LoadBalanced(可以写,也可以不用写,默认所有方法都自动加 @LoadBalanced)
  5.     @GetMapping("/article/start")
  6.     String userStart();
  7. }
复制代码



免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 IT评测·应用市场-qidao123.com (https://dis.qidao123.com/) Powered by Discuz! X3.4