1.前言
上一节 我们实践的是 Spring Cloud 的服务注册与发现。在微服务架构中,业务基本上都会被拆分成一个独立的服务,服务与服务的通讯是基于 http restful 的。
Spring Cloud 有两种服务调用方式,一种是 Ribbon + RestTemplate,另一种是 Feign。Ribbon是一个负载均衡客户端,可以很好的控制HTTP和TCP的一些行为。我们这章就来讲讲它 -- Ribbon,如何使用 Eureka 服务注册中心,搭建一个简单的服务端注册服务,客户端调用服务的案例。
上一节:SpringCloud进击 | 一浅出:服务注册与发现(Eureka)【Finchley版本】
2.论点
我们先提出几个论点,后面来论证:
1) 假设服务提供者有一个方法,可以根据服务消费者的请求,获取到该方法的输出。
2) 假设服务消费者具备负载均衡功能,可以根据服务消费者的请求获取到不同服务提供者的相同输出(可变参数除外)。
3.准备
三个角色:
- 服务注册中心:wei-eureka-server,端口 8090,启动一个(无需修改,正常启动)
- 服务提供者:wei-service-provider,分别以 8010、8011 端口启动一次,获得两个实例的集群(无需修改,正常启动)
- 服务消费者:Ribbon,创建一个 wei-consumer-ribbon 模块,端口 8020(新建应用)
基于上一节的实践和创建好的工程,分别启动 服务注册中心:wei-eureka-server,启动 服务提供者:wei-service-provider,这都是上一节的成果。然后这节我们创建一个服务消费者(wei-consumer-ribbon),用来发送请求消费服务提供者提供的接口。
4.进击
4.1.创建服务消费者(Ribbon)
项目上新建一个模块:wei-consumer-ribbon,用来实现 Ribbon + RestTemplate。创建方法与上一节创建模块过程类似。但在Dependencies选择依赖时需要注意以下:
a) 选择左侧的 Web 后,这里需要钩上 Web 项
b) 选择左侧的 Cloud Discovery 后,这里需要钩上 Eureka Discovery 项
c) 选择左侧的 Cloud Routing后,这里需要钩上 Ribbon 项
最后点 Finish 按钮后,一个模块就自动生成了。
4.1.1.POM依赖
其 pom.xml 全内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.wei</groupId>
<artifactId>wei-consumer-ribbon</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>wei-consumer-ribbon</name>
<description>服务消费者(ribbon + rest)(Finchley版本)</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.5.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<spring-cloud.version>Finchley.SR1</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--客户端负载均衡-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
4.1.2.配置服务消费者
编写配置 application.yml
server:
port: 8020
spring:
application:
name: wei-consumer-ribbon # 指定进行服务注册时该服务的名称,服务与服务之间相互调用一般都是根据这个name
eureka:
client:
service-url:
defaultZone: http://localhost:8090/eureka/ # 指定进行服务注册的地址
- spring.application.name 属性:指定微服务应用的名称,后续在调用的时候只需要使用该名称就可以进行服务间的访问。
- eureka.client.serviceUrl.defaultZone 属性:对应服务注册中心的配置内容,指定服务注册中心的位置。
- server.port 属性:为了在本机上测试区分服务提供方和服务注册中心,使用 server.port 属性设置不同的端口。
这里,我们指定的服务注册中心地址为 http://localhost:8090/eureka/,服务名称为:wei-consumer-ribbon,程序端口为:8020
4.1.3.编写Service
package com.wei.service.demo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
@Service
public class DemoRibbonService {
@Autowired
private RestTemplate restTemplate;
/**
* 创建一个新接口用来消费服务提供者提供的接口
* 用程序名替代了具体的url地址,在ribbon中它会根据服务名来选择具体的服务实例,根据服务实例在请求的时候会用具体的url替换掉服务名
*/
public String getDemoRibbonServiceName(String name) {
String result = restTemplate.getForObject("http://wei-service-provider/demo/info?name=" + name, String.class);
result += "[Ribbon + REST]";
System.out.println(result);
return result;
}
}
使用 RestTemplate 来消费 wei-consumer-ribbon 服务的 "/demo/info" 接口。这里,用程序名替代了具体的URL地址,在 Ribbon 中它会根据服务名来选择具体的服务实例,根据服务实例在请求的时候会用具体的URL替换掉服务名。
4.1.4.编写Controller
package com.wei.controller.demo;
import com.wei.service.demo.DemoRibbonService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class DemoRibbonController {
/**
* 自动装载错误提示,不用管这个,运行的时候会被正确注入
*/
@Autowired
private DemoRibbonService demoRibbonService;
@RequestMapping(value = {"/ribbon/demo/info", "/demo/info"})
public String getDemoRibbonServiceName(@RequestParam String name) {
return demoRibbonService.getDemoRibbonServiceName(name);
}
}
写一个 controller,在 controller 中用调用 Service 的 getDemoRibbonServiceName() 方法。这里配置两个路由,请求输出效果是一样的。
4.1.5.编写启动类
package com.wei;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
@SpringBootApplication
@EnableEurekaClient
public class WeiConsumerRibbonApplication {
public static void main(String[] args) {
SpringApplication.run(WeiConsumerRibbonApplication.class, args);
}
/**
* 注解@Bean,向程序注入一个Bean
* 注解@LoadBalanced,开启RestTemplate的负载均衡功能
* 初始化RestTemplate,用来发起 REST 请求
*/
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
在工程的启动类中,通过 @LoadBalanced 注解,开启 RestTemplate 负载均衡功能。
最后,Run 一下这个启动类。
5.测试
好了,一切准备就绪。我们就来验证一下吧。
5.1.验证服务消费者
浏览器反复请求URL:http://localhost:8020/demo/info?name=tester
Hi,tester,我是服务,我被调用了,服务名为:wei-service-provider,端口为:8010[Ribbon + REST]
浏览器可始终打印上述内容。到此,论点1已经论证完成,结果与预期一致。
5.2.验证Ribbon负载均衡
但是,Ribbon 它是一个基于 HTTP 和 TCP 的客户端负载均衡器。而上述操作并没有展现这种效果,所以,我们接下来就来论证上面的论点2:假设服务消费者具备负载均衡功能,可以根据服务消费者的请求获取到不同服务提供者的相同输出(可变参数除外)。
其实只需要简单的操作就可以达到目的,就是修改一下服务提供者的端口号(由8010改为8011),然后再Run一下其启动类,以新开一个服务提供者实例。
新开一个服务提供者实例步骤如下(后继的章节不再复述):
![](https://i-blog.csdnimg.cn/blog_migrate/6f0ae5ef75173652a67142481522275d.png)
a) 在IDEA上点击Application右边的下三角,弹出选项后,点击 Edit Configuration
![](https://i-blog.csdnimg.cn/blog_migrate/e9583532ad7a0e83e3b32bab7045d244.png)
b) 打开配置后,选择需要的 Application 后,将默认的 Single instance only (单实例) 的钩去掉
c) 修改 application 文件的属性 server.port 的端口号,再运行程序启动类。如果想要多开,则每个实例需要配置不同的端口号
当端口为8011的实例跑起来之后,我们再去 Spring Eureka 的服务注册信息面板,看一看8011实例有没有被 Eureka 所发现并注册进去。
![](https://i-blog.csdnimg.cn/blog_migrate/76076990dae61bb27bd475a85cb79947.png)
嗯,看来一切正常。
现在有两个服务提供者,相当于一个小小的 Service 集群。那我们来验证一下 Ribbon 的负载均衡:
浏览器反复请求URL:http://localhost:8020/demo/info?name=tester 或者 http://localhost:8020/ribbon/demo/info?name=tester
Hi,tester,我是服务,我被调用了,服务名为:wei-service-provider,端口为:8010[Ribbon + REST]
Hi,tester,我是服务,我被调用了,服务名为:wei-service-provider,端口为:8011[Ribbon + REST]
我们可以看到浏览器也在8010和8011端口之间,也就是这个小的 Service 服务提供者集群之间交替打印输出内容。
到此,Ribbon 的负载均衡功能被实现且验证成功。论点2成立。
下一节,请继续关注:SpringCloud进击 | 三浅出:服务消费者(Feign)【Finchley版本】
5.总结
5.1.案例中有三个角色:
服务注册中心、服务提供者、服务消费者
5.2.它们的工作流:
- 启动服务注册中心
- 服务提供者生产服务并注册到服务中心
- 服务消费者从服务中心中获取服务并使用
5.3.此时的架构图:
本节源码:https://github.com/itanping/wei-springcloud/tree/master/chapter02-ribbon
6.物语
SpringCloud进击 | 一浅出:服务注册与发现(Eureka)【Finchley版本】
SpringCloud进击 | 二浅出:服务消费者(Ribbon+REST)【Finchley版本】
SpringCloud进击 | 三浅出:服务消费者(Feign)【Finchley版本】
SpringCloud进击 | 四浅出:断路器与容错(Hystrix)【Finchley版本】
SpringCloud进击 | 五浅出:服务网关 - 路由(Zuul Router)【Finchley版本】
SpringCloud进击 | 六浅出:服务网关 - 过滤器(Zuul Filter)【Finchley版本】
SpringCloud进击 | 七浅出:配置中心(Git配置与更新)【Finchley版本】
SpringCloud进击 | 一深入:配置中心(服务化与高可用)【Finchley版本】
SpringCloud进击 | 二深入:配置中心(消息总线)【Finchley版本】
SpringCloud进击 | 三深入:服务链路跟踪(Spring Cloud Sleuth)【Finchley版本】
SpringCloud进击 | 四深入:服务链路跟踪(Sleuth+Zipkin+RabbitMQ整合)【Finchley版本】
SpringCloud进击 | 五深入:断路器监控(Hystrix Dashboard)【Finchley版本】
SpringCloud进击 | 六深入:断路器聚合监控(Hystrix Turbine)【Finchley版本】
SpringCloud进击 | 七深入:高可用的服务注册中心【Finchley版本】