spring · 16 9 月, 2021 0

spring cloud负载均衡之ribbon—demo实现

在微服务实现中,比较重要的一个组建就是负载均衡,主要是同一个服务又多实例时,为了能够将请求分发到不同的实例节点上, 负载均衡是一个比不可少的组件。在spring cloud eureka的实现中,默认使用了ribbon作为服务均衡的实现, 本篇文章主要是以demo的方式优先了解ribbon的一个具体的使用,然后才能更好的从源码角度分析ribbon的工作原理。

微服务准备

在该demo种,将会创建两个简单的服务,提供相同的接口,名称为spring-cloud-eureka-client-aspring-cloud-eureka-client-b服务,这两个服务配置基本一致,不同的时,同在本地运行时,需要修改一下端口的信息。我们为了简便,会在本地运行一个简易的eureka server, 具体demo可以参考spring cloud服务注册之Eureka Server – DEMO

pom.xml

这两个项目都是maven项目,parent的依赖配置如下:

<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>org.example</groupId>
    <artifactId>spring-cloud</artifactId>
    <packaging>pom</packaging>
    <version>1.0-SNAPSHOT</version>
    <modules>
        <module>spring-cloud-eureka-server</module>
        <module>spring-cloud-eureka-client</module>
        <module>spring-cloud-eureka-client-a</module>
      <module>spring-cloud-autoconfigure</module>
    </modules>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>2.1.12.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

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

</project>

这两个微服务的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">
    <parent>
        <artifactId>spring-cloud</artifactId>
        <groupId>org.example</groupId>
        <version>1.0-SNAPSHOT</version>
        <relativePath>../pom.xml</relativePath>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>spring-cloud-eureka-client-a</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-netflix-eureka-client</artifactId>
        </dependency>

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

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-autoconfigure</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-context</artifactId>
        </dependency>

        <dependency>
            <groupId>com.netflix.eureka</groupId>
            <artifactId>eureka-client</artifactId>
        </dependency>

        <dependency>
            <groupId>com.netflix.eureka</groupId>
            <artifactId>eureka-core</artifactId>
        </dependency>

        <dependency>
            <groupId>com.netflix.ribbon</groupId>
            <artifactId>ribbon</artifactId>
        </dependency>

        <dependency>
            <groupId>com.netflix.ribbon</groupId>
            <artifactId>ribbon-core</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>


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

</project>

spring-cloud-eureka-client-a

application.yaml

yaml文件配置作为spring服务启动的默认配置文件, 具体配置如下:

spring:
  cloud:
    discovery:
      enabled: true
  application:
    name: spring-eureka-client-b
  main:
    allow-bean-definition-overriding: true
server:
  port: 8082
management:
  endpoints:
    web:
      exposure:
        include: prometheus, env,info, health
  health:
    show-details: always
eureka:
  client:
    prefer-ip-address: true
    service-url:
      defaultZone: http://localhost:8761/eureka/

spring-cloud-eureka-client-b

application.yaml

spring:
  cloud:
    discovery:
      enabled: true
  application:
    name: spring-eureka-client-b
  main:
    allow-bean-definition-overriding: true
server:
  port: 8081
management:
  endpoints:
    web:
      exposure:
        include: prometheus, env,info, health
  health:
    show-details: always
eureka:
  client:
    prefer-ip-address: true
    service-url:
      defaultZone: http://localhost:8761/eureka/

Controller

Controller在两个服务中为相同的代码,具体就是返回当前的实例信息, 具体代码如下:

package org.spring.learn.eureka.client.controller;

import com.netflix.appinfo.ApplicationInfoManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.netflix.eureka.EurekaClientConfigBean;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author xianglujun
 * @date 2021/9/15 18:26
 * @since
 */
@RestController
public class InfoController {

    @Autowired
    private ApplicationInfoManager applicationInfoManager;

    @GetMapping("/info")
    public String info() {
        return applicationInfoManager.getInfo().getId();
    }
}

Application启动类

启动类则是启动spring cloud的微服务信息, 具体源码如下:

package org.spring.learn.eureka.client;

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

@SpringBootApplication
@EnableDiscoveryClient
public class SpringEurekaClientDemoBApplication {

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

 

负载均衡客户端配置

这里我们通过引入ribbon的方式, 在客户端配置ribbon, 并负载均衡的调用以上的两个服务,具体配置如下:

RestTemplate配置

@Service
public class RibbonService {


    @LoadBalanced
    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

调用远程服务

@RestController
public class InfoController {

    @Autowired
    private RestTemplate restTemplate;

    @GetMapping("/info")
    public String info() {
        return restTemplate.getForObject("http://SPRING-EUREKA-CLIENT-B/info", String.class);
    }
}

启动服务

@SpringBootApplication
@EnableDiscoveryClient
public class SpringEurekaClientDemoApplication {

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

当服务启动完成之后,我们通过调用本地http://localhost:8080/info查看调用的实例信息, 有如下日志信息:

eureka ribbon eureka ribbon

通过浏览器上输出信息,可以知道服务均衡起到了作用,至此负载均衡的实现demo实现到此完成。