当前位置: 首页 > news >正文

自定义loadbalance实现feignclient的自定义路由

自定义loadbalance实现feignclient的自定义路由

项目背景

服务A有多个同事同时开发,每个同事都在dev或者test环境发布自己的代码,注册到注册中心有好几个(本文nacos为例),这时候调用feign可能会导致请求到不同分支的服务上面,会出现一些问题,本文重点在于解决该问题

实操

解决方案

/*** @author authorZhao* @since 2023-08-03*/
@EnableConfigurationProperties(LoadBalancerProperties.class)
public class LoadBalanceConfig{@Bean@ConditionalOnMissingBeanpublic ReactorLoadBalancer<ServiceInstance> reactorServiceInstanceLoadBalancer(Environment environment,LoadBalancerClientFactory loadBalancerClientFactory) {String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);return new MyRoundRobinLoadBalancer(loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class), name);}
}
//@Configuration(proxyBeanMethods = false)
//@LoadBalancerClients(defaultConfiguration = LoadBalanceConfig.class) 全局配置
//@LoadBalancerClient(value = "user-center-service",configuration = LoadBalanceConfig.class) //单个配置
public class LoadBalance {}
/*** A Round-Robin-based implementation of {@link ReactorServiceInstanceLoadBalancer}.** @author Spencer Gibb* @author Olga Maciaszek-Sharma* @author Zhuozhi JI*/
public class MyRoundRobinLoadBalancer implements ReactorServiceInstanceLoadBalancer {private static final Log log = LogFactory.getLog(CubeRoundRobinLoadBalancer.class);final AtomicInteger position;final String serviceId;ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider;/*** @param serviceInstanceListSupplierProvider a provider of* {@link ServiceInstanceListSupplier} that will be used to get available instances* @param serviceId id of the service for which to choose an instance*/public CubeRoundRobinLoadBalancer(ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider,String serviceId) {this(serviceInstanceListSupplierProvider, serviceId, new Random().nextInt(1000));}/*** @param serviceInstanceListSupplierProvider a provider of* {@link ServiceInstanceListSupplier} that will be used to get available instances* @param serviceId id of the service for which to choose an instance* @param seedPosition Round Robin element position marker*/public CubeRoundRobinLoadBalancer(ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider,String serviceId, int seedPosition) {this.serviceId = serviceId;this.serviceInstanceListSupplierProvider = serviceInstanceListSupplierProvider;this.position = new AtomicInteger(seedPosition);}@SuppressWarnings("rawtypes")@Override// see original// https://github.com/Netflix/ocelli/blob/master/ocelli-core/// src/main/java/netflix/ocelli/loadbalancer/RoundRobinLoadBalancer.javapublic Mono<Response<ServiceInstance>> choose(Request request) {ServiceInstanceListSupplier supplier = serviceInstanceListSupplierProvider.getIfAvailable(NoopServiceInstanceListSupplier::new);return supplier.get(request).next().map(serviceInstances -> processInstanceResponse(supplier, serviceInstances));}private Response<ServiceInstance> processInstanceResponse(ServiceInstanceListSupplier supplier,List<ServiceInstance> serviceInstances) {Response<ServiceInstance> serviceInstanceResponse = getInstanceResponse(serviceInstances);if (supplier instanceof SelectedInstanceCallback && serviceInstanceResponse.hasServer()) {((SelectedInstanceCallback) supplier).selectedServiceInstance(serviceInstanceResponse.getServer());}return serviceInstanceResponse;}private Response<ServiceInstance> getInstanceResponse(List<ServiceInstance> instances) {for (ServiceInstance instance : instances) {if(instance instanceof NacosServiceInstance nacosServiceInstance){//项目注册的时候在配置一个元数据,后面可以根据当前上下文拿到当前tag,进行匹配,默认使用base分支String s = instance.getMetadata().get("feature-tag");if("base".equals(s)){return new DefaultResponse(nacosServiceInstance);}}}if (instances.isEmpty()) {if (log.isWarnEnabled()) {log.warn("No servers available for service: " + serviceId);}return new EmptyResponse();}// Ignore the sign bit, this allows pos to loop sequentially from 0 to// Integer.MAX_VALUEint pos = this.position.incrementAndGet() & Integer.MAX_VALUE;ServiceInstance instance = instances.get(pos % instances.size());return new DefaultResponse(instance);}}

loadbalance执行过程

调用流程

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Lf3NGlrZ-1692865252643)(img/image-20230824160138272.png)]

