SpringCloud学习笔记之客户端负载均衡Ribbon

本文涉及的产品
应用型负载均衡 ALB,每月750个小时 15LCU
传统型负载均衡 CLB,每月750个小时 15LCU
网络型负载均衡 NLB,每月750个小时 15LCU
简介: SpringCloud学习笔记之客户端负载均衡Ribbon

SpringCloud学习笔记之客户端负载均衡Ribbon


前言

Ribbon 初识

Spring Cloud Ribbon 是一个基于 HTTP 和 TCP 的客户端负载均衡工具,它基于 Netflix Ribbon 实现。


通过 Spring Cloud Ribbon 的封装,我们在微服务架构中使用客户端负载均衡调用非常简单,仅需两步:


  • 服务提供者只需启动多个服务实例不注册到一个注册中心或者是多个相关联的服务注册中心;
  • 服务消费者直接调用被 @LoadBalanced 注解修饰过的 RestTemplate 来实现面向服务的接口调用;


项目实战

pom 依赖

<?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">
    <modelVersion>4.0.0</modelVersion>
    <groupId>top.simba1949</groupId>
    <artifactId>spring-cloud-rabbion-consumer</artifactId>
    <version>1.0-SNAPSHOT</version>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.5.RELEASE</version>
        <relativePath /> <!-- lookup parent from repository -->
    </parent>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Greenwich.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <dependencies>
        <!--spring boot starter : Core starter, including auto-configuration support, logging and YAML-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <!--spring boot starter test : Starter for testing Spring Boot applications with libraries including JUnit, Hamcrest and Mockito-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!--spring boot starter actuator:
            Starter for using Spring Boot’s Actuator which provides production ready features to help you monitor and manage your application
        -->
        <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>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <!--spring boot starter web : Starter for building web, including RestFul, applications using Spring MVC. Uses Tomcat as the default embedded container-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <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-netflix-ribbon</artifactId>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <!--编译插件-->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <!-- 配置使用的 jdk 版本 -->
                    <target>1.8</target>
                    <source>1.8</source>
                </configuration>
            </plugin>
            <!--springboot-maven打包插件 和 热部署配置-->
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <fork>true</fork> <!-- 如果没有该配置,devtools不会生效 -->
                    <executable>true</executable><!--将项目注册到linux服务上,可以通过命令开启、关闭以及伴随开机启动等功能-->
                </configuration>
            </plugin>
            <!--资源拷贝插件-->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-resources-plugin</artifactId>
                <configuration>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
        </plugins>
        <!--IDEA是不会编译src的java目录的xml文件,如果需要读取,则需要手动指定哪些配置文件需要读取-->
        <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.xml</include>
                </includes>
            </resource>
            <resource>
                <directory>src/main/resources</directory>
                <includes>
                    <include>**/*</include>
                </includes>
            </resource>
        </resources>
    </build>
</project>


application.properties

server.port=7000
spring.application.name=spring-cloud-rabbion-consumer
eureka.instance.hostname=127.0.0.1
eureka.client.service-url.defaultZone=http://${eureka.instance.hostname}:8081/eureka
eureka.client.eureka-server-connect-timeout-seconds=20
eureka.client.eureka-server-read-timeout-seconds=20


Rabbtion 配置类

package top.simba1949.config;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
/**
 * @author SIMBA1949
 * @date 2019/7/12 15:57
 */
@Configuration
public class RibbonConfig {
    @Bean
    @LoadBalanced
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }
}


JavaBean 类

package top.simba1949.common;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
/**
 * @author SIMBA1949
 * @date 2019/7/12 14:25
 */
@Data
public class UserDTO implements Serializable {
    private static final long serialVersionUID = 5572396433234547850L;
    private Integer id;
    private String username;
    private String password;
    private Date birthday;
    private Boolean adultFlag;
    private List<String> stringList;
}


控制层

package top.simba1949.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
import top.simba1949.common.UserDTO;
import java.net.URI;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
 * @author SIMBA1949
 * @date 2019/7/12 15:59
 */
