日志

服务消费者(RestTemplate+Ribbon+feign)

 来源    2020-08-02    0  

负载均衡

​ spring cloud 体系中,我们知道服务之间的调用是通过http协议进行调用的。注册中心就是维护这些调用的服务的各个服务列表。在Spring中提供了RestTemplate,用于访问Rest服务的客户端,Spring Cloud体系中也是使用RestTemplate进行服务之间的调用。

​ 负载均衡(Load Balance),通常指将请求分摊到各个操作单元上进行处理,精髓在于均衡,也就是平均。负载均衡在我们日常开发中也是经常听到的,下面介绍几种常见的负载均衡技术实现。

  1. Nginx

    ​ Nginx是我们平时使用的较多的负载均衡技术实现,性能也是很不错。一个http请求请求至Nginx服务器,Nginx服务器根据请求和一定的算法将请求转发至真正的服务器,以达到负载均衡的目的。至于Nginx里面具体的负载均衡算法,了解过Nginx的人应该会比较熟悉,没了解过的请自己去看吧。

  2. DNS解析

    ​ 在DNS服务器上配置多个域名对应ip的记录,一个域名可以对应多组的ip地址。DNS服务器在解析域名时根据相应的算法,把通过域名的请求分配到合适的真实服务器上去。这样也可以达到一定的负载均衡,不至于一个服务器的压力过大。

RestTemplate

我们先看下官方是怎么定义的:

Synchronous client to perform HTTP requests, exposing a simple, template method API over underlying HTTP client libraries such as the JDK HttpURLConnection, Apache HttpComponents, and others. The RestTemplate offers templates for common scenarios by HTTP method, in addition to the generalized exchange and execute methods that support of less frequent cases.

​ 我们可以看到,RestTemplate采用的是同步方式执行Http请求的类,底层使用的是JDK的HttpURLConnection或者ApacheHttpComponents的类库,或者其他的类库。RestTemplate还提供了模版使得开发人员能够更简单发送Http请求。

RestTemplate中定义了很多和Rest资源交互的API,下面就介绍2个我们平时常用的GET和POST请求,在RestTemplate中是怎么请求的。

GET请求:

RequestEntity requestEntity = RequestEntity.get(new URI(uri)).build();
ResponseEntity<User> responseEntity2 = this.restTemplate.exchange(requestEntity, User.class);

exchage是一个通用的请求方法,接受一个RequestEntity对象,可以设置路径,请求头,请求信息等。最后返回一个ResponeseEntity实体。

当然GET请求也可以是getForEntity()getForObject()2中类型:

//getForEntity()
ResponseEntity<User> responseEntity = this.restTemplate.getForEntity(uri, User.class);
User user = responseEntity.getBody();
//getForObject()
User user = this.restTemplate.getForObject(uri, User.class);

POST请求:

HttpEntity<MultiValueMap> request = new HttpEntity<>(map, header);    ResponseEntity<String> exchangeResult = restTemplate.exchange(url, HttpMethod.POST, request, String.class);

map中存放post的数据,header里存放请求头相关的信息,最后返回一个ResponeseEntity实体类。

同样的,POST请求也是有着对应的getForObject()getForEntity()类型:

//postForObject()
User user = this.restTemplate.postForObject(uri, user, User.class);
//postForEntity()
ResponseEntity<User> responseEntity = this.restTemplate.postForEntity(uri, user, User.class);

请他的请求,也是类似,这里就不在此列举了,感兴趣的可以查看RestTesmplate的api

Ribbon

Spring Cloud Ribbon是基于Netflix Ribbon实现的客户端负载均衡组件。区别于Nginx的服务端负载均衡的实现。在结合Spring Cloud Eureka组件使用时,ribbonServerList会被重写,改为通过Eureka的注册中心来获取服务列表,可以通过简单的几行配置来实现客户端的负载均衡。

接下来我们来使用Spring Cloud Ribbon来实现客户端的负载均衡

