Spring Cloud 教程第七章 Ribbon 的负载均衡服务调用与 Feign 的区别

JAVA herman 33浏览 0评论

这一章我想写 Ribbon,文章的标题我想了很久,也没想出更好的标题,于是就随便起了一个标题。本文将详细的解释如何使用 Ribbon 的负载均衡策略来调用服务。

在写 Ribbon 之前,我们已经用过 Feign 来对各个服务进行调用来。本文将在前面 Feign 的基础上来阐述 Ribbon 对服务的调用,服务注册用的是之前写的 xttblog-eureka-server,服务提供者用到了 xttblog-cloud-producer

在上面两个案例的基础上,我们再新建一个 xttblog-cloud-producer2 工程。该工程的 pom.xml 和 java 代码都是一样的,只是 application.yml 中对端口做了一下修改。因为在同一台机器上运行,端口不能冲突。

server:
  port: 8889

eureka:
  instance:
    hostname: localhost
  client:
    serviceUrl:
      defaultZone: http://${eureka.instance.hostname}:8761/eureka/

spring:
  application:
    name: xttblog-cloud-producer

然后我们新建一个 xttblog-cloud-ribbon 工程,来用解释 ribbon 和 feign 的区别。相关的 pom.xml 文件内容如下:

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.sourceEncoding>UTF-8</project.reporting.sourceEncoding>
    <java.version>1.8</java.version>
</properties>

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.5.13.RELEASE</version>
</parent>

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>Edgware.SR4</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-config</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-eureka</artifactId>
    </dependency>

    <!-- 不用 feign,改用 ribbon -->
    <!-- <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-feign</artifactId>
    </dependency> -->

    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-ribbon</artifactId>
    </dependency>
</dependencies>

application.yml 文件改动也不大:

server:
  port: 7080

eureka:
  instance:
    hostname: localhost
  client:
    serviceUrl:
      defaultZone: http://${eureka.instance.hostname}:8761/eureka/

spring:
  application:
    name: xttblog-cloud-ribbon

Spring boot 的入口类,内容也很简单:

@SpringBootApplication
@EnableDiscoveryClient
public class RibbonApplication {

    //开启软均衡负载
    @LoadBalanced
    @Bean
    RestTemplate restTemplate() {
        return new RestTemplate();
    }

    public static void main(String[] args) {
        SpringApplication.run(RibbonApplication.class, args);
    }
}

Controller 类的代码,主要是想通过浏览器来测试消费者对服务的调用。

@RestController
public class RibbonController {

    @Autowired
    CalService calService;

    @RequestMapping("/test")
    public String test(@RequestParam Integer a, @RequestParam Integer b){
        return a + "+" + b + "的计算结果为:" + calService.add(a, b);
    }
}

Service 的接口类和实现类都很简单,我就贴在一起了。

public interface CalService {
    Integer add(Integer a, Integer b);
}
@Service
public class CalServiceImpl implements CalService {

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private LoadBalancerClient loadBalancerClient;

    @Override
    public Integer add(Integer a, Integer b) {
        String reqURL = "http://xttblog-cloud-producer/cal/add?a=" + a + "&b=" + b;
        test();
        return restTemplate.getForEntity(reqURL, Integer.class).getBody();
    }

    private void test(){
        ServiceInstance serviceInstance = loadBalancerClient.choose("xttblog-cloud-producer");
        System.out.println("Host:" + serviceInstance.getHost()
                + ",ServiceId:" + serviceInstance.getServiceId()
                + ",Port:" + serviceInstance.getPort());
    }
}

以上代码写完后,我们依次启动:xttblog-eureka-server、xttblog-cloud-producer、xttblog-cloud-producer2、xttblog-cloud-ribbon。

然后浏览器里访问 http://localhost:8761/,就会看到一下内容:

Eureka 服务注册中心

再接下来一步,我们浏览器里访问 http://localhost:7080/test?a=1&b=2。会把计算结果显示到浏览器上:

1+2的计算结果为:3

多次刷新访问后,控制台上打印出了一些访问服务的具体信息:

Host:localhost,ServiceId:xttblog-cloud-producer,Port:8889
Host:localhost,ServiceId:xttblog-cloud-producer,Port:8889
Host:localhost,ServiceId:xttblog-cloud-producer,Port:8889
Host:localhost,ServiceId:xttblog-cloud-producer,Port:8889
Host:localhost,ServiceId:xttblog-cloud-producer,Port:8889
Host:localhost,ServiceId:xttblog-cloud-producer,Port:8889
Host:localhost,ServiceId:xttblog-cloud-producer,Port:8888
Host:localhost,ServiceId:xttblog-cloud-producer,Port:8888
Host:localhost,ServiceId:xttblog-cloud-producer,Port:8888
Host:localhost,ServiceId:xttblog-cloud-producer,Port:8888

根据上面的信息,我们可以判断出 @LoadBalanced 默认使用的是随机访问的负载均衡策略。

再结合前面第五章的内容《Spring Cloud 教程第五章 Feign 的声明式服务调用与负载均衡》,可以看出 Feign 和 Ribbon 之间的巨大差异。总结一下,可以得出下面的结论:

  • Ribbon 的服务调用需要用到 RestTemplate 和 httpclient、okHttp 等支持
  • Feign 的负载均衡是借助 Ribbon 来实现的
  • Feign 的声明式调用,比 Ribbon 用起来更方便

在此之前,我也在网上搜索了大量的文章,发现很少有人把 Feign 和 Ribbon 之间的区别说清楚的。

ribbon 是一个基于 http 和 tcp 客户端的负载均衡,可以配置在客户端,以轮询、随机、权重等方式实现负载均衡。feign 使用起来更加方便,也是一个 http 客户端调用接口的负载均衡器,相比而言 feign 里面基本上是包括了 ribbon,调用的时候比 ribbon 体验更好,让人感觉不到是远程调用。Feign 更专注于 HTTP 协议服务的调用。feign 是远程调用的,ribbon 是做负载均衡的,feign 发请求到哪是 ribbon 决定的。feign 封装集成了 hystrix 和 ribbon,支持负载均衡和熔断。

Feign 是一个声明式的REST客户端,它的目的就是让 REST 调用更加简单。Feign 提供了 HTTP 请求的模板,通过编写简单的接口和插入注解,就可以定义好 HTTP 请求的参数、格式、地址等信息。而 Feign 则会完全代理 HTTP 请求,我们只需要像调用方法一样调用它就可以完成服务请求及相关处理。Spring Cloud 对Feign 进行了封装,使其支持 SpringMVC 标准注解和 HttpMessageConverters。Feign 可以与 Eureka 和 Ribbon 组合使用以支持负载均衡。

Ribbon 和 Feign 都是用于调用其他服务的,不过方式不同。

  • 启动类使用的注解不同,Ribbon 用的是 @RibbonClient,Feign 用的是 @EnableFeignClients。
  • 服务的指定位置不同,Ribbon 是在 @RibbonClient 注解上声明,Feign 则是在定义抽象方法的接口中使用 @FeignClient 声明。
  • 调用方式不同,Ribbon 需要自己构建 http 请求,模拟 http 请求然后使用 RestTemplate 发送给其他服务,步骤相当繁琐。

Feign 则是在 Ribbon 的基础上进行了一次改进,采用接口的方式,将需要调用的其他服务的方法定义成抽象方法即可,不需要自己构建 http 请求。不过要注意的是抽象方法的注解、方法签名要和提供服务的方法完全一致。

本文相关源码已上传至:https://github.com/xmt1139057136/xttblog-cloud

业余草公众号

最后,欢迎关注我的个人微信公众号:业余草(yyucao)!可加QQ1群:135430763,QQ2群:454796847,QQ3群:187424846。QQ群进群密码:xttblog,想加微信群的朋友,可以微信搜索:xmtxtt,备注:“xttblog”,添加助理微信拉你进群。备注错误不会同意好友申请。再次感谢您的关注!后续有精彩内容会第一时间发给您!原创文章投稿请发送至532009913@qq.com邮箱。商务合作可添加助理微信进行沟通!

本文原文出处:业余草: » Spring Cloud 教程第七章 Ribbon 的负载均衡服务调用与 Feign 的区别