@RestController
@RequestMapping("user")
public class UserController {
    private static final String SERVICE_NAME = "http://SPRING-CLOUD-RABBION-PROVIDER";
    @Autowired
    private RestTemplate restTemplate;
    @GetMapping("test")
    public String test(){
        return "SUCCESS";
    }
    @GetMapping("list")
    public List<UserDTO> userList(){
        ResponseEntity<List> resp = restTemplate.getForEntity(SERVICE_NAME + "/user/list", List.class);
        List body = resp.getBody();
        List list = restTemplate.getForObject(SERVICE_NAME + "/user/list", List.class);
        return body;
    }
    @GetMapping("get")
    public UserDTO get(UserDTO userDTO){
        Map map = new HashMap<>(16);
        map.put("id", userDTO.getId());
        map.put("username", userDTO.getUsername());
        // 通过可变参数传递参数
        ResponseEntity<UserDTO> resp = restTemplate.getForEntity(SERVICE_NAME + "/user/get?id={1}&username={2}", UserDTO.class, userDTO.getId(), userDTO.getUsername());
        // 通过 Map 传递参数
        ResponseEntity forEntity = restTemplate.getForEntity(SERVICE_NAME + "/user/get?id={id}&username={username}", UserDTO.class, map);
        UserDTO userDTO1 = restTemplate.getForObject(SERVICE_NAME + "/user/get?id={1}&username={2}", UserDTO.class, userDTO.getId(), userDTO.getUsername());
        UserDTO userDTO2 = restTemplate.getForObject(SERVICE_NAME + "/user/get?id={id}&username={username}", UserDTO.class, map);
        return null;
    }
    @PostMapping
    public String insert(@RequestBody UserDTO userDTO){
        ResponseEntity<UserDTO> resp = restTemplate.postForEntity(SERVICE_NAME + "/user/", userDTO, UserDTO.class);
        UserDTO dto = restTemplate.postForObject(SERVICE_NAME + "/user/", userDTO, UserDTO.class);
        URI uri = restTemplate.postForLocation(SERVICE_NAME + "/user/", userDTO, UserDTO.class);
        return "SUCCESS";
    }
    @PutMapping
    public String update(@RequestBody UserDTO userDTO){
        restTemplate.put(SERVICE_NAME + "/user/", userDTO, UserDTO.class);
        return "SUCCESS";
    }
    @DeleteMapping
    public String delete(Integer id){
        restTemplate.delete(SERVICE_NAME + "/user?id={1}", id);
        return "SUCCESS";
    }
}



启动类

package top.simba1949;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
/**
 * @author SIMBA1949
 * @date 2019/7/12 15:53
 */
@EnableDiscoveryClient
@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}


RestTemplate 详解

ResponseEntity

getForEntity() 方法返回的是 ResponseEntity ,该对象是 Spring 对 HTTP 请求响应的封装,其中主要存储了 HTTP 的几个重要元素,比如 HTTP 请求状态码的枚举对象 HttpStatus,在它的父类 HttpEntity 中还存储 HTTP 请求头信息对象 HttpHeaders 以及泛型类型的请求体对象。


GET 请求

getForEntity


  • url:为请求地址,http:// 服务名 / 具体请求路径
  • responseType:为请求响应体 body 的包装类型
  • uriVariables:url 中绑定的参数


通过可变参数,使用数值占位符

// 格式
public <T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Object... uriVariables)
// 示例
ResponseEntity<UserDTO> resp = restTemplate.getForEntity("http://SPRING-CLOUD-RABBION-PROVIDER/user/get?id={1}&username={2}", UserDTO.class, userDTO.getId(), userDTO.getUsername());


通过 Map, 使用 key 值占位符