提前项目准备:

1.Eureka:首先我们先启动一个Eureka 服务端作为注册中心
2.然后开启2个服务,注册到Eureka服务中去,我这里开启了2个oauth服务注册到Eureka服务端中
3.开始构建具有负载均衡功能的服务消费方apiGateWay

​ 这里使用apiGateWay作为服务消费方的原因是我们应用一般都是需要权限管理,验证登录用户的,这里apiGateWay通过调用oauth应用服务来验证用户的合法性。

  1. 首先添加依赖

    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-eureka</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-ribbon</artifactId>
    </dependency>
  2. 启用服务发现客户端

    这里apiGateWay作为服务消费方,就相当于http请求过程充当了客户端的角色,被调用的服务就是服务端。先在客户端的启动类中声明要使用的RestTemplate

    @SpringBootApplication
    @EnableDiscoveryClient
    @EnableZuulProxy
    @Slf4j
    public class ApiGatewayApplication {
        public static void main(String[] args){
            SpringApplication.run(ApiGatewayApplication.class);
            log.info("ApiGatewayApplication启动");
        }
    
        @Bean
        @LoadBalanced
        RestTemplate restTemplate(){
            return new RestTemplate();
        }
    }
  3. 编写测试类

    @RestController
    @Slf4j
    public class RibbonClient {
        @Autowired
        RestTemplate restTemplate;
    
        @GetMapping("/demo")
        public String ribbonClientDemo(String paramName){
            log.info("请求参数paramName:{}",paramName);
            return restTemplate.getForObject("http://oauth/demo?paramName="+paramName,String.class);
        }
    }
  4. 启动应用,访问http://localhost:38763/demo?paramName=demo

    请求的端口是:38765
    或者是
    请求的端口是:38764

    然后我们多次发起请求,看被调用的服务的日志,可以发现请求确实被均匀的分配到开启的2个服务的。

    oauth(端口:38764)

    请求的参数是:demo
    serverPort:38764

    oauth(端口:38765)

    请求的参数是:demo
    serverPort:38765

    可以看到,2个服务被轮询调用。Ribbon默认的均衡策略是以轮询的方式去选择服务器。

    1.RandomRule:随机选取负载均衡策略,随机Random对象,在所有服务实例中随机找一个服务的索引号,然后从上线的服务中获取对应的服务。
    2.RoundRobinRule:线性轮询负载均衡策略。
    3.WeightedResponseTimeRule:响应时间作为选取权重的负载均衡策略,根据平均响应时间计算所有服务的权重,响应时间越短的服务权重越大,被选中的概率越高。刚启动时,如果统计信息不足,则使用线性轮询策略,等信息足够时,再切换到WeightedResponseTimeRule。
    4.RetryRule:使用线性轮询策略获取服务,如果获取失败则在指定时间内重试,重新获取可用服务。
    5.ClientConfigEnabledRoundRobinRule:默认通过线性轮询策略选取服务。通过继承该类,并且对choose方法进行重写,可以实现更多的策略,继承后保底使用RoundRobinRule策略。
    6.BestAvailableRule:继承自ClientConfigEnabledRoundRobinRule。从所有没有断开的服务中,选取到目前为止请求数量最小的服务。
    7.PredicateBasedRule:抽象类,提供一个choose方法的模板,通过调用AbstractServerPredicate实现类的过滤方法来过滤出目标的服务,再通过轮询方法选出一个服务。
    8.AvailabilityFilteringRule:按可用性进行过滤服务的负载均衡策略,会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,还有并发的连接数超过阈值的服务,然后对剩余的服务列表进行线性轮询。
    9.ZoneAvoidanceRule:本身没有重写choose方法,用的还是抽象父类PredicateBasedRule的choose。

    如果没有符合我们业务需求的,那么我们也可以根据业务需求自己实现一个IRule。可以通过继承AbstractLoadBalancerRule来实现我们自己的负载均衡算法:

    @Slf4j
    public class MyRule extends AbstractLoadBalancerRule {
    
        @Override
        public void initWithNiwsConfig(IClientConfig iClientConfig){
    
        }
    
        /**
         * 自定义均衡策略
         * 这里简单实现返回列表的第一个服务
         */
        @Override
        public Server choose(Object o) {
            log.info("key:" + o);
          	//获取服务列表
            List<Server> allServers = getLoadBalancer().getAllServers();
            log.info(allServers.toString());
            return allServers.get(0);
        }
    }

    我们通过实现choose方法来实现我们自己的负载均衡算法。getLoadBalancer().getAllServers()可以获取到所有的服务信息,然后我们可以根据自己的策略来确定选择哪一个服务器。

    自定义策略之后呢,我们需要在服务调用方添加一个注解配置@FeignClient+配置类来修改spring cloud的默认配置。

    首先启动类上添加注解:

    @SpringBootApplication
    @EnableDiscoveryClient
    @EnableZuulProxy
    @Slf4j
    @FeignClient(value = "oauth",configuration = RuleConfig.class)
    public class ApiGatewayApplication {
        public static void main(String[] args){
            SpringApplication.run(ApiGatewayApplication.class);
            log.info("ApiGatewayApplication启动");
        }
    
        @Bean
        @LoadBalanced
        RestTemplate restTemplate(){
            return new RestTemplate();
        }
    }

    然后创建RuleConfig类来把策略修改为我们刚刚实现的策略:

    @Configuration
    public class RuleConfig {
        @Bean
        public IRule ribbonRule() {
            return new MyRule();
        }
    }

    重新启动应用,然后我们在发起请求,就会发现这次请求就只会转发给同一个服务,也就是server列表里的第一个服务,而不在是轮询的进行请求。

    然后可以看到MyRule类打印的日志:

    请求参数paramName:demo
    key:default
    [192.168.3.2:38764, 192.168.3.2:38765]

    服务列表中依旧是2个服务在运行,但请求通过我们自定义的策略,永远只会发送给第一个服务,而不会转发给第二个服务。

    当然我们也可以通过配置文件配置,这就自己去研究吧。。。

