第一个Ribbon实例
上一章已经实现了Eureka 高可用,理论上使得微服务已经很完美了。但是,考虑到机器自身硬件条件的限制,面对流量高峰,系统同样还会存在宕机等情况。此时,如果使用Ribbon整合Eureka实现负载均衡,将用户请求分摊到多个服务上,能够大幅减轻访问服务压力,使系统达到更好的负载能力。
下面我们在前面搭建的Eureka集群基础上进行改造,具体步骤如下:
1. 改造服务提供者
后续会在服务消费者上集成Ribbon实现客户端负载均衡,为了验证服务消费者调用的是哪个服务提供者的服务,下面我们对服务提供者进行改造,改造后的服务提供者提供了“/port”API接口,用于返回服务提供者的端口号。
在项目eureka-provider和eureka-provider-another中新建controller包,并创建PortController类,该类能够返回当前项目的端口号,具体代码如例1所示。
例1 PortController.java
1 import org.springframework.beans.factory.annotation.Value;
2 import org.springframework.web.bind.annotation.RequestMapping;
3 import org.springframework.web.bind.annotation.RestController;
4 @RestController
5 public class PortController{
6 @Value("${server.port}")
7 String port;
8 @RequestMapping("port")
9 public String getPort(){
10 return "Hello World, I'm from port:"+port;
11 }
12 }
在例1中,第4行代码的@RestController注解标注在PortController类上,其效果等同于@Controller和@ResponseBody注解结合在一起使用的效果。也就是说,@RestController注解将PortController类标注为一个Controller,并且PortController中所有方法的返回对象都会自动序列化为HttpResponse对象;第6行代码的@Value注解用于将配置文件中server.port属性的值注入port;第8行代码的@RequestMapping注解用于指定getPort()方法用于处理路径为/port的请求。
2. 搭建含有Ribbon的服务消费者
(1)使用Spring Initializr方式创建一个名称为eureka-ribbon-client的Spring Boot项目,这里将Group命名为com.itheima,将Artifact命名为eureka-ribbon-client,添加Eureka Client、Ribbon和Web的依赖,项目创建好后的pom.xml文件如例2所示。
例2 eureka-ribbon-client\pom.xml
1 <?xml version="1.0" encoding="UTF-8"?>
2 <project xmlns="http://maven.apache.org/POM/4.0.0"
3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
5 https://maven.apache.org/xsd/maven-4.0.0.xsd">
6 <modelVersion>4.0.0</modelVersion>
7 <parent>
8 <groupId>org.springframework.boot</groupId>
9 <artifactId>spring-boot-starter-parent</artifactId>
10 <version>2.1.7.RELEASE</version>
11 <relativePath/> <!-- lookup parent from repository -->
12 </parent>
13 <groupId>com.itheima</groupId>
14 <artifactId>eureka-ribbon-client</artifactId>
15 <version>0.0.1-SNAPSHOT</version>
16 <name>eureka-ribbon-client</name>
17 <description>Demo project for Spring Boot</description>
18 <properties>
19 <java.version>1.8</java.version>
20 <spring-cloud.version>Greenwich.SR2</spring-cloud.version>
21 </properties>
22 <dependencies>
23 <dependency>
24 <groupId>org.springframework.boot</groupId>
25 <artifactId>spring-boot-starter-web</artifactId>
26 </dependency>
27 <dependency>
28 <groupId>org.springframework.cloud</groupId>
29 <artifactId>spring-cloud-starter-netflix-eureka-client
30 </artifactId>
31 </dependency>
32 <dependency>
33 <groupId>org.springframework.cloud</groupId>
34 <artifactId>spring-cloud-starter-netflix-ribbon
35 </artifactId>
36 </dependency>
37 <dependency>
38 <groupId>org.springframework.boot</groupId>
39 <artifactId>spring-boot-starter-test</artifactId>
40 <scope>test</scope>
41 </dependency>
42 </dependencies>
43 <dependencyManagement>
44 <dependencies>
45 <dependency>
46 <groupId>org.springframework.cloud</groupId>
47 <artifactId>spring-cloud-dependencies</artifactId>
48 <version>${spring-cloud.version}</version>
49 <type>pom</type>
50 <scope>import</scope>
51 </dependency>
52 </dependencies>
53 </dependencyManagement>
54 <build>
55 <plugins>
56 <plugin>
57 <groupId>org.springframework.boot</groupId>
58 <artifactId>spring-boot-maven-plugin</artifactId>
59 </plugin>
60 </plugins>
61 </build>
62 </project>
(2)在全局配置文件application.yml进行相关配置,包括指定应用名称、端口号、服务注册地址等信息,具体如例3所示。
例3 eureka-ribbon-client\src\main\resources\application.yml
1 spring:
2 application:
3 name: eureka-ribbon-client
4 server:
5 port: 8764
6 eureka:
7 client:
8 serviceUrl:
9 defaultZone: http://localhost:7000/eureka/
(3)在项目启动类中激活Eureka Client的相关配置。在项目启动类添加@EnableEurekaClient注解开启Eureka Client功能,如例4所示。
例4 eureka-ribbon-client\src\main\java\com\itheima\eurekaribbonclient\EurekaRibbonClientApplication.java
1 import org.springframework.boot.SpringApplication;
2 import org.springframework.boot.autoconfigure.SpringBootApplication;
3 import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
4 @EnableEurekaClient
5 @SpringBootApplication
6 public class EurekaRibbonClientApplication {
7 public static void main(String[] args) {
8 SpringApplication.run(EurekaRibbonClientApplication.class,args);
9 }
10 }
(4)创建配置类。在com.itheima.eurekaribbonclient下新建config包,并在该包下创建RibbonConfig类,该类注入restTemplate的Bean,并在这个Bean中加上@LoadBalanced注解,如例5所示。
例5 eureka-ribbon-client\src\main\java\com\itheima\eurekaribbonclient\config\RibbonConfig.java
1 import org.springframework.boot.web.client.RestTemplateBuilder;
2 import org.springframework.cloud.client.loadbalancer.LoadBalanced;
3 import org.springframework.context.annotation.Bean;
4 import org.springframework.context.annotation.Configuration;
5 import org.springframework.web.client.RestTemplate;
6 @Configuration
7 public class RibbonConfig {
8 @Bean
9 @LoadBalanced
10 public RestTemplate restTemplate(RestTemplateBuilder builder){
11 return builder.build();
12 }
13 }
在例5中,第6行代码使用@Configuration注解将RibbonConfig标注为配置类,第8行代码的@Bean注解注入restTemplate()方法返回的RestTemplate对象;第9行代码使用@LoadBalanced注解使RestTemplate具备了负载均衡的能力。
(5)创建Service类。在com.itheima. eurekaribbonclient下新建service包,并在该包下创建一个RibbonService类,在该类的hi()方法中使用restTemplate调用eureka-client的API接口,如例6所示。
例6 eureka-ribbon-client\src\main\java\com\itheima\eurekaribbonclient\service\RibbonService.java
1 import org.springframework.beans.factory.annotation.Autowired;
2 import org.springframework.stereotype.Service;
3 import org.springframework.web.client.RestTemplate;
4 @Service
5 public class RibbonService {
6 @Autowired
7 RestTemplate restTemplate;
8 public String hi(){
9 return restTemplate.getForObject
10 ("http://eureka-provider/port",String.class);
11 }
12 }
(6)创建Controller类。在com.itheima.eurekaribbonclient下新建controller的包,在该包下新建一个RibbonController的类,在该类上添加@RestController注解,将RibbonController类标注为一个Controller类,写一个hi()方法,调用RibbonService的hi()方法,如例7所示。
例7 eureka-ribbon-client\src\main\java\com\itheima\eurekaribbonclient\controller\RibbonController.java
1 import com.itheima.eurekaribbonclient.service.RibbonService;
2 import org.springframework.beans.factory.annotation.Autowired;
3 import org.springframework.web.bind.annotation.GetMapping;
4 import org.springframework.web.bind.annotation.RequestParam;
5 import org.springframework.web.bind.annotation.RestController;
6 @RestController
7 public class RibbonController {
8 @Autowired
9 RibbonService ribbonService;
10 @RequestMapping("/hi")
11 public String hi(){
12 return ribbonService.hi();
13 }
14 }
3. 测试运行
启动并访问应用。启动服务器eureka-server和eureka-server-another,服务提供者eureka-provider和eureka-provider-another,服务消费者eurek-ribbon-client,在浏览器上访问http://server1:7000
与http://server2:7009
,无论访问哪个Eureka Server,Eureka Server的注册实例都是一样的,界面显示如图1所示和图2所示。
图1 访问server1:7000的页面效果
图2 访问server2:7009的页面效果
从图1和2中可以看出,两个服务提供者和一个服务消费者已经全部成功注册到Eureka实现了高可用,为了演示含有Ribbon的服务消费者负载均衡的效果,使用浏览器多次访问http://localhost:8764/hi
,浏览器页面访问效果如图3和图4所示。
图3 浏览器页面效果(1)
图4 浏览器页面效果(2)
从图3和图4可以看出,当访问http://localhost:8764/hi
时,浏览器页面会轮流显示两个服务提供者的端口号,说明负载均衡起了效果,负载均衡器会轮流请求服务提供者中的“hi”接口。