欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Spring Cloud(第二章)服务提供者 Eureka + 服务消费者(rest + Ribbon)

程序员文章站 2022-03-15 23:10:05
...

    Spring Cloud Ribbon是基于Netflix Ribbon实现的一套客户端负载均衡的工具。它是一个基于HTTP和TCP的客户端负载均衡器。它可以通过在客户端中配置ribbonServerList来设置服务端列表去轮询访问以达到均衡负载的作用。

Ribbon是什么?

    Ribbon是Netflix发布的开源项目,主要功能是提供客户端的软件负载均衡算法,将Netflix的中间层服务连接在一起。Ribbon客户端组件提供一系列完善的配置项如连接超时,重试等。简单的说,就是在配置文件中列出Load Balancer(简称LB)后面所有的机器,Ribbon会自动的帮助你基于某种规则(如简单轮询,随即连接等)去连接这些机器。我们也很容易使用Ribbon实现自定义的负载均衡算法。
LB方案分类

    目前主流的LB方案可分成两类:一种是集中式LB, 即在服务的消费方和提供方之间使用独立的LB设施(可以是硬件,如F5, 也可以是软件,如nginx), 由该设施负责把访问请求通过某种策略转发至服务的提供方;另一种是进程内LB,将LB逻辑集成到消费方,消费方从服务注册中心获知有哪些地址可用,然后自己再从这些地址中选择出一个合适的服务器。Ribbon就属于后者,它只是一个类库,集成于消费方进程,消费方通过它来获取到服务提供方的地址。
Ribbon的主要组件与工作流程

    微服务架构的核心思想是,一个应用是由多个小的、相互独立的、微服务组成,这些服务运行在自己的进程中,开发和发布都没有依赖。 不同服务通过一些轻量级交互机制来通信,例如 RPC、HTTP 等,服务可独立扩展伸缩,每个服务定义了明确的边界,不同的服务甚至可以采用不同的编程语言来实现,由独立的团队来维护。 简单的来说,一个系统的不同模块转变成不同的服务!而且服务可以使用不同的技术加以实现!
Ribbon的核心组件

均为接口类型,有以下几个

ServerList

    用于获取地址列表。它既可以是静态的(提供一组固定的地址),也可以是动态的(从注册中心中定期查询地址列表)。

ServerListFilter

    仅当使用动态ServerList时使用,用于在原始的服务列表中使用一定策略过虑掉一部分地址。

IRule

    选择一个最终的服务地址作为LB结果。选择策略有轮询、根据响应时间加权、断路器(当Hystrix可用时)等。
Ribbon在工作时首选会通过ServerList来获取所有可用的服务列表,然后通过ServerListFilter过虑掉一部分地址,最后在剩下的地址中通过IRule选择出一台服务器作为最终结果。

Ribbon提供的主要负载均衡策略介绍

简单轮询负载均衡(RoundRobin)

以轮询的方式依次将请求调度不同的服务器,即每次调度执行i = (i + 1) mod n,并选出第i台服务器。

随机负载均衡 (Random)

随机选择状态为UP的Server

加权响应时间负载均衡 (WeightedResponseTime)

根据相应时间分配一个weight,相应时间越长,weight越小,被选中的可能性越低。

区域感知轮询负载均衡(ZoneAvoidanceRule)

复合判断server所在区域的性能和server的可用性选择server

准备工作

本次项目示例,改造第一篇文章中的项目,使用spring-cloud-eureka-service作为服务注册中心,spring-cloud-eureka-provider,复制三分,项目名称依次修改为spring-cloud-eureka-provider-1 [1-3]

改造 Provider

服务提供者

在项目:spring-cloud-eureka-provider-1,spring-cloud-eureka-provider-2,spring-cloud-eureka-provider-3 的启动类,都加入@Value("${server.port}"),修改home()方法, 来区分不同端口的Controller 响应,因为接下来,使用ribbon做均衡需要测试需要使用到

package io.ymq.example.eureka.provider;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.Map;

