SpringCloud中使用Ribbon的方法详解

springcloud之ribbon介绍

ribbon是负责负载均衡的,属于进程内负载均衡。请求发送到ribbon然后由ribbon发送到各个服务。

服务器端负载均衡:Nginx与F5集中式负载均衡只位于因特网与服务提供者之间,并负责把网络请求转发到各个提供单位。

进程内负载均衡是指从一个实例库选取一个实例进行流量导入,在微服务的范畴内,实例库一般是存储在Eureka、Consul、Zookeeper、etcd这样的注册中心,而此时的负载均衡器就是类似于Ribbon的IPC(Inter-Process Communication,进程间通信)组件,因此,进程内,因此,进程内负载均衡也叫做客户端负载均衡。

 Ribbon负载均衡策略

策略类 命令 描述
RandomRule 随机策略 随机选择server
RoundRobinRule 轮询策略 按照顺序循环选择server
RetryRule 重试策略

在一个配置时间段内当选择server不成功,则一直尝试选择一个可用的server

BestAvailableRule 最低并发策略 逐个考察server,如果server断路器打开,则忽略,再选择其中并发连接最低的server
AvailabilityFilteringRule 可用过滤策略 过滤掉一直连接失败并被标记位circuit tripped的server,过滤掉那些高并发连接的server(active connections超过配置的阈值)
ResponseTimeWeightedRule 响应时间加权策略 根据server的响应时间分配权重。响应时间越长,权重越低,被选择到的概率就越低;响应时间越短,权重越高,被选择到的概率就越高。这个策略很贴切,综合了各种因素,如:网络、磁盘、IO等,这些因素直接影响着响应时间。
ZoneAvoidanceRule 区域权衡策略 综合判断server所在区域的性能和server的可用性轮询选择server,并且判断一个AWS Zone的运行性能是否可用,剔除不可用的Zone中的所有server

 

可以在java配置文件中添加自己所需要的负载均衡策略如:

import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class TestConfiguration {
    @Bean
    public IRule ribbonRule(){
        return new RandomRule();
    }
}

 也可以在yml文件中配置负载均衡的实现类:(注意:yml的配置高于java配置文件,若同时配置了Java和yml则会选择yml的配置)

client-a:
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

 application.yml中配置ribbon的其他配置

client-a:
  ribbon:
    ConnectTimeout: 300000
    ReadTimeout: 300000
    MaxAutoRetries: 1 #对第一次请求的服务的重试次数
    MaxAutoRetriesNextServer: 1 #要重试的下一个服务的最大数量(不包括第一个服务)
    OkToRetryOnAllOperations: true

 ribbon默认是懒加载,所以第一次请求会慢很多(他需要从注册中心拿去服务实例列表,在进行自身策略的调整),为了避免这个问题使懒加载变为饿加载让其在项目启动时就加载,我们采用如下配置:

ribbon:
  eager-load: 
    enable: true
    clients: client-a, client-b, client-c

ribbon1.2.0之后的版本支持了yml配置ribbon的行为,也就是说通过配置文件能决定让ribbon使用哪些实现类来完成负载均衡:

ribbon各个功能的接口:这些接口在用到的时候可查有哪些实现类,若有兴趣也可自己实现具体实现类来配置。

自定义配置实现类的列表:

Ribbon实例

搭建Eureka服务器

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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>eureka-client-ribbon</groupId>
    <artifactId>eureka-client-ribbon</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>Provider8003</name>
    <description>Demo project for Spring Boot</description>

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

    <dependencies>
        <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>

        <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>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
            </dependency>
        </dependencies>
    </dependencyManagement>

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


</project>

 application.yml

server:
  port: 7001

eureka:
  instance:
    hostname: localhost

  client:
    register-with-eureka: false
    fetchRegistry: false
    service-url:
      defaultZone: http://localhost:7001/eureka

Application.java 

package com.zk.ribbon;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
@EnableEurekaServer
public class Application {
    @Bean
    @LoadBalanced
    RestTemplate restTemplate() {
        return new RestTemplate();
    }

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

 搭建服务提供者

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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>eureka-client-ribbon</groupId>
    <artifactId>eureka-client-ribbon</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>Provider8003</name>
    <description>Demo project for Spring Boot</description>

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

    <dependencies>
        <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>

