6、SpringBoot整合ribbon项目实战

一、客户端负载均衡

    Spring Cloud Ribbon是基于HTTP和TCP的客户端负载均衡工具,它是基于Netflix Ribbon实现的。通过Spring Cloud的封装,可以轻松地将面向服务的REST模板请求,自动转换成客户端负载均衡服务调用。 客户端负载均衡示意图如下所示:

二、Ribbon负载均衡实战

    我将要建立一个组合实例spring-ribbon-eureka,他包含如下实例,各个实例的作用如下:

(1)eureka_register_service

        eureka 注册服务,提供其他服务器的注册。

(2)ribbon_service_a

        系统中提供hello服务的服务器a

(3)ribbon_service_b

        系统中同样提供hello服务的服务器b

(4)ribbon_customer

          客户端负载均衡客户,同事负载从a或b服务器随机获取hello服务,启动服务发现功能,从注册中心发现提供hello服务的a和b并负载到a或b(根据各种算法,当然默认算法是轮训)。

2.1 新建spring-ribbon-eureka父项目

eclipse建立父项目步骤如下:

File->New->Others->Maven->Maven Project,选择Create a simple project,下一步填写GroupId和ArtifactId,重点是选择Packaging为pom,然后结束创建。

(1)创建之后修改父项目依赖,以便子项目继承(将子项目公共依赖提取出来,作为公共的依赖,放到父项目依赖中)

<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.0http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <!-- 项目属性 -->
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.easystudy</groupId>
  <artifactId>spring-ribbon-eureka</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  
  <!-- 父级工程或聚合工程中,用来做jar包的版本控制 ,项目中所有要使用到的jar包的版本都集中由父工程管理-->
  <packaging>pom</packaging>
  <name>spring-ribbon-eureka</name>
  <description>SpringBoot结合eureka使用</description>
  
  <!-- 聚合的工程模块:通过继承聚合相关联-->
  <modules>
   <module>eureka_register_service</module> <!-- eureka注册中心:提供各个模块注册 -->
   <module>ribbon_service_a</module> <!-- 服务器a,提供test-service服务 -->
   <module>ribbon_service_b</module> <!-- 服务器b,提供test-service服务 -->
   <module>ribbon_customer</module> <!-- 负载均衡客户端:服务发现与服务负载均衡 -->
  </modules>
  
  <!-- spring boot项目 -->
  <parent>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-parent</artifactId>
      <version>2.0.2.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.BUILD-SNAPSHOT</spring-cloud.version>
  </properties>
  
  <!-- 项目依赖管理声明,统一管理项目依赖的版本信息,继承项目无需声明版本 -->
  <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>
  
  <!-- 远程仓库:中央仓库找不到时候,从远程仓库中查找 -->
  <repositories>
      <repository>
          <id>spring-snapshots</id>
          <name>Spring Snapshots</name>
          <url>https://repo.spring.io/snapshot</url>
          <snapshots>
              <enabled>true</enabled>
          </snapshots>
      </repository>
      <repository>
          <id>spring-milestones</id>
          <name>Spring Milestones</name>
          <url>https://repo.spring.io/milestone</url>
          <snapshots>
              <enabled>false</enabled>
          </snapshots>
      </repository>
  </repositories>
  
  <!-- 项目依赖 -->
  <dependencies>
<!-- spring boot依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--spring boot测试-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- 监控系统健康情况的工具 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- 修改自动检测加载工具 -->
    <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<!-- RESTFul接口文档:通过接口访问文档:http://localhost:8762/swagger-ui.html,8762为服务配置的监听端口,默认8080-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.2.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.2.2</version>
</dependency>
  </dependencies>
  <!-- 编译插件 -->
  <build>
      <plugins>
         <!-- SpringBoot编译插件 -->
          <plugin>
              <groupId>org.springframework.boot</groupId>
              <artifactId>spring-boot-maven-plugin</artifactId>
          </plugin>
      </plugins>
  </build>
</project>

    各个依赖如上所述,不在一一说明,请自行查询相关依赖作用。spring-ribbon-eureka作用仅仅是提供公共部分的依赖和依赖管理以及build管理。

2.2 新建 eureka_register_service项目

