spring cloud gateway 自定义负载均衡

2023-11-13


spring cloud gateway 自定义负载均衡

 

 

**************************

相关类及接口

 

LoadbalancerClientFilter:使用ribbon负载均衡,默认使用该类(已不推荐使用)

/** @deprecated */
@Deprecated
public class LoadBalancerClientFilter implements GlobalFilter, Ordered {
    public static final int LOAD_BALANCER_CLIENT_FILTER_ORDER = 10100;
    private static final Log log = LogFactory.getLog(LoadBalancerClientFilter.class);
    protected final LoadBalancerClient loadBalancer;
    private LoadBalancerProperties properties;

    public LoadBalancerClientFilter(LoadBalancerClient loadBalancer, LoadBalancerProperties properties) {
        this.loadBalancer = loadBalancer;
        this.properties = properties;
    }

    public int getOrder() {
        return 10100;
    }

    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        URI url = (URI)exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR);
        String schemePrefix = (String)exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_SCHEME_PREFIX_ATTR);
        if (url != null && ("lb".equals(url.getScheme()) || "lb".equals(schemePrefix))) {
            ServerWebExchangeUtils.addOriginalRequestUrl(exchange, url);
            if (log.isTraceEnabled()) {
                log.trace("LoadBalancerClientFilter url before: " + url);
            }

            ServiceInstance instance = this.choose(exchange);
            if (instance == null) {
                throw NotFoundException.create(this.properties.isUse404(), "Unable to find instance for " + url.getHost());
            } else {
                URI uri = exchange.getRequest().getURI();
                String overrideScheme = instance.isSecure() ? "https" : "http";
                if (schemePrefix != null) {
                    overrideScheme = url.getScheme();
                }

                URI requestUrl = this.loadBalancer.reconstructURI(new DelegatingServiceInstance(instance, overrideScheme), uri);
                if (log.isTraceEnabled()) {
                    log.trace("LoadBalancerClientFilter url chosen: " + requestUrl);
                }

                exchange.getAttributes().put(ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR, requestUrl);
                return chain.filter(exchange);
            }
        } else {
            return chain.filter(exchange);
        }
    }

    protected ServiceInstance choose(ServerWebExchange exchange) {
        return this.loadBalancer.choose(((URI)exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR)).getHost());
    }
}

说明:默认使用该类,可通过下述方法使用ReactiveLoadbalancerClientFilter

​"You already have RibbonLoadBalancerClient on your classpath. It will be used by default. 
As Spring Cloud Ribbon is in maintenance mode. We recommend switching to " + BlockingLoadBalancerClient.class.getSimpleName() + " instead. 
In order to use it, set the value of `spring.cloud.loadbalancer.ribbon.enabled` to `false` 
or remove spring-cloud-starter-netflix-ribbon from your project."

 

 

ReactiveLoadBalancerClientFilter:负载均衡拦截器

public class ReactiveLoadBalancerClientFilter implements GlobalFilter, Ordered {
    private static final Log log = LogFactory.getLog(ReactiveLoadBalancerClientFilter.class);
    private static final int LOAD_BALANCER_CLIENT_FILTER_ORDER = 10150;
    private final LoadBalancerClientFactory clientFactory;
    private LoadBalancerProperties properties;

    public ReactiveLoadBalancerClientFilter(LoadBalancerClientFactory clientFactory, LoadBalancerProperties properties) {
        this.clientFactory = clientFactory;
        this.properties = properties;
    }