feign

我们先来看下官网是怎么定义的:

Feign is a declarative web service client. It makes writing web service clients easier. To use Feign create an interface and annotate it. It has pluggable annotation support including Feign annotations and JAX-RS annotations. Feign also supports pluggable encoders and decoders. Spring Cloud adds support for Spring MVC annotations and for using the same HttpMessageConverters used by default in Spring Web. Spring Cloud integrates Ribbon and Eureka to provide a load balanced http client when using Feign.

Feign是一个声明示的Http客户端,它是的写Http客户端更加简单。它只需要通过注解相应的接口就可以实现,虽然通过上面的Ribbon里介绍的也可以创建Http客户端发起请求,但不是那么的优雅,Feign是NetFlix开发的声明式、模块式的HTTP客户端,可以帮助我们更好的、更快的开发调用HTTP API。

Feign应用

  1. 首先在工程中加入相应的依赖:

    <!-- feign -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-openfeign</artifactId>
    </dependency>
  2. 然后添加配置文件:

    server.port=38763
    spring.application.name=api-gateway
    spring.cloud.config.discovery.enabled=true
    spring.cloud.config.discovery.service-id=config-server
    spring.cloud.config.profile=@package.environment@
    eureka.client.service-url.defaultZone=http://localhost:38761/eureka/
  3. 创建启动类,添加注解@EnableFeignClients,开启Feign支持:

    @SpringBootApplication
    @EnableDiscoveryClient
    @EnableZuulProxy
    @Slf4j
    @EnableFeignClients
    public class ApiGatewayApplication {
        public static void main(String[] args){
            SpringApplication.run(ApiGatewayApplication.class);
            log.info("ApiGatewayApplication启动");
        }
    }
  4. 创建一个接口类IOauthClient,加入注解@FeignClient来指定这个接口要调用的服务的名称

    //使用@FeignClient注解来指定要调用的服务名称,即注册到eureka里的服务名称
    @FeignClient(name = "oauth")
    public interface IOauthClient {
    
        /**
         * value 指定要调用的接口
         * method 指定调用的方式是 GET、POST、PUT、DELETE等
         * @RequestParam 指定要传入的参数
         */
        @RequestMapping(value = "/demo",method = RequestMethod.GET)
        public String demo(@RequestParam("paramName") String paramName);
    }
  5. 然后在业务需要的地方调用该接口

    @RestController
    @Slf4j
    public class DemoController {
    
        @Autowired
        IOauthClient iOauthClient;
    
        @GetMapping("/demo")
        public String demo(String paramName){
            log.info("请求参数为:{}",paramName);
            return iOauthClient.demo(paramName);
        }
    }
  6. 启动应用,然后发起请求

    然后我们就可以看到页面上请求的返回值:

    请求的端口是:38764

    是不是和前面讲Ribbon一样的,不过这种实现方式是不是和前面的方式更加优雅呢?尤其是在调用的接口变多之后,这种实现方式是不是更加简单?

  7. 注意

    这里使用Feign的时候,需要注意的问题:

    1.GET请求多个参数的时候,需要使用@RequestParam

    2.POST请求使用@RequestBody注解参数