eureka_register_service项目作用是提供服务注册功能,所有的服务都可以通过协议注册上来。新建步骤:选择spring-ribbon-eureka父项目,右键鼠标,弹出菜单中,选择Maven->New Maven Module Project,在弹出项目编辑框选择create a simple project并填写名称,下一步填写groupid和Artifactid,选择packaging类型为jar包,然后下一步即可完成。

(1)修改此时eureka_register_service注册中心pom.xml如下。

<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.0http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <!-- 项目信息 -->
  <modelVersion>4.0.0</modelVersion>
  <artifactId>eureka_register_service</artifactId>
  <name>eureka register service</name>
  <description>注册中心</description>
 
  <!-- 父亲项目 -->
  <parent>
    <groupId>com.easystudy</groupId>
    <artifactId>spring-ribbon-eureka</artifactId>
    <version>0.0.1-SNAPSHOT</version>
  </parent>
 
  <!-- 项目依赖:特殊强制依赖,其他继承父亲 -->
  <dependencies>
       <!-- eureka服务器 -->
      <dependency>
          <groupId>org.springframework.cloud</groupId>
          <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
      </dependency>
  </dependencies>
 
</project>

我们可以看到,父亲项目为spring-ribbon-eureka,且除了父亲依赖的依赖之外,自己依赖了spring-cloud-starter-netflix-eureka-server即eureka-server组件。

(2)在src/main/java下创建com.easystudy包,并添加启动入口:EurekaServerApp

package com.easystudy;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

@EnableEurekaServer                    // 开启eureka服务
@SpringBootApplication
public class EurekaServerApp {

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

}

(3)在src/main/resources下添加启动配置文件,这里我们添加yml文件application.yml(当然可以application.properties文件,看你喜欢),配置信息如下:

# 第一个高可用注册中心
server:
  # 指定服务端口
  port: 8761
# eureka配置
eureka: 
  instance: 
    hostname: localhost
  client:
    # 是否将eureka自身作为应用注册到eureka注册中心【这里设置为false,因为eureka服务和client不可能自己监听两套端口,serviceUrl可以天其他eureka服务地址,实现高可用】
    registerWithEureka: false
    # 为true时,可以启动,但报异常:Cannot execute request on any known server
    fetchRegistry: false 
    serviceUrl: 
      # 引用对应值,通过配置其他可用的serviceUrl来实现相互注册【高可用配置】,这里可以实现本服务器注册到其他服务器去,实现服务器互为注册功能,达到两个或多个注册中心【即整个系统】的服务提供者信息共享
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
  server:
    # 关闭自我保护
    enable-self-preservation: false
    # 清理服务器
    eviction-interval-timer-in-ms: 60000
   
 # 关闭程序
endpoints:
  shutdown:
    enabled: true
    sensitive: true

 具体配置项目描述很清楚,不明白自己查一下,这里我指出重点是:server.port端口8761即启动的内置tomcat监听端口8671提供服务。eureka.client.registerWithEureka=false表明eureka自己不是服务提供者,不需要将自己注册到注册中心,否则会出错。fetchRegistry表示是否从Eureka服务器中获取注册信息,默认为true,这里因为是服务器本身,不需要获取。defaultZone为注册中信息服务器提供的注册地址。

2.3 新建ribbon_service_a项目

    ribbon_service_a项目提供hello服务,也就是他是一个地地道道的SpringBoot项目,新建过程同2.2新建eureka_register_service

(1)新建之后配置pom.xml配置如下:

<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.0http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <!-- 项目信息 -->
  <modelVersion>4.0.0</modelVersion>
  <artifactId>ribbon_service_a</artifactId>
  <name>service provider a</name>
 
  <!-- 父亲项目 -->
  <parent>
    <groupId>com.easystudy</groupId>
    <artifactId>spring-ribbon-eureka</artifactId>
    <version>0.0.1-SNAPSHOT</version>
  </parent>
 
  <!-- 特别依赖,其他依赖继承父亲,其他元素也继承父亲 -->
  <dependencies>
     <!-- spring cloud 客户注册 -->
     <dependency>
           <groupId>org.springframework.cloud</groupId>
          <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
     </dependency>
  </dependencies>
 
</project>

 (2)SpringBoot配置application.yml如下(src/main/resource)

# 多环境通用部分[各个环境可以覆盖通用字段]
spring: 
  application:
    # 通用名字,其他环境可以覆盖:为你的应用起个名字,该名字将注册到eureka注册中心
    name: test-service