    public int getOrder() {
        return 10150;
    }

    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        URI url = (URI)exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR);
        String schemePrefix = (String)exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_SCHEME_PREFIX_ATTR);
        if (url != null && ("lb".equals(url.getScheme()) || "lb".equals(schemePrefix))) {
                            //url不为null且协议为lb,或者url以lb开头

            ServerWebExchangeUtils.addOriginalRequestUrl(exchange, url);
            if (log.isTraceEnabled()) {
                log.trace(ReactiveLoadBalancerClientFilter.class.getSimpleName() + " url before: " + url);
            }

            return this.choose(exchange).doOnNext((response) -> {
                            //获取ServiceInstance实例,进行一些处理

                if (!response.hasServer()) {
                            //如果没有serviceInstance,直接抛出异常

                    throw NotFoundException.create(this.properties.isUse404(), "Unable to find instance for " + url.getHost());
                } else {    //如果有serviceInstance,进行相关处理
                    URI uri = exchange.getRequest().getURI();
                    String overrideScheme = null;
                    if (schemePrefix != null) {
                        overrideScheme = url.getScheme();
                    }

                    DelegatingServiceInstance serviceInstance = new DelegatingServiceInstance((ServiceInstance)response.getServer(), overrideScheme);
                    URI requestUrl = LoadBalancerUriTools.reconstructURI(serviceInstance, uri);
                    if (log.isTraceEnabled()) {
                        log.trace("LoadBalancerClientFilter url chosen: " + requestUrl);
                    }

                    exchange.getAttributes().put(ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR, requestUrl);
                }
            }).then(chain.filter(exchange));
        } else {
            return chain.filter(exchange); //如果获取不到serviceInstance,直接进行后续过滤
        }
    }

    private Mono<Response<ServiceInstance>> choose(ServerWebExchange exchange) {
        URI uri = (URI)exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR);
        ReactorLoadBalancer<ServiceInstance> loadBalancer = (ReactorLoadBalancer)this.clientFactory.getInstance(uri.getHost(), ReactorLoadBalancer.class, new Class[]{ServiceInstance.class});
        if (loadBalancer == null) {
            throw new NotFoundException("No loadbalancer available for " + uri.getHost());
        } else {
            return loadBalancer.choose(this.createRequest());
        }
    }//选择服务实例

    private Request createRequest() {
        return ReactiveLoadBalancer.REQUEST;
    }
}

 

ReactorLoadBalancer:负载均衡接口

public interface ReactorLoadBalancer<T> extends ReactiveLoadBalancer<T> {
    Mono<Response<T>> choose(Request request);

    default Mono<Response<T>> choose() {
        return this.choose(REQUEST);
    }
}

***********************

public interface ReactorServiceInstanceLoadBalancer extends ReactorLoadBalancer<ServiceInstance> {
}

 

RoundRobinLoadbalancer:负载均衡使用轮询

public class RoundRobinLoadBalancer implements ReactorServiceInstanceLoadBalancer {
    private static final Log log = LogFactory.getLog(RoundRobinLoadBalancer.class);
    private final AtomicInteger position;

    private ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider;
    private final String serviceId;

************
构造方法

