这一章我想写 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/,就会看到一下内容:
再接下来一步,我们浏览器里访问 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
: » Spring Cloud 教程第七章 Ribbon 的负载均衡服务调用与 Feign 的区别
原创文章,作者:745907710,如若转载,请注明出处:https://blog.ytso.com/251826.html