server: 
  # 服务提供监听端口[eureka客户端],注意改端口不能与本机服务器端口冲突
  port: 8762
eureka:
  client:
    # 是否将eureka自身作为应用注册到eureka注册中心,默认为true
    registerWithEureka: true
    service-url:
      # 这里可以填写所有的eureka服务器地址并以','分离,当前面不能注册时候,自动选择后面的进行注册,排除单点故障问题
      defaultZone:http://localhost:8761/eureka/

(3)新建ServiceAController控制层,提供hello服务

package com.easystudy.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ServiceAController {
    
    @RequestMapping("/hello")
    public String testA(){
        return "Hello world AAAAAAAAAA!";
    }
}

 为了区分它与b服务器的打印,a它提供的hello服务打印“Hello world AAAAAAAAAA!”;

(4)创建a服务器的程序入口RibbonServiceApp

package com.easystudy;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@SpringBootApplication
@EnableDiscoveryClient     // 该注解会根据配置文件中的地址,将服务自身注册到服务注册中心
public class RibbonServiceApp {

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

}

2.3 新建ribbon_service_b项目

(1)新建ribbon_service_b

过程同ribbon_service_a

(2)修改pom配置文件

<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.0http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <!-- 项目信息 -->
  <modelVersion>4.0.0</modelVersion>
  <artifactId>ribbon_service_b</artifactId>
  <name>ribbon service b</name>
 
  <!-- 父亲项目 -->
  <parent>
    <groupId>com.easystudy</groupId>
    <artifactId>spring-ribbon-eureka</artifactId>
    <version>0.0.1-SNAPSHOT</version>
  </parent>
 
  <!-- 特别依赖,其他依赖继承父亲,其他元素也继承父亲 -->
  <dependencies>
     <!-- spring cloud 客户注册 -->
     <dependency>
           <groupId>org.springframework.cloud</groupId>
          <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
     </dependency>
  </dependencies>
 
</project>

依赖配置同service_a,注意依赖eurreka客户端注册组件。

(3)添加(src/main/resources)application.yml配置文件

# 多环境通用部分[各个环境可以覆盖通用字段]
spring: 
  application:
    # 通用名字,其他环境可以覆盖:为你的应用起个名字,该名字将注册到eureka注册中心
    name: test-service
server: 
  # 服务提供监听端口[eureka客户端],注意改端口不能与本机服务器端口冲突
  port: 8763
eureka:
  client:
    # 是否将eureka自身作为应用注册到eureka注册中心,默认为true
    registerWithEureka: true
    service-url:
      # 这里可以填写所有的eureka服务器地址并以','分离,当前面不能注册时候,自动选择后面的进行注册,排除单点故障问题
      defaultZone:http://localhost:8761/eureka/

注意:spring.application.name注册到eureka的同名的服务test-service,都提供hello服务。

(4)创建控制器ServiceBController提供服务

package com.easystudy.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ServiceBController {
    
    @RequestMapping("/hello")
    public String testB(){
        return "Hello world BBBBBBB!";
    }
}

此处service_b服务打印的是Hello world BBBBBBB!,区别与service_a

(5)创建service_b的入口RibbonServiceApp

package com.easystudy;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@SpringBootApplication
@EnableDiscoveryClient     // 该注解会根据配置文件中的地址,将服务自身注册到服务注册中心
public class RibbonServiceApp {

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

}

2.3 新建ribbon_customer项目

ribbon_service_b项目和ribbon_service_a项目都提供hello服务,ribbon_customer则是提供了ribbon_service_a和ribbon_service_b负载的hello服务,也就是说ribbon_customer注册到eureka中心获取hello服务的service_a和service_b,然后通过客户端ribbon_customer的ribbon客户端负载均衡到service_a或service_b查找hello服务。

(1)新建ribbon_customer项目,过程同以上项目

(2)修改pom.xml配置