    public RoundRobinLoadBalancer(ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider, String serviceId) {
    public RoundRobinLoadBalancer(ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider, String serviceId, int seedPosition) {

************
普通方法

    public Mono<Response<ServiceInstance>> choose(Request request) {
        if (this.serviceInstanceListSupplierProvider != null) {
            ServiceInstanceListSupplier supplier = (ServiceInstanceListSupplier)this.serviceInstanceListSupplierProvider.getIfAvailable(NoopServiceInstanceListSupplier::new);
            return ((Flux)supplier.get()).next().map(this::getInstanceResponse);
        } else {
            ServiceInstanceSupplier supplier = (ServiceInstanceSupplier)this.serviceInstanceSupplier.getIfAvailable(NoopServiceInstanceSupplier::new);
            return ((Flux)supplier.get()).collectList().map(this::getInstanceResponse);
        }
    }

    private Response<ServiceInstance> getInstanceResponse(List<ServiceInstance> instances) {
        if (instances.isEmpty()) {
            log.warn("No servers available for service: " + this.serviceId);
            return new EmptyResponse();
        } else {
            int pos = Math.abs(this.position.incrementAndGet());
            ServiceInstance instance = (ServiceInstance)instances.get(pos % instances.size());
            return new DefaultResponse(instance);
        }
    }//使用轮询获取实例
}

 

 

**************************

示例:参数id为偶数时,输出hello new version

 

********************

网关

 

配置文件

spring:
  application:
    name: hello-gateway
  cloud:
    consul:
      host: 172.18.0.20
      port: 8500
    loadbalancer:
      ribbon:
        enabled: false
    gateway:
      routes:
        - id: myRoute
          uri: lb://hello-service
          predicates:
            - Path=/hello

 

自定义过滤器

@Component
public class CustomLoadBalancerClientFilter implements GlobalFilter, Ordered {
    private static final Log log = LogFactory.getLog(org.springframework.cloud.gateway.filter.ReactiveLoadBalancerClientFilter.class);

    @Resource
    private final LoadBalancerClientFactory clientFactory;

    @Resource
    private LoadBalancerProperties properties;

    public CustomLoadBalancerClientFilter(LoadBalancerClientFactory clientFactory, LoadBalancerProperties properties) {
        this.clientFactory = clientFactory;
        this.properties = properties;
    }

    public int getOrder() {
        return 10149;
    }

    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        URI url = exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR);
        String schemePrefix = exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_SCHEME_PREFIX_ATTR);
        if (url != null && ("lb".equals(url.getScheme()) || "lb".equals(schemePrefix))) {
            ServerWebExchangeUtils.addOriginalRequestUrl(exchange, url);
            if (log.isTraceEnabled()) {
                log.trace(ReactiveLoadBalancerClientFilter.class.getSimpleName() + " url before: " + url);
            }

            return this.choose(exchange).doOnNext((response) -> {
                if (!response.hasServer()) {
                    throw NotFoundException.create(this.properties.isUse404(), "Unable to find instance for " + url.getHost());
                } else {
                    URI uri = exchange.getRequest().getURI();
                    String overrideScheme = null;
                    if (schemePrefix != null) {
                        overrideScheme = url.getScheme();
                    }

                    int id=Integer.parseInt(Objects.requireNonNull(exchange.getRequest().getQueryParams().getFirst("id")));
                    if (id%2==0){
                        while (!"new".equals(response.getServer().getMetadata().get("version"))){
                            try {
                                response=this.choose(exchange).toFuture().get();
                            }catch (Exception e){
                                System.out.println(e.getMessage());
                            }
                        }
                    }

                    DelegatingServiceInstance serviceInstance = new DelegatingServiceInstance(response.getServer(), overrideScheme);

                    System.out.println(exchange.getRequest().getQueryParams().getFirst("id")+"对应server的version为:"+serviceInstance.getMetadata().get("version"));
                    URI requestUrl = LoadBalancerUriTools.reconstructURI(serviceInstance, uri);
                    if (log.isTraceEnabled()) {
                        log.trace("LoadBalancerClientFilter url chosen: " + requestUrl);
                    }

                    exchange.getAttributes().put(ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR, requestUrl);
                }
            }).then(chain.filter(exchange));
        } else {
            return chain.filter(exchange);
        }
    }

    private Mono<Response<ServiceInstance>> choose(ServerWebExchange exchange) {
        URI uri = exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR);
        assert uri != null;
        ReactorLoadBalancer<ServiceInstance> loadBalancer = this.clientFactory.getInstance(uri.getHost(), ReactorLoadBalancer.class, new Class[]{ServiceInstance.class});
        if (loadBalancer == null) {
            throw new NotFoundException("No loadbalancer available for " + uri.getHost());
        } else {
            return loadBalancer.choose(this.createRequest());
        }
    }

    private Request createRequest() {
        return ReactiveLoadBalancer.REQUEST;
    }
}

 

 

********************

同名应用hello-service1

 

配置文件

spring:
  application:
    name: hello-service
  cloud:
    consul:
      host: 172.18.0.20
      port: 8500
      discovery:
        instance-id: ${spring.application.name}-${random.int}
        tags: version=old

 