// 格式
public <T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Map<String, ?> uriVariables)
// 示例
Map map = new HashMap<>(16);
map.put("id", userDTO.getId());
map.put("username", userDTO.getUsername());
ResponseEntity forEntity = restTemplate.getForEntity("http://SPRING-CLOUD-RABBION-PROVIDER/user/get?id={id}&username={username}", UserDTO.class, map);


无参数

// 格式
public <T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Object... uriVariables)
// 示例
ResponseEntity<List> resp = restTemplate.getForEntity("http://SPRING-CLOUD-RABBION-PROVIDER/user/list", List.class);


getObject

通过可变参数,使用数值占位符

// 格式
public <T> T getForObject(String url, Class<T> responseType, Object... uriVariables)
// 示例
ResponseEntity<UserDTO> resp = restTemplate.getForEntity("http://SPRING-CLOUD-RABBION-PROVIDER/user/get?id={1}&username={2}", UserDTO.class, userDTO.getId(), userDTO.getUsername());


通过 Map, 使用 key 值占位符

// 格式
public <T> T getForObject(String url, Class<T> responseType, Map<String, ?> uriVariables)
// 示例
Map map = new HashMap<>(16);
map.put("id", userDTO.getId());
map.put("username", userDTO.getUsername());
ResponseEntity forEntity = restTemplate.getForEntity("http://SPRING-CLOUD-RABBION-PROVIDER/user/get?id={id}&username={username}", UserDTO.class, map);


无参数

// 格式
public <T> T getForObject(URI url, Class<T> responseType)
// 示例
List list = restTemplate.getForObject("http://SPRING-CLOUD-RABBION-PROVIDER/user/list/user/list", List.class);


POST 请求


  • url:为请求地址,http:// 服务名 / 具体请求路径
  • request:为请求体的数据
  • responseType:为请求响应体 body 的包装类型
  • uriVariables:url 中绑定的参数


postForEntity

// 1. 数值占位符(示例参考 get 请求)
public <T> ResponseEntity<T> postForEntity(String url, @Nullable Object request,
    Class<T> responseType, Object... uriVariables)
// 2. key 值占位符(示例参考 get 请求)
public <T> ResponseEntity<T> postForEntity(String url, @Nullable Object request,
    Class<T> responseType, Map<String, ?> uriVariables)
// 3. 无 url 绑定参数(示例参考 get 请求)
public <T> ResponseEntity<T> postForEntity(URI url, @Nullable Object request, Class<T> responseType)


postForObject

// 1. 数值占位符(示例参考 get 请求)
public <T> T postForObject(String url, @Nullable Object request, Class<T> responseType,
    Object... uriVariables) 
// 2. key 值占位符(示例参考 get 请求)
public <T> T postForObject(String url, @Nullable Object request, Class<T> responseType,
    Map<String, ?> uriVariables)
// 3. 无 url 绑定参数(示例参考 get 请求)
public <T> T postForObject(URI url, @Nullable Object request, Class<T> responseType)


postForLocation

该方法实现以 POST 请求提交资源,并返回新资源的 URI

// 1. 数值占位符(示例参考 get 请求)
public URI postForLocation(String url, @Nullable Object request, Object... uriVariables)
// 2. key 值占位符(示例参考 get 请求)
public URI postForLocation(String url, @Nullable Object request, Map<String, ?> uriVariables)
// 3. 无 url 绑定参数(示例参考 get 请求)
public URI postForLocation(URI url, @Nullable Object request)


PUT 请求

// 1. 数值占位符(示例参考 get 请求)
public void put(String url, @Nullable Object request, Object... uriVariables)
// 2. key 值占位符(示例参考 get 请求)
public void put(String url, @Nullable Object request, Map<String, ?> uriVariables)
// 3. 无 url 绑定参数(示例参考 get 请求)
public void put(URI url, @Nullable Object request)


DELETE 请求

// 1. 数值占位符(示例参考 get 请求)
public void delete(String url, Object... uriVariables)
// 2. key 值占位符(示例参考 get 请求)
public void delete(String url, Map<String, ?> uriVariables)
// 3. 无 url 绑定参数(示例参考 get 请求)
public void delete(URI url)


