负载均衡的两种方式

如何实现负载均衡

目前已经实现让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的更多相关文章

  1. spring cloud 之 客户端负载均衡 Ribbon

    一.负载均衡 负载均衡(Load Balance): 建立在现有网络结构之上,它提供了一种廉价有效透明的方法扩展网络设备和服务器的带宽.增加吞吐量.加强网络数据处理能力.提高网络的灵活性和可用性.其意 ...

  2. 三、Spring Cloud之软负载均衡 Ribbon

    前言 上一节我们已经学习了Eureka 注册中心,其实我们也使用到了Ribbon ,只是当时我们没有细讲,所以我们现在一起来学习一下Ribbon. 什么是Ribbon 之前接触到的负载均衡都是硬负载均 ...

  3. SpringCloud学习笔记(8)----Spring Cloud Netflix之负载均衡-Ribbon的负载均衡的策略

    一. 内置 负载均衡策略的介绍的 IRule的实现类 2. 通过代码实现负载均衡 在第六节Riddom的使用的工程中,随机策略配置类 package com.wangx.cloud.springclo ...

  4. SpringCloud学习笔记(7)----Spring Cloud Netflix之负载均衡-Ribbon的深入理解

    1. 注解@LoadBalanced 作用:识别应用名称,并进行负载均衡. 2. 入口类:LoadBalancerAutoConfiguration 说明:类头上的注解可以知道Ribbon 实现的负载 ...

  5. SpringCloud学习笔记(6)----Spring Cloud Netflix之负载均衡-Ribbon的使用

    1. 什么是负责均衡? 负载均衡,就是分发请求流量到不同的服务器. 负载均衡一般分为两种 1. 服务器端负载均衡(nginx) 2. 客户端负载均衡(Ribbon) 2. 服务提供者(spring-c ...

  6. 【Spring Cloud】客户端负载均衡组件——Ribbon(三)

    一.负载均衡 负载均衡技术是提高系统可用性.缓解网络压力和处理能力扩容的重要手段之一. 负载均衡可以分为服务器负载均衡和客户端负载均衡,服务器负载均衡由服务器实现,客户端只需正常访问:客户端负载均衡技 ...

  7. API网关spring cloud gateway和负载均衡框架ribbon实战

    通常我们如果有一个服务,会部署到多台服务器上,这些微服务如果都暴露给客户,是非常难以管理的,我们系统需要有一个唯一的出口,API网关是一个服务,是系统的唯一出口.API网关封装了系统内部的微服务,为客 ...

  8. Spring Cloud 2-Ribbon 客户端负载均衡(二)

    Spring Cloud Eureka  1.Hello-Service服务端配置 pom.xml application.yml 启动两个service 2.Ribbon客户端配置 pom.xml ...

  9. Spring Cloud中的负载均衡策略

    在上篇博客(Spring Cloud中负载均衡器概览)中,我们大致的了解了一下Spring Cloud中有哪些负载均衡器,但是对于负载均衡策略我们并没有去详细了解,我们只是知道在BaseLoadBal ...

  10. Spring Cloud之Zuul负载均衡

    Zuul网关默认是实现负载均衡的,不需要任何配置.默认开启ribbon效果的 可以启启动两个服务端口,访问下.

随机推荐

  1. java中关键字volatile的作用

    用在多线程,同步变量. 线程为了提高效率,将某成员变量(如A)拷贝了一份(如B),线程中对A的访问其实访问的是B.只在某些动作时才进行A和B的同步.因此存在A和B不一致的情况.volatile就是用来 ...

  2. js的原型模式

    以下内容来自<JavaScript高级程序设计>第三版 我们创建的每个函数都有一个prototype(原型)属性,这个属性是一个指针,指向一个对象,而这个对象的用途是包含可以由特定类型的所 ...

  3. python基础语法(1)

    一.基本概念 1. python中数有四种类型:整数.长整数.浮点数和复数. 整数, 如 1 长整数 是比较大的整数 浮点数 如 1.23.3E-2 复数 如 1 + 2j. 1.1 + 2.2j 2 ...

  4. Swift学习--常量.变量.数据类型的使用(一)

    一.Swift中的常量和变量 /* Swift 中定义常量和变量用let/var let 代表定义一个常量 var 代表定义一个变量 Swift 中代表定义常量和变量不需要写数据类型,编译器辉根据我们 ...

  5. DB2数据类型

    DB2数据库的内置数据类型主要分成数值型(numeric).字符串型(character string).图形字符串(graphic string).二进制字符串型(binary string)或日期 ...

  6. 求N个元素的子集合个数

    详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt406 一个集合有n个元素,请问怎么算出来它的子集(包括空集和本身)是 2的n ...

  7. [UWP]如何使用Fluent Design System (上)

    1. 前言 微软在Build 2017中公布了新的设计语言Fluent Design System(以下简称FDS),不过官网只是堆砌了各种华丽的词语以及一堆动画.至于在UWP中要做成怎么样,怎么做, ...

  8. codeforces285B

    Find Marble CodeForces - 285B Petya and Vasya are playing a game. Petya's got n non-transparent glas ...

  9. 以添加评论组件为例看angular2请求数据的处理

    在NiceFish项目中,数据请求处理并没有用Promise的那一套方法,用的是Observable(观察者模式),我将其理解成生产者和消费者模式 如下简单例子:出自(https://segmentf ...

  10. android studio友盟分享demo运行报错Gradle&#39;s dependency cache may be corrupt解决方法

    gradle-wrapper.properties里修改了gradle的版本,与之前没有报错的项目gradle版本一致.