负载均衡的两种方式

如何实现负载均衡

目前已经实现让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. vue 项目路由跳转后显示不同的title

    1.在router/index.js的每个路由中配置title 2.在项目中运行命令 npm install vue-wechat-title --save 安装插件(在 package.json文件 ...

  2. 19南京网络赛A 扫描线

    题目链接:https://nanti.jisuanke.com/t/41298 扫描线的简单题,题目难在找宫殿的价值(°ー°"),比赛时将近100多行代码找价值,纯模拟,看到题解哭了. 存下 ...

  3. window10配置python虚拟环境的路径

    当我们搭建python+django项目的时候,需要配置虚拟环境,从而使项目与项目之间的包相互隔离,互不影响. 1.配置虚拟环境前,首先需要安装两个包 pip install virtualenvwr ...

  4. Java架构师线上问题排查,这些命令程序员一定用得到!

    Java架构师线上问题排查,这些命令程序员一定用得到! 线上问题排查,以下场景,你遇到过吗? 一.了解机器连接数情况 问题:1.2.3.4的sshd的监听端口是22,如何统计1.2.3.4的sshd服 ...

  5. 夜晚 暴力 十点钟 jQuery 的 extend 实现 原理

    jQuery 的 extend 是怎么实现的 一看代码 喉咙 就不爽 这是 jQuery JavaScript Library v1.6 一看代码 多的 屁股疼 , 排名 前三 的 文章 可以去参考下 ...

  6. T117897 七步洗手法 / PJT1(洛谷)

    题目:现在有n个人需要依次使用1个洗手池洗手,进行一步洗手需要1单位时间.他们每个人至少会进行一步洗手,但是却不一定进行了完整的七部洗手. 现在你知道了他们总共的洗手时间为t,请你推测他们有多少人进行 ...

  7. 使用Python写的WingPro7 Pyside2 和 PyQt5插件

    pyside2的 import wingapi import subprocess pyside2_uic = "pyside2-uic" pyside2_qrc = " ...

  8. PPT制作简易套路指南

    最近正在重做公众号相关的一些设计以及排版,想到年前部门里的UI设计大神做了一个关于"PPT设计指南"的分享,正好可以拿来实践一把. 一直以来,PPT.Word.Excel都是办公人 ...

  9. java内存模型梳理

    java内存模型 内存模型和内存结构区别 它们是两个概念. 内存模型是和jvm多线程相关的. 内存结构是指的jvm内存结构. 内存模型的作用 内存模型简称JMM JMM是决定一个线程对共享变量的写入时 ...

  10. linux--->配置lamp环境(centos7 最小版)

    这篇博客写的很全,按照顺序敲代码即可 参考:https://www.cnblogs.com/me80/p/7218883.html