        <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>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
            </dependency>
        </dependencies>
    </dependencyManagement>

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


</project>

 Police.java

package com.zk.springribbon;

public class Police {
    
    private String id;// 警察编号,用来保存用户输入的参数
    private String url;// 处理请求的服务器url
    private String message;// 提示信息
    
    
    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
    public String getUrl() {
        return url;
    }
    public void setUrl(String url) {
        this.url = url;
    }
    public String getMessage() {
        return message;
    }
    public void setMessage(String message) {
        this.message = message;
    } 
}

 PoliceApplication.java

package com.zk.springribbon;

import java.util.Scanner;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

@SpringBootApplication
@EnableEurekaClient
public class PoliceApplication {

	public static void main(String[] args) {
		Scanner scan = new Scanner(System.in);
		String port = scan.nextLine();
		new SpringApplicationBuilder(PoliceApplication.class).properties("server.port=" + port).run(args);
	}

}

 PoliceController.java

package com.zk.springribbon;
import org.apache.catalina.servlet4preview.http.HttpServletRequest;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class PoliceController {

    @RequestMapping(value="/getPolice", method=RequestMethod.GET, produces=MediaType.APPLICATION_JSON_VALUE)
    public Police getPolice(HttpServletRequest request){
        Police p = new Police();
        p.setUrl(request.getRequestURL().toString());
        p.setMessage("警察派出成功");
        return p;
    }
    
    @RequestMapping(value="/getPoliceById/{id}", method=RequestMethod.GET, produces=MediaType.APPLICATION_JSON_VALUE)
    public Police getPolice(HttpServletRequest request, @PathVariable("id") String id){
        Police p = new Police();
        p.setId(id);
        p.setUrl(request.getRequestURL().toString());
        p.setMessage("指定警察派出成功");
        return p;
    }
}

 application.yml

server:
  port: 8003

spring:
  application:
    name: springCloud-ribbon-police

eureka:
  client:
    register-with-eureka: true
    fetchRegistry: false
    service-url:
      defaultZone: http://localhost:7001/eureka

  因为需要测试负载均衡,服务提供者需要开启多个服务实例。我们使用手动读取端口号的方式,启动多个服务实例,下面启动8002、8003端口,输入localhost:7001

服务调用者

配置 pom.xml,加入springCloud核心依赖、配置及eureka客户端依赖、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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>eureka-client-ribbon</groupId>
	<artifactId>eureka-client-ribbon</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>

	<name>eureka-client-ribbon</name>
	<description>Demo project for Spring Boot</description>

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

	<dependencies>
		<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>

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

		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
		</dependency>
	</dependencies>

	<dependencyManagement>
		<dependencies>
			<dependency>
				<groupId>org.springframework.cloud</groupId>
				<artifactId>spring-cloud-dependencies</artifactId>
				<version>${spring-cloud.version}</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
			<dependency>
				<groupId>org.springframework.cloud</groupId>
				<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
			</dependency>
		</dependencies>
	</dependencyManagement>

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


</project>

 PersonApplication.java

package com.zk.springribbon;

import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

@SpringBootApplication
@EnableEurekaClient
public class PersonApplication {

	public static void main(String[] args) {
		new SpringApplicationBuilder(PersonApplication.class).web(true).run(args);
	}

}

 PersonController.java

package com.zk.springribbon;

import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@RestController
@Configuration
public class PersonController {

    @Bean
    @LoadBalanced
    public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }
    
    @RequestMapping("/getPolice")
    public String getPolice(){
        RestTemplate rt = getRestTemplate();
        String result = rt.getForObject("http://springCloud-ribbon-police/getPolice", String.class);
        return result;
    }
    
    @RequestMapping("/getPoliceById/{id}")
    public String getPoliceById(@PathVariable("id") String id){
        RestTemplate rt = getRestTemplate();
        String result = rt.getForObject("http://springCloud-ribbon-police/getPoliceById/"+id, String.class);
        return result;
    }

}

 Application.yml

server:
  port: 9090
spring:
  application:
    name: springCloud-ribbon-person
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/

  启动http://localhost:9090/getPolice,发现负载均衡服务接口已经调通了。

 

参考文档如下:https://www.cnblogs.com/li-yan-long/p/15989103.html

posted @ 2021-02-07 23:15  leagueandlegends  阅读(751)  评论(0编辑  收藏  举报