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

浙公网安备 33010602011771号