controller 层

@RestController
public class HelloController {

    @RequestMapping("/hello")
    public String hello(){
        return "hello old version";
    }
}

 

********************

同名应用hello-service2

 

配置文件

spring:
  application:
    name: hello-service
  cloud:
    consul:
      host: 172.18.0.20
      port: 8500
      discovery:
        instance-id: ${spring.application.name}-${random.int}
        tags: version=new

 

controller 层

@RestController
public class HelloController {

    @RequestMapping("/hello")
    public String hello(){
        return "hello new version";
    }
}

 

 

**************************

测试输出

 

consul注册的应用

        

 

参数测试

       

当id为偶数时,输出为hello new version

 

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

spring cloud gateway 自定义负载均衡 的相关文章

  • 分布式日志系统的设计和实践

    什么是日志 日志是一种按照时间顺序存储记录的数据 它记录了什么时间发生了什么事情 提供精确的系统记录 根据日志信息可以定位到错误详情和根源 按照APM概念的定义 日志的特点是描述一些离散的 不连续的 事件 日志是按照错误级别分级的 常见的错
  • matlab 逆否,逆否命题与反证法

    在原命题 逆命题 否命题与逆否命题中 原命题与逆否命题等价 同真同假 所以证明一个命题成立可以去证明它的逆否命题成立 即先否定结论 在这个否定的结论下 去推出原来的条件的否定成立 例题一 1 判断命题 如果 x y neq 3 那么 x n
  • Python使用xlwt和xlrd读写excel文件

    Python使用xlwt和xlrd读写excel文件 xlwt和xlrd是两个相互配套的模块 在Python中 用于将数据写入Excel文件和读取Excel文件的数据 从字面即可看出xlwt是对xls格式的文件进行write xlrd是对x
  • nvidia-docker踩坑记录

    docker nvidia docker配置镜像创建容器 众所周知 想要在容器中使用nvidia的显卡 需要使用nvidia docker命令创建容器 环境说明 服务器端为Ubuntu18 04离线 nvidia smi正常使用 CUDA版
  • APIPOST入门+认识接口(前后端分离)

    APIPOST入门 认识接口 前后端分离 文章目录 APIPOST入门 认识接口 前后端分离 啥是 API 接口 笑话小案例 编写mock数据 如何解决跨域问题 后续要解决的 实战二维码 驾照题库实战项目 自己写一个接口 2 post和ge
  • 6:sort_values,loc,corr数据筛选,绘图

    一 使用sort values 对某一列 进行从小到大或者从大到小的排序 1 对一列进行操作 import pandas as pd df pd read excel r C Users 73575 Desktop 北京新发地菜价 xlsx
  • 整型的提升和截断详解(看完包会)

    所有常量值 在没有后缀得情况下 默认是4个字节 int型 将一个int型值赋给char型变量时 会发生整形截断 按存储顺序截断 先到先截 一个char截断一个字节即8个bit位 将char类型值按有常量值 在没有后缀得情况下 默认是4个字节
  • linux常用库 对应函数

    1 include
  • Vue在线引入地址

    Vue在线引入地址 vue2 vue3 CodePan在线运行ElementUI时添加的JS及CSS引用地址 Vue https cdn jsdelivr net npm vue 2 dist vue
  • 【Flink系列1】flink与spark的区别

    Flink简介 spark基本架构 flink基本架构 Spark提出的最主要抽象概念是弹性分布式数据集 RDD flink支持增量迭代计算 基于流执行引擎 Flink提供了诸多更高抽象层的API以方便用户编写分布式任务 1 DataSet
  • RabbitMQ镜像集群搭建

    RabbitMQ镜像集群搭建 消息队列 在消息的传输过程中保存消息的容器 MQ角色 Broker 即消息队列服务器实体 Exchange 消息交换机 它指定消息按什么规则 路由到哪个队列 Queue 消息队列载体 每个消息都会被投入到一个或
  • 基于SpringBoot并整合MyBatis和Thymeleaf模板引擎开发的图书管理系统

    先展示下前端页面 登录页面 用户注册页面 一 管理员相关页面以及功能 管理员主页信息以及左侧导航栏 页头可查看当前管理员的信息
  • Unity Application.LoadLevel() 已过时

    解决办法 使用EditorSceneManager方法 https blog csdn net shenqiankk article details 100137502
  • 大数据技术——Scala语言基础

    Scala基础知识 控制结构 if条件表达式 有一点与Java不同的是 Scala中的if表达式的值可以赋值给变量 while循环 for循环 基本语法 其中 变量 lt 表达式 被称为 生成器 generator 守卫 guard 的表达
  • finereport连接oracle_FINEREPORT连接远程ORACLE数据库

    有如下错误提示 SEVERE CannotcreatePoolableConnectionFactory Listenerrefusedtheconnectionwiththefollowingerror ORA 12505 TNS lis
  • python小技巧大应用--基础实用漂亮界面(无边框,圆角,可拖拽)

    这回要实现一个漂亮的基础界面 要具有如下特色 无边框 圆角 漂亮的背景 可拖拽移动 具有最小化 关闭按钮 界面与代码分离 支持qss 先展示一下最后的效果 那就开始工作吧 1 通过Qt Designer实现界面设计 将设计好的界面保存为di
  • 【数据结构】设计循环队列详解

    我的个人主页 我们登上并非我们所选择的舞台 演出并非我们所选择的剧本 Enchiridion 设计循环队列 前言 1 什么是循环队列 2 循环队列的设计 2 1 MyCircularQueue k 实现 2 2 isEmpty 和 isFu
  • usb 命名乱的一批,怎么破

    USB 的命名真是乱的一批 命名里 一股浓浓的 印度风扑面而来 我想给 iso 文件加个驱动直接跪了 被绕进去了 幸运的是速度没乱 以下用速度整理该文档 USB2 0 时代 12 mbps usb1 0 480 mbps usb2 0 US

