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

Java Spring Cloud:(三)Spring Cloud Netflix Ribbon-8800字匠心出品

程序员文章站 2022-07-14 22:39:19
...

1.Ribbon 简介

  • Ribbon 是一个基于 Http 和 TCP 的客服端负载均衡工具,它是基于 Netflix Ribbon 实现的。它不像 spring cloud 服务注册中心、配置中心、API 网关那样独立部署,但是它几乎存在于每个 spring cloud 微服务中。
  • 包括 feign 提供的声明式服务调用也是基于该 Ribbon 实现的。Ribbon 默认提供很多种负载均衡算法,例如 轮询、随机 等等。甚至包含自定义的负载均衡算法。Ribbon 可以用于解决并提供微服务的负载均衡的问题。

2.使用 Ribbon 开发微服务

  • 在 Spring Cloud 中,使用 Ribbon 技术开发 Eureka Client 组件还是非常方便的。我们在开发过程中,不需要像 Dubbo 那样关注服务的角色。无论是 Provider 还是 Consumer 都是一个微服务客户端,只是在编码层面上,服务消费者代码的开发相对比较麻烦。我们通过简单案例测试一下 Spring Cloud 中的微服务开发过程。
  • 因为现在的 Eureka Server 部署在 Linux 中,并已为 Linux 定义了新的主机域名,需要先修改开发测试环境中的 hosts 文件 。 windows 中的 hosts 文件位于:C:\windows\system32\dirvers\etc\hosts。新增内容如下:(IP 根据具体情况配置)
192.168.2.115 eureka1 
192.168.2.116 eureka2

2.1 创建 Eureka Client 工程

Java Spring Cloud:(三)Spring Cloud Netflix Ribbon-8800字匠心出品

2.1.1 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>
	<packaging>pom</packaging>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.2.2.RELEASE</version>
	</parent>
	<groupId>com.dqcgm</groupId>
	<artifactId>cloud</artifactId>
	<version>1.0-SNAPSHOT</version>
	<dependencyManagement>
		<dependencies>
			<dependency>
				<groupId>org.springframework.cloud</groupId>
				<artifactId>spring-cloud-dependencies</artifactId>
				<version>Hoxton.SR1</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
		</dependencies>
	</dependencyManagement>
</project>

2.2 创建 Application Service 服务提供者 Module

Java Spring Cloud:(三)Spring Cloud Netflix Ribbon-8800字匠心出品

2.3 开发服务提供者 - Application Service

2.3.1 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">

	<parent>
		<artifactId>cloud</artifactId>
		<groupId>com.dqcgm</groupId>
		<version>1.0-SNAPSHOT</version>
	</parent>
	<modelVersion>4.0.0</modelVersion>

	<artifactId>applicationservice</artifactId>
	<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>
	</dependencies>
</project>

2.3.2 服务提供者代码

package com.dqcgm.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ServiceController {
	@GetMapping
	public Object first(){
		return "测试 Spring Cloud Netflix Ribbon 开发服务提供者";
	}
}

2.3.3 配置文件 application.yml

server:
	port: 8081
spring:
	application:
		name: application-service
eureka:
	client:
		service-url:
			# 配置注册中心地址。如果注册中心为多个,则配置多行地址。
			# 注册中心地址格式为: http://ip:port/eureka/
			defaultZone:
				- http://eureka1:8761/eureka/
				- http://eureka2:8761/eureka/

2.3.4 启动类

package com.dqcgm;

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

//@EnableEurekaClient 注解 - 在 Spring Cloud 低版本开发中,每个 Eureka Client 应用启动类上都必须增加此注解。
//代表当前应用是一个 Eureka Client 应用,即需要通过 Eureka Server 注册或发现服务
@SpringBootApplication
public class ServiceApp {
	public static void main(String[] args) {
		SpringApplication.run(ServiceApp.class, args);
	}
}

2.3.5 检查 Eureka Server 中的服务注册情况

Java Spring Cloud:(三)Spring Cloud Netflix Ribbon-8800字匠心出品

2.4 创建 Application Client 服务消费者 Module

Java Spring Cloud:(三)Spring Cloud Netflix Ribbon-8800字匠心出品

2.5 开发服务消费者 - Application Client

2.5.1 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">

	<parent>
		<artifactId>cloud</artifactId>
		<groupId>com.dqcgm</groupId>
		<version>1.0-SNAPSHOT</version>
	</parent>
	<modelVersion>4.0.0</modelVersion>

	<artifactId>applicationclient</artifactId>
	<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>
	</dependencies>
</project>

2.5.2 服务消费者代码

2.5.2.1 服务接口
package com.dqcgm.service;

public interface ClientService {
	String first();
}
2.5.2.2 服务实现
package com.dqcgm.service.impl;

import com.dqcgm.service.ClientService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

@Service
public class ClientServiceImpl implements ClientService {

	@Autowired
	private LoadBalancerClient loadBalancerClient;
	
	//ribbon 负载均衡器,其中记录了从 Eureka Server 中获取的所有服务信息
	@Override
	public String first() {
		//ServiceInstance 封装了服务的基本信息,如 IP,端口
		//在 Spring Cloud 中,对所有注册到 Eureka Server 中的服务都称为一个 service instance 服务实例
		//一个服务实例,就是一个有效的,可用的,服务单体实例或集群实例。
		//每个 service instance 都和 spring application name 对应
		//可以通过 spring application name 查询 service instance
		ServiceInstance si = this.loadBalancerClient.choose("application-service");
		// 拼接访问服务的 URL http://ip:port/
		StringBuilder sb = new StringBuilder();
		sb.append("http://").append(si.getHost()) .append(":").append(si.getPort()).append("/");
		System.out.println("本次访问的 service 是: " + sb.toString());
		RestTemplate rt = new RestTemplate();
		ParameterizedTypeReference<String> type = new ParameterizedTypeReference<String>() { };
		ResponseEntity<String> response = rt.exchange(sb.toString(), HttpMethod.GET, null, type);
		String result = response.getBody();

		return result;
	}
}
2.5.2.3 控制器
package com.dqcgm.controller;