@SpringBootApplication
@EnableEurekaClient
@RestController
public class EurekaProviderApplication {
    /**
     * 读取配置文件中的端口信息
    */
    @Value("${server.port}")
    String port;
    /**
     * 读取配置文件中的应用名
     */
    @Value("${spring.application.name}")
    String name;
    /**
     * 请求路径
     */
    @RequestMapping("/hello")
    /**
     * 返回map信息
     */
    public Map<String,String> home() {
        Map<String,String> map=new HashMap<>();
        map.put("port",port);
        map.put("name",name);
        return map;
    }

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

}

修改配置
在项目:spring-cloud-eureka-provider-1,spring-cloud-eureka-provider-2,spring-cloud-eureka-provider-3,修改server: port:端口依次为8081,8082,8083

server.port=8081
spring.application.name=eureka-provider
eureka.client.serviceUrl.defaultZone=http://192.168.0.101:8761/eureka
Ribbon Consumer

服务消费者

添加依赖
新建 spring-cloud-ribbon-consumer

<?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>io.ymq.example</groupId>
    <artifactId>spring-cloud-ribbon-consumer</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>spring-cloud-ribbon-consumer</name>
    <description>Eureka Ribbon Consumer Demo project for Spring Boot</description>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.5.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <dependencies>
        <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>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!--一定要加入这个依赖  -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <!-- RELEASE -->
                <version>Finchley.RELEASE</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>

</project>
开启服务负载均衡

在工程的启动类中,通过@EnableDiscoveryClient向服务注册中心注册;并且向程序的ioc注入一个bean: restTemplate并通过@LoadBalanced注解表明这个restRemplate开启负载均衡的功能。

package io.ymq.example.ribbon.consumer;

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;

@EnableDiscoveryClient
@SpringBootApplication
public class RibbonConsumerApplication {
    /**
     * ribbon+restTemplate实现客户端负载均衡
    */
    @LoadBalanced
    @Bean
    RestTemplate restTemplate() {
        return new RestTemplate();
    }

	public static void main(String[] args) {
		SpringApplication.run(RibbonConsumerApplication.class, args);
	}
}
消费提供者方法

新建 ConsumerController 类,调用提供者的 hello 方法

package io.ymq.example.ribbon.consumer;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import java.util.Map;

/**
 * 描述:调用提供者的 `home` 方法
 *
 * @author lilei
 * @create 2019-04-23 22:48:53
 *
 * */

@RestController
public class ConsumerController {

    @Autowired
    private RestTemplate restTemplate;
        /**
         * 这个是调用eureka-consumer本身应用用的对应的hello方法
         */
    @GetMapping("/hello")
    public Map<String,String> hello() {
        /**
         * (1)http://eureka-provider/hello请求就是eureka-provider
         * 三个同名运用的 @RequestMapping("/hello")对应的home方法
         * (2)通过url就可以调用了home方法
         */
        return restTemplate.getForEntity("http://eureka-provider/hello", Map.class).getBody();
    }

}

添加配置
完整配置 application.properties

指定服务的注册中心地址,配置自己的服务端口,服务名称

server.port=8088
spring.application.name=eureka-consumer
eureka.client.serviceUrl.defaultZone=http://192.168.0.101:8761/eureka
测试服务

启动服务
依次启动项目:

spring-cloud-eureka-service
spring-cloud-eureka-provider-1
spring-cloud-eureka-provider-2
spring-cloud-eureka-provider-3
spring-cloud-ribbon-consumer

启动该工程后,访问服务注册中心,查看服务是否都已注册成功:http://192.168.0.101:8761/(192.168.0.101需要换成自己的IP)
Spring Cloud(第二章)服务提供者 Eureka + 服务消费者(rest + Ribbon)
负载均衡
在命令窗口curl http://192.168.0.101:8088/hello,发现Ribbon已经实现负载均衡

或者浏览器get 请求http://192.168.0.101:8088/hello F5 刷新
Spring Cloud(第二章)服务提供者 Eureka + 服务消费者(rest + Ribbon)
Spring Cloud(第二章)服务提供者 Eureka + 服务消费者(rest + Ribbon)
源码下载
GitHub:https://github.com/15029274098/springboot2.x-.git