2.【Spring Cloud Alibaba】实现负载均衡-Ribbon
负载均衡的两种方式
如何实现负载均衡
目前已经实现让A总能找到B,如何实现负载均衡
负载均衡的两种方式
- 服务器端负载均衡
- 客户端负载均衡
使用Ribbo实现负载均衡
Ribbon是什么
Netflix开源的客户端侧负载均衡器
引入Ribbon后的架构演进
整合Ribbon实现负载均衡
// 在spring容器中,创建一个对象,类型RestTemplate;名称/ID是:restTemplate
// <bean id="restTemplate" class="xxx.RestTemplate"/>
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
RestTemplate template = new RestTemplate();
return template;
}
@Autowired
private RestTemplate restTemplate;
@GetMapping("/test-rest-template-sentinel/{userId}")
public UserDTO test(@PathVariable Integer userId) {
return this.restTemplate
.getForObject(
"http://user-center/users/{userId}",
UserDTO.class, userId);
}
Ribbon的组成
Ribbon内置的负载均衡规则
细粒度配置自定义
- Java代码配置
- 用配置属性配置
- 最佳实践总结
Java代码配置
@Configuration
@RibbonClient(name = "user-center",configuration = RibbonConfiguration.class)
public class UserCenterRibbonConfiguration {
}
@Configuration
public class RibbonConfiguration {
@Bean
public IRule ribbonRule() {
return new NacosSameClusterWeightedRule();
}
}
用配置属性配置
user-center:
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
两种方式对比
Ribbon全局配置
@Configuration
@RibbonClients(defaultConfiguration = RibbonConfiguration.class)
public class UserCenterRibbonConfiguration {
}
@Configuration
public class RibbonConfiguration {
@Bean
public IRule ribbonRule() {
return new NacosSameClusterWeightedRule();
}
}
Ribbon饥饿加载配置方式
ribbon:
eager-load:
enabled: true
clients: user-center
扩展Ribbon-支持Nacos权重
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.alibaba.nacos.NacosDiscoveryProperties;
import org.springframework.cloud.alibaba.nacos.ribbon.NacosServer;
@Slf4j
public class NacosWeightedRule extends AbstractLoadBalancerRule {
@Autowired
private NacosDiscoveryProperties nacosDiscoveryProperties;
@Override
public void initWithNiwsConfig(IClientConfig clientConfig) {
// 读取配置文件,并初始化NacosWeightedRule
}
@Override
public Server choose(Object key) {
try {
BaseLoadBalancer loadBalancer = (BaseLoadBalancer) this.getLoadBalancer();
// log.info("lb = {}", loadBalancer);
// 想要请求的微服务的名称
String name = loadBalancer.getName();
// 拿到服务发现的相关API
NamingService namingService = nacosDiscoveryProperties.namingServiceInstance();
// nacos client自动通过基于权重的负载均衡算法,给我们选择一个实例。
Instance instance = namingService.selectOneHealthyInstance(name);
log.info("选择的实例是:port = {}, instance = {}", instance.getPort(), instance);
return new NacosServer(instance);
} catch (NacosException e) {
return null;
}
}
}
// spring cloud commons --> 定义了标准
// spring cloud loadbalancer --> 没有权重
扩展Ribbon-同一集群优先调用
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.alibaba.nacos.client.naming.core.Balancer;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.AbstractLoadBalancerRule;
import com.netflix.loadbalancer.BaseLoadBalancer;
import com.netflix.loadbalancer.Server;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.alibaba.nacos.NacosDiscoveryProperties;
import org.springframework.cloud.alibaba.nacos.ribbon.NacosServer;
import org.springframework.util.CollectionUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
@Slf4j
public class NacosSameClusterWeightedRule extends AbstractLoadBalancerRule {
@Autowired
private NacosDiscoveryProperties nacosDiscoveryProperties;
@Override
public void initWithNiwsConfig(IClientConfig clientConfig) {
}
@Override
public Server choose(Object key) {
try {
// 拿到配置文件中的集群名称 BJ
String clusterName = nacosDiscoveryProperties.getClusterName();
BaseLoadBalancer loadBalancer = (BaseLoadBalancer) this.getLoadBalancer();
// 想要请求的微服务的名称
String name = loadBalancer.getName();
// 拿到服务发现的相关API
NamingService namingService = nacosDiscoveryProperties.namingServiceInstance();
// 1. 找到指定服务的所有实例 A
List<Instance> instances = namingService.selectInstances(name, true);
// 2. 过滤出相同集群下的所有实例 B
List<Instance> sameClusterInstances = instances.stream()
.filter(instance -> Objects.equals(instance.getClusterName(), clusterName))
.collect(Collectors.toList());
// 3. 如果B是空,就用A
List<Instance> instancesToBeChosen = new ArrayList<>();
if (CollectionUtils.isEmpty(sameClusterInstances)) {
instancesToBeChosen = instances;
log.warn("发生跨集群的调用, name = {}, clusterName = {}, instances = {}",
name,
clusterName,
instances
);
} else {
instancesToBeChosen = sameClusterInstances;
}
// 4. 基于权重的负载均衡算法,返回1个实例
Instance instance = ExtendBalancer.getHostByRandomWeight2(instancesToBeChosen);
log.info("选择的实例是 port = {}, instance = {}", instance.getPort(), instance);
return new NacosServer(instance);
} catch (NacosException e) {
log.error("发生异常了", e);
return null;
}
}
}
class ExtendBalancer extends Balancer {
public static Instance getHostByRandomWeight2(List<Instance> hosts) {
return getHostByRandomWeight(hosts);
}
}
扩展Ribbon-基于元数据的版本控制
元数据
元数据就是一堆的描述信息,以map存储。举个例子:
spring:
cloud:
nacos:
metadata:
# 自己这个实例的版本
version: v1
# 允许调用的提供者版本
target-version: v1
代码实现
@Slf4j
public class NacosFinalRule extends AbstractLoadBalancerRule {
@Autowired
private NacosDiscoveryProperties nacosDiscoveryProperties;
@Override
public Server choose(Object key) {
// 负载均衡规则:优先选择同集群下,符合metadata的实例
// 如果没有,就选择所有集群下,符合metadata的实例
// 1. 查询所有实例 A
// 2. 筛选元数据匹配的实例 B
// 3. 筛选出同cluster下元数据匹配的实例 C
// 4. 如果C为空,就用B
// 5. 随机选择实例
try {
String clusterName = this.nacosDiscoveryProperties.getClusterName();
String targetVersion = this.nacosDiscoveryProperties.getMetadata().get("target-version");
DynamicServerListLoadBalancer loadBalancer = (DynamicServerListLoadBalancer) getLoadBalancer();
String name = loadBalancer.getName();
NamingService namingService = this.nacosDiscoveryProperties.namingServiceInstance();
// 所有实例
List<Instance> instances = namingService.selectInstances(name, true);
List<Instance> metadataMatchInstances = instances;
// 如果配置了版本映射,那么只调用元数据匹配的实例
if (StringUtils.isNotBlank(targetVersion)) {
metadataMatchInstances = instances.stream()
.filter(instance -> Objects.equals(targetVersion, instance.getMetadata().get("version")))
.collect(Collectors.toList());
if (CollectionUtils.isEmpty(metadataMatchInstances)) {
log.warn("未找到元数据匹配的目标实例!请检查配置。targetVersion = {}, instance = {}", targetVersion, instances);
return null;
}
}
List<Instance> clusterMetadataMatchInstances = metadataMatchInstances;
// 如果配置了集群名称,需筛选同集群下元数据匹配的实例
if (StringUtils.isNotBlank(clusterName)) {
clusterMetadataMatchInstances = metadataMatchInstances.stream()
.filter(instance -> Objects.equals(clusterName, instance.getClusterName()))
.collect(Collectors.toList());
if (CollectionUtils.isEmpty(clusterMetadataMatchInstances)) {
clusterMetadataMatchInstances = metadataMatchInstances;
log.warn("发生跨集群调用。clusterName = {}, targetVersion = {}, clusterMetadataMatchInstances = {}", clusterName, targetVersion, clusterMetadataMatchInstances);
}
}
Instance instance = ExtendBalancer.getHostByRandomWeight2(clusterMetadataMatchInstances);
return new NacosServer(instance);
} catch (Exception e) {
log.warn("发生异常", e);
return null;
}
}
@Override
public void initWithNiwsConfig(IClientConfig iClientConfig) {
}
}
public class ExtendBalancer extends Balancer {
/**
* 根据权重,随机选择实例
*
* @param instances 实例列表
* @return 选择的实例
*/
public static Instance getHostByRandomWeight2(List<Instance> instances) {
return getHostByRandomWeight(instances);
}
}
深入理解Nacos的Namespace
服务调用不能跨namespace
2.【Spring Cloud Alibaba】实现负载均衡-Ribbon的更多相关文章
- spring cloud 之 客户端负载均衡 Ribbon
一.负载均衡 负载均衡(Load Balance): 建立在现有网络结构之上,它提供了一种廉价有效透明的方法扩展网络设备和服务器的带宽.增加吞吐量.加强网络数据处理能力.提高网络的灵活性和可用性.其意 ...
- 三、Spring Cloud之软负载均衡 Ribbon
前言 上一节我们已经学习了Eureka 注册中心,其实我们也使用到了Ribbon ,只是当时我们没有细讲,所以我们现在一起来学习一下Ribbon. 什么是Ribbon 之前接触到的负载均衡都是硬负载均 ...
- SpringCloud学习笔记(8)----Spring Cloud Netflix之负载均衡-Ribbon的负载均衡的策略
一. 内置 负载均衡策略的介绍的 IRule的实现类 2. 通过代码实现负载均衡 在第六节Riddom的使用的工程中,随机策略配置类 package com.wangx.cloud.springclo ...
- SpringCloud学习笔记(7)----Spring Cloud Netflix之负载均衡-Ribbon的深入理解
1. 注解@LoadBalanced 作用:识别应用名称,并进行负载均衡. 2. 入口类:LoadBalancerAutoConfiguration 说明:类头上的注解可以知道Ribbon 实现的负载 ...
- SpringCloud学习笔记(6)----Spring Cloud Netflix之负载均衡-Ribbon的使用
1. 什么是负责均衡? 负载均衡,就是分发请求流量到不同的服务器. 负载均衡一般分为两种 1. 服务器端负载均衡(nginx) 2. 客户端负载均衡(Ribbon) 2. 服务提供者(spring-c ...
- 【Spring Cloud】客户端负载均衡组件——Ribbon(三)
一.负载均衡 负载均衡技术是提高系统可用性.缓解网络压力和处理能力扩容的重要手段之一. 负载均衡可以分为服务器负载均衡和客户端负载均衡,服务器负载均衡由服务器实现,客户端只需正常访问:客户端负载均衡技 ...
- API网关spring cloud gateway和负载均衡框架ribbon实战
通常我们如果有一个服务,会部署到多台服务器上,这些微服务如果都暴露给客户,是非常难以管理的,我们系统需要有一个唯一的出口,API网关是一个服务,是系统的唯一出口.API网关封装了系统内部的微服务,为客 ...
- Spring Cloud 2-Ribbon 客户端负载均衡(二)
Spring Cloud Eureka 1.Hello-Service服务端配置 pom.xml application.yml 启动两个service 2.Ribbon客户端配置 pom.xml ...
- Spring Cloud中的负载均衡策略
在上篇博客(Spring Cloud中负载均衡器概览)中,我们大致的了解了一下Spring Cloud中有哪些负载均衡器,但是对于负载均衡策略我们并没有去详细了解,我们只是知道在BaseLoadBal ...
- Spring Cloud之Zuul负载均衡
Zuul网关默认是实现负载均衡的,不需要任何配置.默认开启ribbon效果的 可以启启动两个服务端口,访问下.
随机推荐
- 深入理解协程(四):async/await异步爬虫实战
本文目录: 同步方式爬取博客标题 async/await异步爬取博客标题 本片为深入理解协程系列文章的补充. 你将会在从本文中了解到:async/await如何运用的实际的爬虫中. 案例 从CSDN上 ...
- scala 对一个数组分组操作
通常我们有一些需求,对一个数组两两进行翻转,通常就涉及到奇数偶数,否则就会出现数组index异常了,所以我们该怎么办呢? 虽然是一个入门级问题,但是我还是觉得这是一个很有意思的题目,因此写了一个对于通 ...
- 「2.0」一个人开发一个App,小程序从0到1,文件剖析
不知你是不是见到“文件剖析”这4个大字,才点进来看一看的?如果真是的话,那我可以坦诚.真心.负责任地告诉你:你上当了,你上了贼船啦,如果你现在想跳的话,还来得及,反正茫茫大海中,鲨鱼正缺搞程序的人.说 ...
- 美食家App开发日记1
前期一直在看第一行代码Android,这本书感觉讲基础讲得特别细致. 百看不如一试. 因为刚刚接触Android,没办法做到想写什么功能就直接一下写好,只能从最开始基础的控件使用开始练习. 所以一直在 ...
- 「 从0到1学习微服务SpringCloud 」08 构建消息驱动微服务的框架 Spring Cloud Stream
系列文章(更新ing): 「 从0到1学习微服务SpringCloud 」01 一起来学呀! 「 从0到1学习微服务SpringCloud 」02 Eureka服务注册与发现 「 从0到1学习微服务S ...
- 使用LD_PRELOAD注入程序
LD_PRELOAD是Linux系统的一个环境变量,它可以影响程序的运行时的链接(Runtime linker),它允许你定义在程序运行前优先加载的动态链接库.这个功能主要就是用来有选择性的载入不同动 ...
- Java的String类常用方法
一.构造函数 String(byte[ ] bytes):通过byte数组构造字符串对象. String(char[ ] value):通过char数组构造字符串对象. String(Sting or ...
- win10打开相机提示我们找不到你的相机
- springIOC源码接口分析(十一):ConfigurableApplicationContext
一 实现接口 关系图: ConfigurableApplicationContext接口实现了三个接口,ApplicationContext, Lifecycle, Closeable, Applic ...
- Jenkins | 搭建你第一个Jenkins应用
搭建你第一个Jenkins应用 1.准备工作 第一次使用 Jenkins,您需要: 机器要求: 256 MB 内存,建议大于 512 MB 10 GB 的硬盘空间(用于 Jenkins 和 Docke ...