参考资料

欢迎关注我的公众号

本文由博客群发一文多发等运营工具平台 OpenWrite 发布

相关文章
白话SpringCloud | 第四章:服务消费者(RestTemple+Ribbon+Feign)
日志前言 上两章节,介绍了下关于注册中心-Eureka的使用及高可用的配置示例,本章节开始,来介绍下服务和服务之间如何进行服务调用的,同时会讲解下几种不同方式的服务调用. 一点知识 何为负载均衡 实现的方 ...
1
spring cloud(服务消费者(利用feign实现服务消费及负载均衡)——初学三)
日志Feign是一个声明式的Web Service客户端,我们只需要使用Feign来创建一个接口并用注解来配置它既可完成. 它具备可插拔的注解支持,包括Feign注解和JAX-RS注解.Feign也支持可 ...
1
Spring Cloud 服务消费者 rest+ribbon (二)
日志Ribbon简介      Spring Cloud Ribbon是一个基于HTTP和TCP的客户端负载均衡工具,它基于Netflix Ribbon实现.通过Spring Cloud的封装,可以让我们 ...
1
Spring Cloud学习笔记二 Eureka 服务提供者/服务消费者(ribbon)
日志Ribbon 是 Netflix 发布的开源项目,主要功能是为 REST 客户端实现负载均衡.它主要包括六个组件: ServerList,负载均衡使用的服务器列表.这个列表会缓存在负载均衡器中,并定期 ...
springcloud干货之服务消费者(ribbon)
日志springcloud系列文章的第二篇 本章介绍springcloud中的服务消费者 springcloud服务调用方式有两种实现方式: 1,restTemplate+ribbon, 2,feign ...
1
SpringCloud学习系列之二 ----- 服务消费者(Feign)和负载均衡(Ribbon)使用详解
日志前言 本篇主要介绍的是SpringCloud中的服务消费者(Feign)和负载均衡(Ribbon)功能的实现以及使用Feign结合Ribbon实现负载均衡. SpringCloud Feign Fei ...
2
玩转SpringCloud(F版本) 二.服务消费者(1)ribbon+restTemplate
日志上一篇博客有人问我,Springcloud系列会不会连载 ,大家可以看到我的标签分类里已经开设了SpringCloud专题,所以当然会连载啦,本人最近也是买了本书在学习SpringCloud微服务框架 ...
第二篇:服务消费者(RestTemplate+ribbon)
日志第一篇讲了服务的注册,这篇来说说服务的调用,服务与服务的通讯是基于http restful,springcloud的服务调用是通过ribbon方式的,客户端的负载均衡. Talk is cheap.S ...
1
SpringCloud(3)服务消费者(Feign)
日志上一篇文章,讲述了如何通过 RestTemplate+Ribbon 去消费服务,这篇文章主要讲述如何通过Feign去消费服务. 1.Feign简介 Feign是一个声明式的伪Http客户端,它使得写H ...
SpringCloud(2)服务消费者(rest+ribbon)
日志1.准备工作 这一篇文章基于上一篇文章的工程.启动eureka-server 工程,端口为 8761.分别以端口 8762 和 8763 启动 service-hi 工程.访问 localhost:8 ...
1
微服务:Eureka+Zuul+Ribbon+Feign+Hystrix构建微服务架构
日志原文地址:http://blog.csdn.net/qq_18675693/article/details/53282031 本案例将打架一个微服务框架,参考来源官方参考文档 微服务:是什么?网上有一 ...
2
SpringCloud微服务(02):Ribbon和Feign组件,实现服务调用的负载均衡
日志本文源码:GitHub·点这里 || GitEE·点这里 一.Ribbon简介 1.基本概念 Ribbon是一个客户端的负载均衡(Load Balancer,简称LB)器,它提供对大量的HTTP和TC ...
spring cloud(服务消费者(利用ribbon实现服务消费及负载均衡)——初学二)
日志Ribbon是一个基于HTTP和TCP客户端的负载均衡器,利用ribbon实现服务消费,并实现客户端的负载均衡. 一.准备工作(利用上一节的内容) 启动服务注册中心 启动computer-servic ...
(1-2)SpringCloud:服务的消费者rest+ribbon
日志服务发现的任务是由Eureka客户端完成,而服务的消费任务由Ribbon完成.Ribbon是一个基于HTTP和TCP的客户端负载据衡器,它可以通过客户端中配置ribbonServerList服务端列表 ...
1
服务间的通信 RestTemplate和Feign
日志1.RestTemplate    Spring RestTemplate 是 Spring 提供的用于访问 Rest 服务的客户端,RestTemplate 提供了多种便捷访问远程Http服务的方法 ...
2
SpringCloud教程 | 第三篇: 服务消费者(Feign)(Finchley版本)
日志上一篇文章,讲述了如何通过RestTemplate+Ribbon去消费服务,这篇文章主要讲述如何通过Feign去消费服务. 一.Feign简介 Feign是一个声明式的伪Http客户端,它使得写Htt ...
1
SpringCloud教程 | 第二篇: 服务消费者(rest+ribbon)(Finchley版本)
日志在上一篇文章,讲了服务的注册和发现.在微服务架构中,业务都会被拆分成一个独立的服务,服务与服务的通讯是基于http restful的.Spring cloud有两种服务调用方式,一种是ribbon+r ...
史上最简单的SpringCloud教程 | 第二篇: 服务消费者(rest+ribbon)
日志在上一篇文章,讲了服务的注册和发现.在微服务架构中,业务都会被拆分成一个独立的服务,服务与服务的通讯是基于http restful的.Spring cloud有两种服务调用方式,一种是ribbon+r ...
1
Spring Boot + Spring Cloud 实现权限管理系统 后端篇(十九):服务消费(Ribbon、Feign)
日志技术背景 上一篇教程中,我们利用Consul注册中心,实现了服务的注册和发现功能,这一篇我们来聊聊服务的调用.单体应用中,代码可以直接依赖,在代码中直接调用即可,但在微服务架构是分布式架构,服务都运行 ...
1
SpringCloud03 Ribbon知识点、 Feign知识点、利用RestTemplate+Ribbon调用远程服务提供的资源、利用feign调用远程服务提供的资源、熔断
日志1 远程服务资源的调用 1.1 古老的套路 在微服务出现之前,所有的远程服务资源必须通过RestTemplate或者HttpClient进行:但是这两者仅仅实现了远程服务资源的调用,并未提供负载均衡实 ...
1