文档章节

SpringCloud——使用Ribbon做负载均衡

d
 devils_os
发布于 10/09 23:07
字数 1582
阅读 843
收藏 8

Ribbon负载均衡

一、简介

1:什么是负载均衡

负载均衡建立在现有网络结构之上,它提供了一种廉价有效透明的方法扩展网络设备和服务器的带宽、增加吞吐量、加强网络数据处理能力、提高网络的灵活性和可用性。

负载均衡(Load Balance)其意思就是分摊到多个操作单元上进行执行,例如Web服务器、FTP服务器、企业关键应用服务器和其它关键任务服务器等,从而共同完成工作任务。以上内容来自于百度百科

个人理解而言,负载均衡,是弥补了单体架构或者单个服务的负载能力不足而导致的整体性能瓶颈,因此,可以通过将一个服务部署多台服务器,然后将一台机器原来的压力分摊到多个执行单元上,这样就提升了原有架构的性能瓶颈。可以理解为 “将负载均衡到多个服务中”。常见的负载均衡有两种策略:

  • Nginx独立进程做负载均衡,通过负载均衡策略,将请求转发到不同的执行单元上
  • 客户端负载均衡策略,通过在客户端保存服务列表信息,然后自己调用负载均衡策略,分摊调用不同的执行单元。

2:什么是Ribbon

Ribbon是Netflix公司开源的一个负载均衡的组件,它属于上述负载均衡方式中的第二种。将负载均衡的逻辑封装在了客户端中,并且运行在客户端。Ribbon经过了非常严格的测试,可以更好的控制Http和Tcp客户端的负载均衡行为。

Ribbon的负载均衡有两种方式

  1. 和RestTemplate结合
  2. 和Feign结合

Ribbon的核心子模块

  1. ribbon-loadbalancer:可以独立使用或者和其他模块一起使用的负载均衡API
  2. ribbon-eureka:结合Eureka作客户端的API
  3. ribbon-core:Ribbon的核心API

3:什么是RestTemplate

RestTemplate是SpringResource中一个访问第三方RESTful API接口的网络通讯框架。其主要方法都与REST的HTTP协议的方法紧密关联。 RestTemplate支持常见的HTTP请求方式,例如GET、POST、PUT、DELETE等,所以RestTemplate很容易构建RESTful API 调用方式例如

restTemplate.getForObject("http://common-service/hello", String.class)

其核心API如下
https://docs.spring.io/spring/docs/3.0.x/javadoc-api/org/springframework/web/client/RestTemplate.html

二、开始使用Ribbon

Ⅰ.代码编写

  1. ribbon-test父项目
  • pom.xml
<groupId>com.calvin.ribbon</groupId>
 <artifactId>ribbon-test</artifactId>
 <packaging>pom</packaging>
 <version>1.0-SNAPSHOT</version>

 <modules>
     <module>common-service</module>
     <module>eureka-server</module>
     <module>ribbon-service</module>
 </modules>

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

 <dependencyManagement>
     <dependencies>
         <dependency>
             <groupId>org.springframework.cloud</groupId>
             <artifactId>spring-cloud-dependencies</artifactId>
            <version>Dalston.SR4</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>
  1. eureka-server
  • pom.xml
<parent>
    <groupId>com.calvin.ribbon</groupId>
    <artifactId>ribbon-test</artifactId>
    <version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>eureka-server</artifactId>
<properties>
    <java.version>1.8</java.version>
</properties>

<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-eureka-server</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

application.yml

server:
  port: 8080
eureka:
  instance:
    hostname: localhost
  client:
    register-with-eureka: false
    fetch-registry: false
    service-url:
      defaultZone:
        http://${eureka.instance.hostname}:${server.port}/eureka

  • ServerApplication.java
@EnableEurekaServer
@SpringBootApplication
public class ServerApplication {

    public static void main(String[] args) {
        SpringApplication.run(ServerApplication.class);
    }
}
  1. commons-service
  • pom.xml
<parent>
    <artifactId>ribbon-test</artifactId>
    <groupId>com.calvin.ribbon</groupId>
    <version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>common-service</artifactId>

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

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>
  • application.yml
spring:
  application:
    name: common-service

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8080/eureka/

此处没有指定server.port,是因为我们在启动此服务的是时候做点手脚,需要以不同端口在本地启动, 即配置两个Name不同的启动类,给分别指定不同的Environment variables,内容为server.port=8083, server.port=8084 具体教程是在Idea下的EditConfiguration中做如下操作:

  • CommonServiceApplication.java
@SpringBootApplication
@EnableEurekaClient
public class CommonServiceApplication {

    public static void main(String[] args) {
        SpringApplication.run(CommonServiceApplication.class);
    }
}
  • HelloController.java
@RestController
public class HelloController {

    @Value("${server.port}")
    private String port;

    /**
     * 接口测试
     * @return
     */
    @GetMapping("/hello")
    public String sayHello(){
        return "port : " + port ;
    }
}

  1. ribbon-service
  • pom.xml
<parent>
    <artifactId>ribbon-test</artifactId>
    <groupId>com.calvin.ribbon</groupId>
    <version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>ribbon-service</artifactId>
<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-eureka</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</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-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>
<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>
  • application.yml
server:
  port: 8082
spring:
  application:
    name: ribbon-service

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8080/eureka/
  • RibbonClientApplication.java
@EnableEurekaClient
@SpringBootApplication
public class RibbonServerApplication {

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

    /**
     * 配置LoadBalance和RestTemplate
     * @return RestTemplate
     */
    @Bean
    @LoadBalanced
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }

}

接下来就是调用的关键代码

  • RemoteCommonService.java