<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.0http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <!-- 本项目信息 -->
  <modelVersion>4.0.0</modelVersion>
  <artifactId>ribbon_customer</artifactId>
  <name>customer</name>
  <description>customer by ribbon</description>
 
  <!-- 父项目 -->
  <parent>
    <groupId>com.easystudy</groupId>
    <artifactId>spring-ribbon-eureka</artifactId>
    <version>0.0.1-SNAPSHOT</version>
  </parent>
 
  <!-- 项目强依赖 -->
  <dependencies>
     <!-- spring cloud 客户注册 -->
     <dependency>
           <groupId>org.springframework.cloud</groupId>
          <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
     </dependency>
     <!-- Ribbon依赖
     <dependency>
           <groupId>org.springframework.cloud</groupId>
           <artifactId>spring-cloud-starter-ribbon</artifactId>
     </dependency>-->
     <!-- Ribbon依赖 -->
     <dependency>
       <groupId>com.netflix.ribbon</groupId>
       <artifactId>ribbon-core</artifactId>
     </dependency>        
     <dependency>
       <groupId>com.netflix.ribbon</groupId>
       <artifactId>ribbon-httpclient</artifactId>
     </dependency>
     <!-- 加入熔断机制依赖 -->
     <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
    </dependency>
  </dependencies>

注意,这里增加了ribbon依赖,hystrix熔断机制依赖

(3)增加配置文件application.yml

# 多环境通用部分[各个环境可以覆盖通用字段]
spring: 
  application:
    # 通用名字,其他环境可以覆盖:为你的应用起个名字,该名字将注册到eureka注册中心
    name: ribbon-consumer
server: 
  # 服务提供监听端口[eureka客户端],注意改端口不能与本机服务器端口冲突
  port: 8764
eureka:
  client:
    # 是否将eureka自身作为应用注册到eureka注册中心,默认为true
    registerWithEureka: true
    service-url:
      # 这里可以填写所有的eureka服务器地址并以','分离,当前面不能注册时候,自动选择后面的进行注册,排除单点故障问题
      defaultZone:http://localhost:8761/eureka/

(4)增加CustomerController

package com.easystudy.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.easystudy.service.HelloService;

@RestController
public class CustomerController {
    
    @Autowired
    HelloService service;
    
    @RequestMapping("/hi")
    public String customer(){
        return service.helloService();
    }
}

通过访问/hi访问hello服务

(4)增加hello负载均衡服务

package com.easystudy.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;

@Service
public class HelloService {
    
    @Autowired
    RestTemplate restTemplate;            // 负载均衡ribbon对象
    
    // 熔断错误回调方法
    public String helloFallBack(){
        return "Error occurred!";
    }
    
    /**
     * 调用Eureka系统中名都为test-service的ribbon_service_a或ribbon_service_b的方法/hello
     * @return
     */
    // 注解指定发生错误时的回调方法
    @HystrixCommand(fallbackMethod="helloFallBack")
    public String helloService(){
        // Get请求调用服务,restTemplate被@LoadBalanced注解标记,Get方法会自动进行负载均衡
        // restTemplate会交替调用service_a和service_b
        return restTemplate.getForObject("http://test-service/hello", String.class);
    }
}

 (5)增加启动入口

启动入口注入了RestTemplate提供负载均衡服务

package com.easystudy;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@EnableCircuitBreaker         // 开启断路器功能,进行容错管理
@EnableDiscoveryClient        // 开启服务发现功能
@SpringBootApplication        // SpringBoot应用
public class CustomerApp {

    @Bean                     // 注册一个具有容错功能的RestTemplate
    @LoadBalanced             // 开启负载均衡客户端
    RestTemplate restTemplate() {
        return new RestTemplate();
    }

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

}

三、测试

  通过访问ribbon_customer,负载到ribbon_service_a和ribbon_service_b,提供hello服务

(1)启动eureka_register_service提供eureka注册服务

(2)启动service_a服务

(3)启动service_b服务

(4)启动ribbon_customer服务

(5)访问eureka后台服务,查看test-service机器数量和状态

可以看到TEST-SERVICE服务有2机器分别对应服务名和端口为8762和8763,RIBBON-CONSUMER有一台机器对应服务端口8764;

(6)直接访问service_a服务http://localhost:8762/hello

(7)直接访问service_b服务http://localhost:8763/hello

(8)访问customer服务

再次刷新访问:

发现customer轮训负载到a和b机器提供hello服务,至此,ribbon负载均衡实例负载整个流程实例到此结束!

猜你喜欢

转载自blog.csdn.net/lixiang987654321/article/details/81542374