feign.SynchronousMethodHandler#executeAndDecode
->feign.Client#execute
->FeignBlockingLoadBalancerClient#execute
public Response execute(Request request, Request.Options options) throws IOException {final URI originalUri = URI.create(request.url());String serviceId = originalUri.getHost();Assert.state(serviceId != null, "Request URI does not contain a valid hostname: " + originalUri);String hint = getHint(serviceId);DefaultRequest<RequestDataContext> lbRequest = new DefaultRequest<>(new RequestDataContext(buildRequestData(request), hint));Set<LoadBalancerLifecycle> supportedLifecycleProcessors = LoadBalancerLifecycleValidator.getSupportedLifecycleProcessors(//loadBalancerClientFactory是NamedContextFactory的子类 容器map,刷新user-center-service子容器loadBalancerClientFactory.getInstances(serviceId, LoadBalancerLifecycle.class),RequestDataContext.class, ResponseData.class, ServiceInstance.class);supportedLifecycleProcessors.forEach(lifecycle -> lifecycle.onStart(lbRequest));//根据serviceId拿到ReactiveLoadBalancer,执行choose方法,然后到了我们的方法ServiceInstance instance = loadBalancerClient.choose(serviceId, lbRequest);org.springframework.cloud.client.loadbalancer.Response<ServiceInstance> lbResponse = new DefaultResponse(instance);if (instance == null) {String message = "Load balancer does not contain an instance for the service " + serviceId;if (LOG.isWarnEnabled()) {LOG.warn(message);}supportedLifecycleProcessors.forEach(lifecycle -> lifecycle.onComplete(new CompletionContext<ResponseData, ServiceInstance, RequestDataContext>(CompletionContext.Status.DISCARD, lbRequest, lbResponse)));return Response.builder().request(request).status(HttpStatus.SERVICE_UNAVAILABLE.value()).body(message, StandardCharsets.UTF_8).build();}String reconstructedUrl = loadBalancerClient.reconstructURI(instance, originalUri).toString();Request newRequest = buildRequest(request, reconstructedUrl);LoadBalancerProperties loadBalancerProperties = loadBalancerClientFactory.getProperties(serviceId);return executeWithLoadBalancerLifecycleProcessing(delegate, options, newRequest, lbRequest, lbResponse,supportedLifecycleProcessors, loadBalancerProperties.isUseRawStatusCodeInResponseData());}

在这里插入图片描述

后面MyRoundRobinLoadBalancer其实是抄袭RoundRobinLoadBalancer的实现,默认就是轮训

本文为原创,转载请申明

相关文章:

自定义loadbalance实现feignclient的自定义路由

自定义loadbalance实现feignclient的自定义路由 项目背景 服务A有多个同事同时开发&#xff0c;每个同事都在dev或者test环境发布自己的代码&#xff0c;注册到注册中心有好几个(本文nacos为例)&#xff0c;这时候调用feign可能会导致请求到不同分支的服务上面&#xff0c;会…...

论文笔记:从不平衡数据流中学习的综述: 分类、挑战、实证研究和可重复的实验框架

0 摘要 论文&#xff1a;A survey on learning from imbalanced data streams: taxonomy, challenges, empirical study, and reproducible experimental framework 发表&#xff1a;2023年发表在Machine Learning上。 源代码&#xff1a;https://github.com/canoalberto/imba…...

C#设计模式六大原则之--迪米特法则

设计模式六大原则是单一职责原则、里氏替换原则、依赖倒置原则、接口隔离原则、迪米特法则、开闭原则。它们不是要我们刻板的遵守&#xff0c;而是根据实际需要灵活运用。只要对它们的遵守程度在一个合理的范围内&#xff0c;努为做到一个良好的设计。本文主要介绍一下.NET(C#)…...

一次js请求一般情况下有哪些地方会有缓存处理?

目录 1、DNS缓存 2、CDN缓存 3、浏览器缓存 4、服务器缓存 1、DNS缓存 DNS缓存指DNS返回了正确的IP之后&#xff0c;系统就会将这个结果临时储存起来。并且它会为缓存设定一个失效时间 (例如N小时)&#xff0c;在这N小时之内&#xff0c;当你再次访问这个网站时&#xff0…...

CSDN编程题-每日一练(2023-08-24)

CSDN编程题-每日一练(2023-08-24) 一、题目名称:计算公式二、题目名称:蛇形矩阵三、题目名称:小玉家的电费一、题目名称:计算公式 时间限制:1000ms内存限制:256M 题目描述: 给定整数n。 计算公式: n i-1 ∑ ∑ [gcd(i + j, i - j) = 1] i=1 j=1 输入描述: 输入整数n…...

怎么把PDF转成Word?需要注意什么事项?

PDF是一种常见的文档格式&#xff0c;但是与Word文档不同&#xff0c;PDF文件通常不能直接编辑。如果您想编辑PDF文件中的文本&#xff0c;或者想将PDF文件转换为Word文档&#xff0c;下面我们就来看一看把PDF转成Word有哪些方法和注意事项。 PDF转Word工具 有许多将PDF转换为…...

USACO22OPEN Pair Programming G

P8273 [USACO22OPEN] Pair Programming G 题目大意 一个程序由一系列指令组成&#xff0c;每条指令的类型如下&#xff1a; d \times d d&#xff0c;其中 d d d是一个 [ 0 , 9 ] [0,9] [0,9]范围内的整数 s s s&#xff0c;其中 s s s是一个表示变量名称的字符串&#xff…...

实战分享之springboot+easypoi快速业务集成

1.依赖引入 <!--引入EasyPOI--><dependency><groupId>cn.afterturn</groupId><artifactId>easypoi-base</artifactId><version>4.1.0</version></dependency><dependency><groupId>cn.afterturn</group…...

金字塔原理(思考的逻辑)

前言&#xff1a;前面学习了表达的逻辑&#xff0c;那在表达之前&#xff0c;如何组织内容&#xff1f;如何进行思考&#xff1f;接下来看第二篇——思考的逻辑。 目录 应用逻辑顺序 时间顺序 结构顺序 程度顺序 概括各组思想 什么是概括&#xff1f; 思想表达方式 如…...

机器学习之前向传播(Forward Propagation)和反向传播(Back propagation)

前向传播&#xff08;Forward Propagation&#xff09;和反向传播&#xff08;Back propagation&#xff09;是深度学习中神经网络训练的两个关键步骤。 前向传播&#xff08;Forward Propagation&#xff09;&#xff1a; 定义&#xff1a;前向传播是指从神经网络的输入层到输…...

Matlab高光谱遥感数据处理与混合像元分解实践技术

光谱和图像是人们观察世界的两种方式&#xff0c;高光谱遥感通过“图谱合一”的技术创新将两者结合起来&#xff0c;大大提高了人们对客观世界的认知能力&#xff0c;本来在宽波段遥感中不可探测的物质&#xff0c;在高光谱遥感中能被探测。以高光谱遥感为核心&#xff0c;构建…...

Docker consul的容器服务注册与发现

前言一、服务注册与发现二、consul 介绍三、consul 部署3.1 consul服务器3.1.1 建立 Consul 服务3.1.2 查看集群信息3.1.3 通过 http api 获取集群信息 3.2 registrator服务器3.2.1 安装 Gliderlabs/Registrator3.2.2 测试服务发现功能是否正常3.2.3 验证 http 和 nginx 服务是…...

Spring注入外部 工厂类Bean

问题 对于一些使用建造者模式的 Bean&#xff0c;我们往往不能直接 new 出来&#xff0c;这些 Bean 如果需要注册到 Spring 容器中&#xff0c;我们就需要使用工厂类。 比如我们项目中经常使用的okhttp: 如果我们想把OkHttpClient注册到Spring容器中&#xff0c;该怎么做? …...

WPF网格拖动自动布局效果

WPF网格拖动自动布局效果 使用Canvas和鼠标相关事件实现如下的效果: XAML代码: <Window x:Class="CanvasTest.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:...

肯德尔秩相关系数(Kendall‘s Tau)排名

肯德尔秩相关系数&#xff08;Kendall’s Tau&#xff09;是一种用于衡量两个排列之间相似性的统计指标&#xff0c;它考虑了元素之间的顺序关系而不考虑具体数值。该系数被广泛用于排序、排名和比较不同实验结果的相关性等领域。 具体而言&#xff0c;肯德尔秩相关系数衡量了…...

电脑怎么把视频转换gif动图?视频生成gif的操作步骤

如果你也想把一些精彩的视频转gif图片&#xff08;https://www.gif.cn&#xff09;的话&#xff0c;今天的文章你可千万不要错过&#xff0c;利用专业的视频转gif工具&#xff0c;轻松在线视频转gif&#xff0c;操作简单又方便&#xff0c;支持电脑、手机双端操作&#xff0c;赶…...

使用 docker 搭建 granfana+prometheus 监控平台监控测试服务器资源

互联网发展的今天&#xff0c;人们对互联网产品的用户体验要求也越来越高&#xff0c;企业为了能提供更优质的用户体验&#xff0c;就会绞尽脑汁想尽各种办法。而对于服务器的资源监控&#xff0c;搭建一个资源监控平台&#xff0c;就是一个很好的维护优质服务的保障平台。利用…...

一、MQ的基本概念

1、初识MQ MQ全称是Message Queue&#xff0c;消息队列&#xff0c;多用于系统之间进行异步通信。队列的概念数据结构中有详细介绍过&#xff0c;先进先出&#xff0c;消息队列就是存储消息的数据结构。 同步调用和异步调用两者之间的区别&#xff1a; 同步调用&#xff1a;发…...

Android面试题:MVC、MVP、MVVM

MVC模式&#xff1a; MVC结构&#xff1a; 1.MVC(Model-View-Controller) 2.Model:对数据库的操作、对网络等的操作都应该在Model里面处理&#xff0c;当然对业务计算&#xff0c;变更等操作也是必须放在的该层的。 3.View:主要包括一下View及ViewGroup控件&#xff0c;可以是…...

vue js 回调函数 异步处理 为什么要 let that = this

1 异步就是开个事务(只有主线程 等主线程空闲),用that 值 做处理,然后返回处理结果,而that的值是开启事务那一刻的this的值.而在主线程处理的时候,this的一直在变化, that的值保留在那一刻 ps 或是将本obj 传递给其他的obj使用处理 ps 开启新事务或开启新子线程都是 在新的ob…...

循环冗余码校验CRC码 算法步骤+详细实例计算

通信过程&#xff1a;&#xff08;白话解释&#xff09; 我们将原始待发送的消息称为 M M M&#xff0c;依据发送接收消息双方约定的生成多项式 G ( x ) G(x) G(x)&#xff08;意思就是 G &#xff08; x ) G&#xff08;x) G&#xff08;x) 是已知的&#xff09;&#xff0…...

2024年赣州旅游投资集团社会招聘笔试真

2024年赣州旅游投资集团社会招聘笔试真 题 ( 满 分 1 0 0 分 时 间 1 2 0 分 钟 ) 一、单选题(每题只有一个正确答案,答错、不答或多答均不得分) 1.纪要的特点不包括()。 A.概括重点 B.指导传达 C. 客观纪实 D.有言必录 【答案】: D 2.1864年,()预言了电磁波的存在,并指出…...

C++中string流知识详解和示例

一、概览与类体系 C 提供三种基于内存字符串的流&#xff0c;定义在 <sstream> 中&#xff1a; std::istringstream&#xff1a;输入流&#xff0c;从已有字符串中读取并解析。std::ostringstream&#xff1a;输出流&#xff0c;向内部缓冲区写入内容&#xff0c;最终取…...

Python如何给视频添加音频和字幕

在Python中&#xff0c;给视频添加音频和字幕可以使用电影文件处理库MoviePy和字幕处理库Subtitles。下面将详细介绍如何使用这些库来实现视频的音频和字幕添加&#xff0c;包括必要的代码示例和详细解释。 环境准备 在开始之前&#xff0c;需要安装以下Python库&#xff1a;…...

C++ 求圆面积的程序(Program to find area of a circle)

给定半径r&#xff0c;求圆的面积。圆的面积应精确到小数点后5位。 例子&#xff1a; 输入&#xff1a;r 5 输出&#xff1a;78.53982 解释&#xff1a;由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982&#xff0c;因为我们只保留小数点后 5 位数字。 输…...

浅谈不同二分算法的查找情况

二分算法原理比较简单&#xff0c;但是实际的算法模板却有很多&#xff0c;这一切都源于二分查找问题中的复杂情况和二分算法的边界处理&#xff0c;以下是博主对一些二分算法查找的情况分析。 需要说明的是&#xff0c;以下二分算法都是基于有序序列为升序有序的情况&#xf…...

RNN避坑指南:从数学推导到LSTM/GRU工业级部署实战流程

本文较长&#xff0c;建议点赞收藏&#xff0c;以免遗失。更多AI大模型应用开发学习视频及资料&#xff0c;尽在聚客AI学院。 本文全面剖析RNN核心原理&#xff0c;深入讲解梯度消失/爆炸问题&#xff0c;并通过LSTM/GRU结构实现解决方案&#xff0c;提供时间序列预测和文本生成…...

Linux nano命令的基本使用

参考资料 GNU nanoを使いこなすnano基础 目录 一. 简介二. 文件打开2.1 普通方式打开文件2.2 只读方式打开文件 三. 文件查看3.1 打开文件时&#xff0c;显示行号3.2 翻页查看 四. 文件编辑4.1 Ctrl K 复制 和 Ctrl U 粘贴4.2 Alt/Esc U 撤回 五. 文件保存与退出5.1 Ctrl …...

Python+ZeroMQ实战:智能车辆状态监控与模拟模式自动切换

目录 关键点 技术实现1 技术实现2 摘要&#xff1a; 本文将介绍如何利用Python和ZeroMQ消息队列构建一个智能车辆状态监控系统。系统能够根据时间策略自动切换驾驶模式&#xff08;自动驾驶、人工驾驶、远程驾驶、主动安全&#xff09;&#xff0c;并通过实时消息推送更新车…...

SQL Server 触发器调用存储过程实现发送 HTTP 请求

文章目录 需求分析解决第 1 步:前置条件,启用 OLE 自动化方式 1:使用 SQL 实现启用 OLE 自动化方式 2:Sql Server 2005启动OLE自动化方式 3:Sql Server 2008启动OLE自动化第 2 步:创建存储过程第 3 步:创建触发器扩展 - 如何调试?第 1 步:登录 SQL Server 2008第 2 步…...