相关实践学习
SLB负载均衡实践
本场景通过使用阿里云负载均衡 SLB 以及对负载均衡 SLB 后端服务器 ECS 的权重进行修改,快速解决服务器响应速度慢的问题
负载均衡入门与产品使用指南
负载均衡(Server Load Balancer)是对多台云服务器进行流量分发的负载均衡服务,可以通过流量分发扩展应用系统对外的服务能力,通过消除单点故障提升应用系统的可用性。 本课程主要介绍负载均衡的相关技术以及阿里云负载均衡产品的使用方法。
目录
相关文章
|
1月前
|
负载均衡 Java Nacos
Ribbon负载均衡
Ribbon负载均衡
31 1
Ribbon负载均衡
|
4月前
|
负载均衡 算法 架构师
Ribbon负载均衡
上一节就已经实现的负载均衡笔者并未深入探讨,本节通过分析负载均衡算法、Ribbon实现负载均衡的底层原理和实现过程,让大家对负载均衡有了一个大体认识,同时针对Ribbon自定义负载均衡策略,饥饿加载让大家对于Ribbon的了解又多一些。Ribbon实现的负载均衡只是方案之一,我们可以尽量多了解但不要局限于此。
|
19天前
|
消息中间件 监控 Java
如何将Spring Boot + RabbitMQ应用程序部署到Pivotal Cloud Foundry (PCF)
如何将Spring Boot + RabbitMQ应用程序部署到Pivotal Cloud Foundry (PCF)
31 6
|
19天前
|
Java 关系型数据库 MySQL
如何将Spring Boot + MySQL应用程序部署到Pivotal Cloud Foundry (PCF)
如何将Spring Boot + MySQL应用程序部署到Pivotal Cloud Foundry (PCF)
38 5
|
19天前
|
缓存 监控 Java
如何将Spring Boot应用程序部署到Pivotal Cloud Foundry (PCF)
如何将Spring Boot应用程序部署到Pivotal Cloud Foundry (PCF)
31 5
|
1月前
|
负载均衡 算法 Java
除了 Ribbon,Spring Cloud 中还有哪些负载均衡组件?
这些负载均衡组件各有特点,在不同的场景和需求下,可以根据项目的具体情况选择合适的负载均衡组件来实现高效、稳定的服务调用。
80 5
|
16天前
|
负载均衡 Java Nacos
常见的Ribbon/Spring LoadBalancer的负载均衡策略
自SpringCloud 2020版起,Ribbon被弃用,转而使用Spring Cloud LoadBalancer。Ribbon支持轮询、随机、加权响应时间和重试等负载均衡策略;而Spring Cloud LoadBalancer则提供轮询、随机及Nacos负载均衡策略,基于Reactor实现,更高效灵活。
42 0
|
3月前
|
负载均衡 Java Nacos
SpringCloud基础1——远程调用、Eureka,Nacos注册中心、Ribbon负载均衡
微服务介绍、SpringCloud、服务拆分和远程调用、Eureka注册中心、Ribbon负载均衡、Nacos注册中心
SpringCloud基础1——远程调用、Eureka,Nacos注册中心、Ribbon负载均衡
|
3月前
|
负载均衡 Java 对象存储
负载均衡策略:Spring Cloud与Netflix OSS的最佳实践
负载均衡策略:Spring Cloud与Netflix OSS的最佳实践
55 2
|
4月前
|
存储 设计模式 缓存
OpenFeign集成Ribbon负载均衡-过滤和选择服务核心实现
该文章主要介绍了如何在OpenFeign中集成Ribbon以实现负载均衡,并详细分析了Ribbon中服务选择和服务过滤的核心实现过程。文章还涉及了Ribbon中负载均衡器(ILoadBalancer)和负载均衡策略(IRule)的初始化方式。
OpenFeign集成Ribbon负载均衡-过滤和选择服务核心实现
下一篇
DataWorks