简单使用 Ribbon 实现微服务高可用通信
负载均衡按实现分类方式,可以分为服务端负载均衡和客户端负载均衡
服务端负载均衡
在架构中会提供专用的负载均衡器,由负载均衡器持有后端节点的信息,服务消费者发来的请求经由专用的负载均衡器分发给服务提供者,进而实现负载均衡。
常用的负载均衡器硬件有:F5、Nginx、HaProxy 等。
客户端负载均衡
在架构中不在部署额外的负载均衡器,在每个服务消费者内部持有服务端负载均衡器,由内置的负载均衡策略决定向哪个服务提供者发起请求。
常用的有:Netfilx Ribbon
Ribbon + RestTemplate 实现服务间高可用通信
在Spring Initializr 中创建 spring boot 项目,构建地址使用的是 https://start.aliyun.com
。
搭建环境
Ip | 端口 | 描述 |
---|---|---|
192.168.1.102 | 8848 | Nacos 注册中心实例 |
192.168.1.101 | 9081 | 服务提供者1 |
192.168.1.102 | 9081 | 服务提供者2 |
192.168.1.101 | 9091 | 消费者 |
第一步,创建服务提供者
pom.xml 依赖有
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
application.properties 配置文件
# 应用名称
spring.application.name=provider-service
# 应用服务 WEB 访问端口
server.port=9080
# Nacos帮助文档: https://nacos.io/zh-cn/docs/concepts.html
# Nacos认证信息
spring.cloud.nacos.discovery.username=nacos
spring.cloud.nacos.discovery.password=nacos
# Nacos 服务发现与注册配置,其中子属性 server-addr 指定 Nacos 服务器主机和端口
spring.cloud.nacos.discovery.server-addr=192.168.1.102:8848
# 注册到 nacos 的指定 namespace,默认为 public
spring.cloud.nacos.discovery.namespace=public
创建服务提供者的接口
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ProviderController {
@GetMapping("/provider/msg")
public String sendMessage() {
return "这个服务提供接口";
}
}
打包运行后出现如下:
第二部,创建服务消费者
构建流程与创建服务提供者一样,创建 consumer-service。
pom.xml 配置
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-netflix-ribbon</artifactId>
<version>${spring-cloud-alibaba.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
在启动类中声明 RestTemplate
@SpringBootApplication
public class ConsumerServiceApplication {
// 创建 RestTemplate 对象
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
public static void main(String[] args) {
SpringApplication.run(ConsumerServiceApplication.class, args);
}
}
消费者接口
@RestController
public class ConsumerController {
@Resource
private LoadBalancerClient loadBalancerClient;
@Resource
private RestTemplate restTemplate;
@GetMapping("/consumer/msg")
public String getProviderMessage() {
// loadBalancerClient.choose() 方法会从 Nacos 获取 provider-service 所有可用实例
// 并按负载均衡策略从中选择一个可用实例,封装为 ServiceInstance (服务实例)对象
// 结合享有环境,两个实例选择一个包装为 ServiceInstance
ServiceInstance serviceInstance = loadBalancerClient.choose("provider-service");
String host = serviceInstance.getHost();
int port = serviceInstance.getPort();
System.out.println("本次调用 provider-service 的" + host + ":" + port + "实例节点负责处理");
String result = restTemplate.getForObject("http://" + host + ":" + port + "/provider/msg",
String.class);
String resultString = "provider-service 响应数据:" + result;
System.out.println(resultString);
return resultString;
}
}
Ribbon 的执行流程如上
- 先从 Nacos 获取可用服务提供实例信息
- 在通过 RestTemplate.getForObject() 向改实例发起 RESTful 请求请求完成处理
打包运行后
浏览器执行地址 http://localhost:9091/consumer/msg,响应数据如下
Ribbon 的负载均衡策略
RoundRobinRule
轮询策略,Ribbon 默认策略,默认超过 10 次获取到的 server 都不可用,会返回一个空的 server。
RandomRule
随机策略,如果随机到的 server 为 null 或者不可用的话,会不停低循环选取
RetryRule
重试策略,一定时限循环重试
BestAvailableRule
最小连接数策略,遍历 serverList,选取出可用的且连接数最小的一个 server,会调用 RoundRobinRule 重新选取。
AvailabilityFilteringRule
可用过滤策略,扩展了轮询策略,会先通过默认的轮询选取一个 server,再去判断该 server 是否超过可用、当前连接数是否超限,都成功再返回。
ZoneAvoiddanceRule
区域权衡策略,扩展了轮询策略,处理过滤超时和连接数过多的 server,还会过滤掉不符合要求的 zone 区域里面的所有节点,始终保证在一个区域/机房的服务实例进行轮询。
使用方法
consumer 配置文件中添加一下内容
#针对client-a服务使用随机策略
consumer-service.ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RandomRule