Spring Cloud 入门 (五): Ribbon 实现客户端的负载均衡

本贴最后更新于 2074 天前,其中的信息可能已经水流花落

假如我们的 Hello world 服务的访问量剧增,用一个服务已经无法承载, 我们可以把 Hello World 服务做成一个集群。

很简单,我们只需要复制 Hello world 服务,同时将原来的端口 8762 修改为 8763。然后启动这两个 Spring Boot 应用, 就可以得到两个 Hello World 服务。这两个 Hello world 都注册到了 eureka 服务中心。这时候再访问 http://localhost:8761, 可以看到两个 hello world 服务已经注册。

imagepng

1. 客户端的负载均衡

负载均衡可分为服务端负载均衡和客户端负载均衡,服务端负载均衡完全由服务器处理,客户端不需要做任何事情。而客户端负载均衡技术,客户端需要维护一组服务器引用,每次客户端向服务端发请求的时候,会根据算法主动选中一个服务节点。常用的负载均衡算法有: Round Robbin, Random,Hash,StaticWeighted 等。

Spring 提供两辆种服务调度方式:Ribbon+restful 和 Feign。Ribbon 就是一个基于客户端的负载均衡器, Ribbon 提供了很多在 HTTP 和 TCP 客户端之上的控制.

Feign 内部也已经使用了 Ribbon, 所以只要使用了 @FeignClient 注解,那么这一章的内容也都是适用的。

下面就看看如何 Spring Cloud 如何用 Ribbon 来实现两个 Hello World 服务的负载均衡。以下是 Spring cloud 的 ribbon 客户端负载均衡架构图。

imagepng

hello world 服务和 ribbon 均注册到服务中心

service-hi 工程跑了两个副本,端口分别为 8762,8763,分别向服务注册中心注册, 当 sercvice-ribbon 通过 restTemplate 调用 service-Hellowworld 的接口时,利用用 ribbon 进行负载均衡,会轮流的调用处于两个不同端口的 Hello world 服务

2. 创建一个 Ribbon 服务

1) 创建一个 maven 工程,取名叫 service-ribbon, 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.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.chry</groupId>
    <artifactId>springcloud.helloworld.ribbon.service</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>
    <name>springcloud.helloworld.ribbon.service</name>
    <description>Demo project for Spring Cloud Ribbon</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.3.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>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-ribbon</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</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>Dalston.RC1</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>

    <repositories>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>
</project>

2). 创建主类 ServiceRibbonApplication

package springcloud.helloworld.ribbon.service;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
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;

@SpringBootApplication
@EnableDiscoveryClient
public class ServiceRibbonApplication {

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

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

@EnableDiscoveryClient 向服务中心注册,并且注册了一个叫 restTemplate 的 bean。

@LoadBalanced 注册表明,这个 restRemplate 是需要做负载均衡的。

3). 创建获取一个获取 Hello 内容的 service 类

package springcloud.helloworld.ribbon.client;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

@Service
public class HelloService {
    @Autowired RestTemplate restTemplate;

    public String getHelloContent() {
        return restTemplate.getForObject("http://SERVICE-HELLOWORLD/",String.class);
    }
}

这里关键代码就是, restTemplate.getForObject 方法会通过 ribbon 负载均衡机制, 自动选择一个 Hello word 服务,这里的 URL 是“http://SERVICE-HELLOWORLD/",其中的 SERVICE-HELLOWORLD 是 Hello world 服务的名字,而注册到服务中心的有两个 SERVICE-HELLOWORLD。 所以,这个调用本质是 ribbon-service 作为客户端根据负载均衡算法自主选择了一个作为服务端的 SERVICE-HELLOWORLD 服务。然后再访问选中的 SERVICE-HELLOWORLD 来执行真正的 Hello world 调用。

3. 启动 ribbon-service 应用

可以访问 http://localhost:8901/, 然后每次刷新可以看到以下两种结果交替出现,表明实际调用的是在不同端口的不同的 SERVICE-HELLOWORLD。

imagepng imagepng

  • Spring

    Spring 是一个开源框架,是于 2003 年兴起的一个轻量级的 Java 开发框架,由 Rod Johnson 在其著作《Expert One-On-One J2EE Development and Design》中阐述的部分理念和原型衍生而来。它是为了解决企业应用开发的复杂性而创建的。框架的主要优势之一就是其分层架构,分层架构允许使用者选择使用哪一个组件,同时为 JavaEE 应用程序开发提供集成的框架。

    942 引用 • 1458 回帖 • 118 关注

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...