import com.dqcgm.service.ClientService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ClientController {
	@Autowired
	private ClientService clientService;

	@GetMapping
	public Object first(){
		return this.clientService.first();
	}
}

2.5.3 配置文件 application.yml

server: 
	port: 8082

spring: 
	application: 
		name: application-client

eureka: 
	client: 
		service-url: 
			defaultZone: 
				- http://eureka1:8761/eureka/ 
				- http://eureka2:8761/eureka/

2.5.4 启动类

package com.dqcgm;

import org.springframework.boot.SpringApplication; 
import org.springframework.boot.autoconfigure.SpringBootApplication;

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

3.集中式与进程内负载均衡区别

  • 业界主流的负载均衡解决方案有:集中式负载均衡和进程内负载均衡

3.1 集中式负载均衡

  • 即在客户端和服务端之间使用独立的负载均衡设施(可以是硬件,如 F5, 也可以是软件,如 nginx), 由该设施负责把访问请求通过某种策略转发至服务端
    Java Spring Cloud:(三)Spring Cloud Netflix Ribbon-8800字匠心出品

3.2 进程内负载均衡

  • 将负载均衡逻辑集成到客户端组件中,客户端组件从服务注册中心获知有哪些地址可用,然后自己再从这些地址中选择出一个合适的服务端发起请求。Ribbon 就是一个进程内的负载均衡实现。
    Java Spring Cloud:(三)Spring Cloud Netflix Ribbon-8800字匠心出品

4.Ribbon 常见的负载均衡策略

  • Ribbon 就属于进程内负载均衡,它只是一个类库,集成于 Eureka Client 进程,Eureka Client进程通过访问注册中心Eureka Server发现服务列表,发现的服务列表信息是由ribbon 来管理的。当访问 Application Service 的时候,Application Client 会通过 ribbon 来找到合适的 Application Service 地址信息,并发起远程调用请求。

4.1Ribbon 中的常用负载均衡简介

  • ribbon 的负载均衡策略是通过不同的类型来实现的,下表详细介绍一些常用负载均衡策略及对应的 Ribbon 策略类。
id 策略名称 策略对应的类名 实现原理
1 轮询策略(默认) RoundRobinRule 轮询策略表示每次都顺序取下一个 provider,比如一共有 5 个 provider,第 1 次取第 1 个,第 2 次取第 2 个,第 3 次取第 3 个,以此类推
2 权重轮询策略(常用) WeightedResponseTimeRule 1. 根据每个 provider 的响应时间分配一个权重,响应时间越长,权重越小,被选中的可能性越低。 2.原理:一开始为轮询策略,并开启一个计时器,每 30 秒收集一次每个 provider 的平均响应时间,当信息足够时,给每个 provider 附上一个权重,并按权重随机选择 provider,高权越重的 provider 会被高概率选中。
3 随机策略(不推荐) RandomRule 从 provider 列表中随机选择一个 provider
4 最少并发数策略 应用在硬件软件环境一致的情况下) BestAvailableRule 选择正在请求中的并发数最小的 provider,除非这个 provider 在熔断中。
5 在“选定的负载均 衡策略”基础上进行重试机制 RetryRule 1.“选定的负载均衡策略”这个策略是轮询策略 RoundRobinRule 2.该重试策略先设定一个阈值时间段,如果在这个阈值时间段内当选择 provider 不成功,则一直尝试采 用“选定的负载均衡策略:轮询策略”最后选择一个可用的 provider
6 可用性敏感策略 (一般在同区域内服务集群环境中使用) AvailabilityFilteringRule 过滤性能差的 provider, 有 2 种:第一种:过滤掉在 eureka 中处于一直连接失败 provider 第二种:过滤掉高并发的 provider
7 区域敏感性策略(应用在大型的,物理隔离分布式环境中) ZoneAvoidanceRule 1.以一个区域为单位考察可用 性,对于不可用的区域整个丢弃,从 剩下区域中选可用的 provider 2.如果这个 ip 区域内有一个或多个实例不可达或响应变慢,都会降低该 ip 区域内其他 ip 被选中的权重。

4.2 配置负载均衡策略

  • 可以通过修改Application Client应用的全局配置文件来改变当前环境中使用的Ribbon 负载均衡策略
server: 
	port: 8082

spring: 
	application: 
		name: application-client

eureka: 
	client: 
		service-url: 
			defaultZone:
				- http://eureka1:8761/eureka/ 
				- http://eureka2:8761/eureka/

# 设置负载均衡策略。application-service 为设置负载均衡的服务名称
application-service: 
	ribbon:
		NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

5.Ribbon 的点对点直连

  • Ribbon 也可以脱离 Eureka Server 注册中心,通过配置的方式指定要调用的远程服务信息,实现 Ribbon 点对点直连。修改的配置内容如下:
server: 
	port: 8082

spring: 
	application: 
		name: application-client

# application-service : 要点对点直连的远程服务命名
application-service:
	ribbon:
		# 远程服务地址
		listOfServers: localhost:8081

# 关闭 ribbon 自动访问 eureka server 的功能
ribbon:
	eureka:
		enabled: false