/**
 * <p> 
 *	CommonService服务远程调用类
 * </p>
 * @author Calvin
 * @date 2019/10/09
 * @since 1.0
 */
@Service
public class RemoteCommonService {

    /**
     * 注入RestTemplate
     */
    @Autowired
    private RestTemplate restTemplate;

    /**
     * 远程调用common-service/hello
     * @return
     */
    public String sayHi(){
        return restTemplate.getForObject("http://common-service/hello", String.class);
    }

}

  • SayHiController.java
@RestController
public class SayHiController {


    @Autowired
    private RemoteCommonService remoteCommonService;

    @GetMapping("hi")
    public String sayHi(){
        return remoteCommonService.sayHi() + ", this is ribbon service";
    }

}

Ⅱ.配置启动

最终配置四个启动类,如图所示:

启动顺序:

  • step1. EurekaSeverApplicaton
  • step2. CommonServiceApplication
  • step3. CommonServiceApplication2
  • step4. RibbonServerApplication

Ⅲ.结果验证

Eureka管理界面 http://localhost:8080/

调用 http://localhost:8082/hi

刷新页面

三、核心剖析——LoadBalancerClient

负载均衡的核心类是LoadBalanceClient,此类可以获取负载均衡的服务提供者的实例信息,当然这些实例信息是通过EurekaClient获取的,并且缓存了一份服务实例信息。

@Autowired
    private LoadBalancerClient loanBalanceClient;

    /**
     * 远程调用common-service/hello
     * @return
     */
    public String sayHi(){
        ServiceInstance serviceInstance = loanBalanceClient.choose("common-service");
        logger.info("current service info is {} : {}", serviceInstance.getHost(), serviceInstance.getPort());
        return restTemplate.getForObject("http://common-service/hello", String.class);
    }

此时不断刷接口,同样可以看到LoadBalancerClient在不断的改变请求的实例信息。

四、小结

  1. 认识了关于Ribbon以及常用负载均衡的概念
  2. 动手实践了一下Ribbon进行负载均衡的调用
  3. 认识Ribbon的一个核心类

五、总结

  1. 本文首次实践Ribbon做负载均衡,缺乏原理剖析
  2. 文章中代码相对简单,但是基本可以表达Ribbon所做的事情
  3. 需要在以后,对整个Ribbon的源码进行解析(算是插眼)
  4. 关于RestTemplate还有很多用法,后续可以专门出文章进行深入理解

© 著作权归作者所有

d
粉丝 0
博文 12
码字总数 19469
作品 0
昌平
后端工程师
私信 提问
加载中

评论(2)

desireljw
desireljw
排版有点乱呢
d
devils_os 博主
谢谢指正,以后我会尽量让排版好点的
SpringCloud学习系列之二 ----- 服务消费者(Feign)和负载均衡(Ribbon)

前言 本篇主要介绍的是SpringCloud中的服务消费者(Feign)和负载均衡(Ribbon)功能的实现以及使用Feign结合Ribbon实现负载均衡。 SpringCloud Feign Feign 介绍 Feign是一个声明式的Web Servi...

虚无境
01/15
434
0
【Spring Cloud】分布式必学springcloud(一)——简介和看法

一、前言 开篇之前,我想说,springcloud会完胜dubbo。 小编以前做分布式是用的webservice、dubbo。最近的项目中,开始使用了springcloud,springcloud包含了很多的组件,这些组件是dubbo没有...

kisscatforever
2018/04/16
0
0
springcloud eureka 服务注册中心

------------------------------------------------------------------------------------------------------------ springcloud (零) springboot 基础 下载 springcloud (一)服务注册中心 ......

curiousby
2017/02/08
0
0
【Spring Cloud】分布式必学springcloud(四)——客户端负载均衡Ribbon

一、前言 前几篇博客,对springcloud的注册中心Eureka做了说明,并且提供者可以注册到注册中心上,客户端可以面向服务的调用Restful接口。有的时候我们需要对提供者做负载均衡,SpringCloud...

kisscatforever
2018/04/20
0
0
springcloud 服务网关 gateway zuul

------------------------------------------------------------------------------------------------------------ springcloud (零) springboot 基础 下载 springcloud (一)服务注册中心 ......

curiousby
2017/02/17
0
0

没有更多内容

加载失败,请刷新页面

加载更多

解答二进制求和

思路:创建一个新的字符串,用于记录原两个字符串每位相加的结果。 1、因为是从左到右计算,所以要把字符串先进行反转,用reverse()方法。 2、字符串对齐,采用补零的方法。 3、计算的时候...

无名氏的程序员
23分钟前
4
0
JSONUtils

package com.demo.utils;import java.util.ArrayList;import java.util.HashMap;import java.util.Iterator;import java.util.List;import java.util.Map;import java.util.Tr......

任梁荣
23分钟前
5
1
在jest中配置typescript

测试是报错: Property 'assign' does not exist on type 'ObjectConstructor' NodeJS已经是最新版了,但道理不需要polyfill。 然后发现是typescript的lib没有"es2015.core",说明ts-jest没有......

linsk1998
24分钟前
3
0
Redis实现分布式文件夹锁

缘起 最近做一个项目,类似某度云盘,另外附加定制功能,本人负责云盘相关功能实现,这个项目跟云盘不同的是,以项目为分配权限的单位,同一个项目及子目录所有有权限的用户可以同时操作所有...

逸竹小站
33分钟前
3
0
Andorid SQLite数据库开发基础教程(2)

Andorid SQLite数据库开发基础教程(2) 数据库生成方式 数据库的生成有两种方式,一种是使用数据库管理工具生成的数据库,我们将此类数据库称为预设数据库,另一种是使用代码生成的数据库。...

大学霸
53分钟前
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部