spring cloud 使用ribbon简单处理客户端负载均衡

Posted 十月围城小童鞋

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了spring cloud 使用ribbon简单处理客户端负载均衡相关的知识,希望对你有一定的参考价值。

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

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

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客户端负载均衡架构图。

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

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

2. 创建一个Ribbon服务

1) 创建一个maven工程,取名叫springcloud-membersServer, pom.xml文件如之前微服务模块springcloud-ssmServer没有新增任何依赖如下:

<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>
    <parent>
        <groupId>com.pupeiyuan.springcloud</groupId>
        <artifactId>spring-Cloud</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <artifactId>springcloud-membersServer</artifactId>

    <dependencies>
        <!-- 单元测试 -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- 支持springWEB web支持: 1、web mvc; 2、restful; 3、jackjson支持; 4、aop ........ -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- AOP依赖模块 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>1.8.7</version>
        </dependency>
        <!-- jdbc -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <scope>provided</scope>
        </dependency>

        <!-- Mybatis -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.1</version>
        </dependency>
        <!-- 通用Mapper -->
        <dependency>
            <groupId>tk.mybatis</groupId>
            <artifactId>mapper-spring-boot-starter</artifactId>
            <version>RELEASE</version>
        </dependency>
        <!-- 分页助手 -->
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper-spring-boot-starter</artifactId>
            <version>1.1.0</version>
        </dependency>
        <dependency>
            <groupId>com.github.jsqlparser</groupId>
            <artifactId>jsqlparser</artifactId>
            <version>0.9.1</version>
        </dependency>

        <!-- mysql 数据库驱动. -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <!-- 连接池 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.9</version>
        </dependency>
        <!-- jstl -->
        <dependency>
            <groupId>jstl</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>
        <dependency>
            <groupId>taglibs</groupId>
            <artifactId>standard</artifactId>
            <version>1.1.2</version>
        </dependency>
        <!-- JSP相关 -->
        <dependency>
            <groupId>com.github.jsqlparser</groupId>
            <artifactId>jsqlparser</artifactId>
            <version>0.9.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-jasper</artifactId>
            <scope>provided</scope>
        </dependency>
        <!-- httpclient -->
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <optional>true</optional>
            <scope>true</scope>
        </dependency>

        <!-- spring cloud -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-config</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-bus-amqp</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <!-- java编译插件 -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.7</source>
                    <target>1.7</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
            <!-- 这是spring boot devtool plugin -->
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <!--fork : 如果没有该项配置,肯呢个devtools不会起作用,即应用不会restart -->
                    <fork>true</fork>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

 

2)创建主类MainApplication.java

package com.pupeiyuan.config;


import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.support.SpringBootServletInitializer;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration
//扫描bean
@ComponentScan(basePackages = "com.pupeiyuan.*")
//不用自动配置数据源
@EnableDiscoveryClient
@SpringBootApplication(exclude=DataSourceAutoConfiguration.class)
public class MainApplication extends SpringBootServletInitializer {

     //相当于xml中的bean标签 用于调用当前方法获取到指定的对象
    @Bean(name="remoteRestTemplate")
    @LoadBalanced
    public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }
    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
        return builder.sources(MainApplication.class);
    }
}

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

RestTemplate为调用返回模板类、

 

3)Controller调用类 ConfigClientController.java

      
      @GetMapping("/balance")
      public void getBalance() {
        //访问提供者 获取数据 通过rest访问获取的json数据转换为的User对象
        //MULTIPLE 为eureka中提供者注册服务名称
         //InstanceInfo instanceInfo = eurekaClient.getNextServerFromEureka("MULTIPLE", false);
         //获取接口项目地址
         //String homePageUrl = instanceInfo.getHomePageUrl();
            List<NhReportStatusHistory> findList = restTemplate.getForObject("http://MULTIPLE/getDate", List.class);
      }

 

浏览器对MULTIPLE服务调用了8次,结果MULTIPLE2个服务模块各被调用4次,说明负载均衡效果达到

 

以上是关于spring cloud 使用ribbon简单处理客户端负载均衡的主要内容,如果未能解决你的问题,请参考以下文章

笔记:Spring Cloud Feign Ribbon 配置

Spring Cloud之负载均衡组件Ribbon原理分析

Spring Cloud之负载均衡组件Ribbon原理分析

Spring Cloud之负载均衡组件Ribbon原理分析

Spring Cloud之Ribbon

spring-cloud-starter-ribbon提供客户端的软件负载均衡算法