随机推荐

  • 什么是Restful?

    REST 简介 REST 是英文 Representational State Transfer 的缩写 有中文翻译为 具象状态传输 REST 这个术语是由 Roy Fielding 在他的博士论文 Architectural Styles
  • 大数据课程最后任务-hive处理数据

    好的这是第五次也就是不加额外挑战任务的最后任务 基本过程来自于厦门大学的hive教程 主要是hive处理20w的数据 两部分 一部分是安装 来自http dblab xmu edu cn blog 959 一步分是运行http dblab
  • Yii Framework 开发教程(34) Zii组件-AutoComplete示例

    CJuiAutoComplete 在用户输入时可以根据用户输入的前几个字符自动提示用户可以输入的文字 它封装了 JUI autocomplete插件 基本用法如下 php view plain copy print
  • vue3优雅实现移动端登录注册模块

    前言 近期开发的移动端项目直接上了vue3 新特性composition api确实带来了全新的开发体验 开发者在使用这些特性时可以将高耦合的状态和方法放在一起统一管理 并能视具体情况将高度复用的逻辑代码单独封装起来 这对提升整体代码架构的
  • VUE element-ui 之table表格表头插入输入框

    很简单
  • 手把手教你安装RabbitMQ(基于CentOS7系统)

    RabbitMQ简介及安装 什么是RabbitMQ RabbitMQ的特点 安装 安装Erlang 配置Erlang环境变量 验证环境 安装RabbitMQ 启动RabbitMQ 添加用户 访问 什么是RabbitMQ RabbitMQ是一
  • 财富自由?五年后为什么他月入十万,而我月入六千

    最近无论是在社群里还是 各种付费平台上 都能看到闪闪发光的一个词 财富自由 我好奇地去搜索了一下百度百科 财富自由是指 你无需为生活开销而努力 为钱工作的状态 简单的说 你的资产产生的被动收入 至少等于或超过你的日常开支 这是我们大多数人最
  • int、float和double的字节及位码

    int类型 4字节32位 第一位 符号位 2 9位 阶位 指数位 10 32位 普通数值位 0 00000000 00000000000000000000001 flaot类型 4字节32位 第一位 符号位 2 9位 阶位 指数位 10 3
  • 神经网络优化(二) - 激活函数和损失函数

    1 神经网络中的激活函数activation function 1 1 引入激活函数概念 神经网络的基本构成单元是神经元 在搭建神经网络一文中使用的神经元模型为 这个神经元模型是较为简化的基本神经元模型 还有一种理论模型包含有激活函数和偏置
  • live555学习之二RTSP协议说明

    RTSP协议 是一种基于C S架构的并用于双方通信约定的流媒体协议 全称实时流协议 Real Time Streaming Protocol 集成了网络实时控制 数据传输接收功能 客户端遵循协议发送指令控制多媒体的资源的功能如播放 暂停 停
  • row format delimited fields terminated by ','

    row format delimited fields terminated by 以 结尾的行格式分隔字段
  • base64图片编码大小与原图文件大小之间的联系

    base64图片编码大小与原图文件大小之间的联系 有时候我们需要把canvas画布的图画转换成图片输出页面 而用canvas生成的图片就是base64编码的 它是由数字 字母等一大串的字符组成的 但是我们需要获取它的文件流大小该怎么办呢 B
  • 题解-equation 8*x^4 + 7*x^3 + 2*x^2 + 3*x + 6 == Y;

    Problem Description Now given the equation 8 x 4 7 x 3 2 x 2 3 x 6 Y can you find its solution between 0 and 100 br Now
  • Docker 容器安全风险和防御综述

    摘要 Docker是目前最具代表性的容器平台之一 它的安全问题引起了产业界和学术界的广泛关注 首先 对Docker架构以及基本安全特性进行介绍 分析了Docker面临的安全威胁 其次 对Docker增强 安全检测 瘦身等方面的安全技术进行了
  • JSONArray操作汇总,排序,筛选,分组

    JSONArray操作汇总 一 排序 1 根据集合对象中某一对象属性进行排序 返回新的集合 2 List进行排序 返回新的List 注意 并没有改变原始list的顺序 二 筛选 1 获取集合对象中某一属性值 2 获取集合对象中某一属性值并去
  • JavaWeb基础7——会话技术Cookie&Session

    导航 黑马Java笔记 踩坑汇总 JavaSE JavaWeb SSM SpringBoot 瑞吉外卖 SpringCloud SpringCloudAlibaba 黑马旅游 谷粒商城 目录 一 会话技术 1 1 会话和跟踪技术介绍 1 2
  • 【华为OD机试 2023】 查找单入口空闲区域(C++ Java JavaScript Python)

    华为od机试题库 华为OD机试2022 2023 C Java JS Py https blog csdn net banxia frontend category 12225173 html 华为OD机试2023最新题库 更新中 C Ja
  • npm安装依赖至指定版本的方法

    简介 本文介绍npm安装依赖至指定版本的方法 依赖的版本可以在淘宝镜像或官方查询到 三种方法 方法一 先在package json里修改好指定版本号 然后输入 npm update webpack 方法二 npm update webpac
  • 【从推理出发】

    赌上爷爷之名 2021年暑假 和现在一样 也是很佛 不想好好学习的时间 8月的天气太过炎热 有时却又暴雨倾盆 很不讨喜 只得在家闲着看电视 动漫打发时间 按照以前的习惯 一般是悠闲地躺在沙发上吹着空调 看着长达900多集的柯南 然后在剧情中
  • spring cloud gateway 自定义负载均衡

    spring cloud gateway 自定义负载均衡 相关类及接口 LoadbalancerClientFilter 使用ribbon负载均衡 默认使用该类 已不推荐使用 deprecated Deprecated public cla