基于重写ribbon负载实现灰度发布
项目结构如下
代码如下:
pom:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>sca.pro</groupId><artifactId>sca-parent</artifactId><version>1.0.1</version></parent><groupId>sca.gary.publish</groupId><artifactId>gray-spring-boot-starter</artifactId><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><dependencies><!-- Compile dependencies --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-configuration-processor</artifactId><optional>true</optional></dependency><dependency><groupId>com.netflix.ribbon</groupId><artifactId>ribbon-loadbalancer</artifactId><scope>provided</scope></dependency><dependency><groupId>com.alibaba</groupId><artifactId>transmittable-thread-local</artifactId><version>2.14.2</version></dependency><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency><dependency><groupId>io.github.openfeign</groupId><artifactId>feign-core</artifactId><scope>provided</scope></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-web</artifactId><scope>provided</scope></dependency><dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId></dependency></dependencies><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><configuration><source>1.8</source><target>1.8</target><encoding>${project.build.sourceEncoding}</encoding></configuration></plugin></plugins></build></project>
spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
sca.gary.publish.graypublish.config.GrayConfig,\
sca.gary.publish.graypublish.feignInterceptor.FeignRequestInterceptor
GrayConfig:可以在对应服务启动类添加如下,可写多个服务
@RibbonClients(value = {@RibbonClient(value = "nacos中的服务名称",configuration = GrayConfig.class) })
package sca.gary.publish.graypublish.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import sca.gary.publish.graypublish.GrayRule;//@Configuration
之前理解有误,这里千万不能加它,否则服务调用会混乱
public class GrayConfig {@Beanpublic GrayRule grayRule(){return new GrayRule();}
}
ContantsString:版本号请求头key
package sca.gary.publish.graypublish.contans;public class ContantsString {public static final String GRAY_KEY="version";}
FeignRequestInterceptor:feign拦截器,当远程调用时,将版本号保存到ttl中,供给服务负载使用,并把当前请求头中的版本号放在远程调用的请求头中,防止它仍需要远程调用
package sca.gary.publish.graypublish.feignInterceptor;import feign.RequestInterceptor;
import feign.RequestTemplate;
import org.springframework.context.annotation.Import;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import sca.gary.publish.graypublish.contans.ContantsString;
import sca.gary.publish.graypublish.ttl.ThreadLocalUtils;import javax.servlet.http.HttpServletRequest;
import java.util.Enumeration;
import java.util.LinkedHashMap;
import java.util.Map;@Component
public class FeignRequestInterceptor implements RequestInterceptor {@Overridepublic void apply(RequestTemplate template) {ServletRequestAttributes sra = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();HttpServletRequest request = sra.getRequest();Map<String, String> headers = getHeaders(request);for (Map.Entry<String, String> entry : headers.entrySet()) {//② 设置请求头到新的Request中template.header(entry.getKey(), entry.getValue());}}/*** 获取原请求头*/private Map<String, String> getHeaders(HttpServletRequest request) {Map<String, String> map = new LinkedHashMap<>();Enumeration<String> enumeration = request.getHeaderNames();if (enumeration != null) {while (enumeration.hasMoreElements()) {String key = enumeration.nextElement();String value = request.getHeader(key);//将灰度标记的请求头透传给下个服务if (ContantsString.GRAY_KEY.equals(key)){//① 保存灰度发布的标记ThreadLocalUtils.set(ContantsString.GRAY_KEY,value);map.put(key, value);}}}return map;}
}
ThreadLocalUtils:用于存储网关传递过来的版本号,实现当前服务的负载选择
package sca.gary.publish.graypublish.ttl;import com.alibaba.ttl.TransmittableThreadLocal;
import java.util.HashMap;
import java.util.Map;public class ThreadLocalUtils {private static TransmittableThreadLocal<Map<String, Object>> cache = new TransmittableThreadLocal<>();/*** 设置对象到本地变量** @param object*/public static void set(String key, Object object) {if (!isCaheIsNull()) {cache.get().put(key, object);} else {Map<String, Object> map = new HashMap<>();map.put(key, object);cache.set(map);}}/*** 从本地变量中获取变量** @return*/public static Object get(String key) {if (!isCaheIsNull()) {return cache.get().get(key);} else {return null;}}/*** 根据KEY移除缓存里的数据** @param key*/public static void remove(String key) {if (isCaheIsNull()) {return;} else {cache.get().remove(key);}}/*** 释放本地线程资源*/public static void clear() {cache.remove();}/*** 是否存在本地变量** @return*/private static boolean isCaheIsNull() {return cache.get() == null;}}
GrayRule:
最重要的就是这个类,重写了ribbon的负载策略,通过从网关传递过来的版本号,和每个服务中的元数据版本号进行对比,如果相同则调用它们的版本,如果没有找到对应版本的服务,则将获取到的所有服务按照原规则进行负载
package sca.gary.publish.graypublish;import com.alibaba.cloud.nacos.ribbon.NacosServer;
import com.google.common.base.Optional;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.Server;
import com.netflix.loadbalancer.ZoneAvoidanceRule;
import org.springframework.util.ObjectUtils;
import sca.gary.publish.graypublish.contans.ContantsString;
import sca.gary.publish.graypublish.ttl.ThreadLocalUtils;import java.util.ArrayList;
import java.util.List;public class GrayRule extends ZoneAvoidanceRule {@Overridepublic void initWithNiwsConfig(IClientConfig clientConfig) {}@Overridepublic Server choose(Object key) {try {//从ThreadLocal中获取灰度标记Object version = ThreadLocalUtils.get(ContantsString.GRAY_KEY);//获取所有可用服务List<Server> serverList = this.getLoadBalancer().getReachableServers();//灰度发布的服务List<Server> grayServerList = new ArrayList<>();if (ObjectUtils.isEmpty(version)){return originChoose(serverList,key);}for(Server server : serverList) {NacosServer nacosServer = (NacosServer) server;//从nacos中获取元素剧进行匹配if(nacosServer.getMetadata().containsKey(ContantsString.GRAY_KEY)&& nacosServer.getMetadata().get(ContantsString.GRAY_KEY).equals(version.toString()) ){grayServerList.add(server);}}if (!ObjectUtils.isEmpty(grayServerList)){return originChoose(grayServerList,key);}return originChoose(serverList,key);} finally {//清除灰度标记ThreadLocalUtils.clear();}}private Server originChoose(List<Server> noMetaServerList, Object key) {Optional<Server> serverOptional = getPredicate().chooseRoundRobinAfterFiltering(noMetaServerList, key);if (serverOptional.isPresent()) {return serverOptional.get();} else {return null;}}}
使用方式:
1.首先保证每个服务都有feign的依赖
2.添加依赖如下
<dependency><groupId>sca.gary.publish</groupId><artifactId>gray-spring-boot-starter</artifactId><version>1.0.1</version><exclusions><exclusion><groupId>io.github.openfeign</groupId><artifactId>feign-core</artifactId></exclusion></exclusions> </dependency>
3.yaml添加配置
spring:
cloud:
nacos:
discovery:
metadata:
version: 2.0
3.在启动类上添加下边的,需要远程调用哪个服务,就加哪几个
@RibbonClients(value = {@RibbonClient(value = "服务名",configuration = GrayConfig.class) })
相关文章:
基于重写ribbon负载实现灰度发布
项目结构如下 代码如下: pom: <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocat…...
无端科技一面(生死狙击项目组 战斗客户端 40min)
自我介绍 实习经历询问 项目询问 TCP和UDP的区别 什么情况会用到UDP 大小端 寻路算法了解多少 A*算法 场景题:扫雷如何随机分地雷,怎么安排数字显示 怎么判断一个物体在三角锥内 动作游戏中打击效果怎么处理穿模问题 八叉树了解过吗 骨骼动画…...
idea开发 java web 高校学籍管理系统bootstrap框架web结构java编程计算机网页
一、源码特点 java 高校学籍管理系统是一套完善的完整信息系统,结合java web开发和bootstrap UI框架完成本系统 ,对理解JSP java编程开发语言有帮助,系统具有完整的源代码和数据库,系统主要采用B/S模式开发。 前段主要技术 css jq…...
linux之文件系统、inode和动静态库制作和发布
一、背景 1.没有被打开的文件都在磁盘上 --- 磁盘级文件 2.对磁盘级别的文件,我们的侧重点 单个文件角度 -- 这个文件在哪里,有多大,其他属性是什么? 站在系统角度 -- 一共有多少文件?各自属性在哪里?…...
C++IO类,输入输出缓冲区,流状态
我们的程序已经使用了很多IO库设施: istream(输入流)类型,提供输入操作。ostream(输出流)类型,提供输出操作。cin,一个istream对象,从标准输入读取数据。写入到标准错误。cout,一个ostream对象,…...
机器学习笔记 - 文字转语音技术路线简述以及相关工具不完全清单
一、TTS技术简述 今天的文本到语音转换技术(TTS)的目标已经不仅仅是让机器说话,而是让它们听起来像不同年龄和性别的人类。通常,TTS 系统合成器的质量是从不同方面进行评估的,包括合成语音的清晰度、自然度和偏好,以及人类感知因素,例如可理解性。 1、技术路线 (1)基…...
阿里云4核8G服务器ECS通用算力型u1实例优惠价格
阿里云4核8G服务器优惠价格955元一年,配置为ECS通用算力型u1实例(ecs.u1-c1m2.xlarge)4核8G配置、1M到3M带宽可选、ESSD Entry系统盘20G到40G可选,CPU采用Intel(R) Xeon(R) Platinum处理器,阿里云活动链接 aliyunfuwuq…...
Jetson nano部署Yolov8 安装Archiconda3+创建pytorch环境(详细教程+错误解决)
由于jetson nano 是aarch64架构,Anaconda官方不支持aarch64架构,所以有了一个叫“Archiconda”,其目的就是将conda移植到aarch64平台上 一. 下载地址Releases Archiconda/build-tools GitHub 然后安装archiconda bash Archiconda3-0.2.3…...
Node.JS多线程PromisePool之promise-pool库实现
什么是Promise Pool Map-like, concurrent promise processing for Node.js. Promise-Pool是一个用于管理并发请求的JavaScript库,它可以限制同时进行的请求数量,以避免过多的请求导致服务器压力过大。使用Promise-Pool可以方便地实现对多个异步操作的并…...
【C++】红黑树讲解及实现
前言: AVL树与红黑树相似,都是一种平衡二叉搜索树,但是AVL树的平衡要求太严格,如果要对AVL树做一些结构修改的操作性能会非常低下,比如:插入时要维护其绝对平衡,旋转的次数比较多,更…...
security如何不拦截websocket
只要添加一个关键配置就行 //忽略websocket拦截Overridepublic void configure(WebSecurity webSecurity){webSecurity.ignoring().antMatchers("/**");} 全部代码我放着了 package com.oddfar.campus.framework.config;import com.oddfar.campus.framework.secur…...
Unity类银河恶魔城学习记录12-3 p125 Limit Inventory Slots源代码
Alex教程每一P的教程原代码加上我自己的理解初步理解写的注释,可供学习Alex教程的人参考 此代码仅为较上一P有所改变的代码 【Unity教程】从0编程制作类银河恶魔城游戏_哔哩哔哩_bilibili Inventory.cs using Newtonsoft.Json.Linq; using System.Collections; us…...
【智能排班系统】雪花算法生成分布式ID
文章目录 雪花算法介绍起源与命名基本原理与结构优势与特点应用场景 代码实现代码结构自定义机器标识RandomWorkIdChooseLocalRedisWorkIdChooselua脚本 实体类SnowflakeIdInfoWorkCenterInfo 雪花算法类配置类雪花算法工具类 说明 雪花算法介绍 在复杂而庞大的分布式系统中&a…...
sass中的导入与部分导入
文章目录 sass中的导入与部分导入1. import:传统的导入方式2. use:现代化的模块化导入 sass中的导入与部分导入 在大型前端项目中,CSS代码量往往十分庞大,为了保持其可读性、可维护性以及便于团队协作,模块化开发成为…...
工业组态 物联网组态 组态编辑器 web组态 组态插件 编辑器
体验地址:by组态[web组态插件] BY组态是一款非常优秀的纯前端的【web组态插件工具】,可无缝嵌入到vue项目,react项目等,由于是原生js开发,对于前端的集成没有框架的限制。同时由于BY组态只是一个插件,不能独…...
git可视化工具
Gitkraken GitKraken 是一款专门用于管理和协作Git仓库的图形化界面工具。它拥有友好直观的界面,使得Git的操作变得更加简单易用,尤其适合那些不熟悉Git命令行的开发者。GitKraken提供了丰富的功能,如代码审查、分支管理、仓库克隆、提交、推…...
基于单片机电子密码锁系统设计
**单片机设计介绍,基于单片机电子密码锁系统设计 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于单片机电子密码锁系统设计概要主要包括以下几个方面: 一、系统概述 基于单片机电子密码锁系统是一个…...
点云从入门到精通技术详解100篇-基于点云与图像纹理的 道路识别(续)
目录 3.1.2 图像滤波去噪 3.2 道路纹理特征提取 3.3 基于超像素分割的图像特征表达...
《机器学习在量化投资中的应用研究》目录
机器学习在量化投资中的应用研究 获取链接:机器学习在量化投资中的应用研究_汤凌冰著_北京:电子工业出版社 更多技术书籍:技术书籍分享,前端、后端、大数据、AI、人工智能... 内容简介 《机器学习在量化投资中的应用研究…...
Spring拓展点之SmartLifecycle如何感知容器启动和关闭
Spring为我们提供了拓展点感知容器的启动与关闭,从而使我们可以在容器启动或者关闭之时进行定制的操作。Spring提供了Lifecycle上层接口,这个接口只有两个方法start和stop两个方法,但是这个接口并不是直接提供给开发者做拓展点,而…...
深入理解Java匿名内部类(day21)
在Java编程中,匿名内部类是一种非常有用的特性,它允许我们定义和实例化一个类的子类或实现一个接口,而无需给出子类的名称。这种特性使得代码更加简洁、紧凑,尤其适用于一些只使用一次的临时对象。本文将深入探讨Java匿名内部类的…...
《状态模式(极简c++)》
本文章属于专栏- 概述 - 《设计模式(极简c版)》-CSDN博客 模式说明: 方案:状态模式是一种行为设计模式,用于在对象的内部状态发生改变时改变其行为。它包括三个关键角色:上下文(Context&#x…...
Day4-Hive直播行业基础笔试题
Hive笔试题实战 短视频 题目一:计算各个视频的平均完播率 有用户-视频互动表tb_user_video_log: id uid video_id start_time end_time if_follow if_like if_retweet comment_id 1 101 2001 2021-10-01 10:00:00 2021-10-01 10:00:30 …...
mybatis批量新增数据
数据量大的时候如果在循环中执行单条新增操作,是非常慢的。那么如何在mybatis中实现批量新增数据呢? 方法 insert 标签的 foreach 属性可以用于批量插入数据。您可以使用 foreach 属性遍历一个集合,并为集合中的每个元素生成一条插入语句。…...
webrtcP2P通话流程
文章目录 webrtcP2P通话流程webrtc多对多 mesh方案webrtc多对多 mcu方案webrtc多对多 sfu方案webrtc案例测试getUserMediagetUserMedia基础示例-打开摄像头getUserMedia canvas - 截图 打开共享屏幕 webrtcP2P通话流程 在这里,stun服务器包括stun服务和turn转发服…...
游戏引擎中的物理系统
一、物理对象与形状 1.1 对象 Actor 一般来说,游戏中的对象(Actor)分为以下四类: 静态对象 Static Actor动态对象 Dynamic Actor ---- 可能受到力/扭矩/冲量的影响检测器 TriggerKinematic Actor 运动学对象 ---- 忽略物理法则…...
【C++ STL有序关联容器】map 映射
文章目录 【 1. 基本原理 】【 2. map 的创建 】2.1 调用默认构造函数,创建一个空的 map2.2 map 被构造的同时初始化2.3 通过一个 queue 初始化另一个 queue2.4 取已建 map 中指定区域内的键值对,初始化新的 map2.5 指定排序规则 【 2. map 元素的操作 】…...
【ZZULIOJ】1041: 数列求和2(Java)
目录 题目描述 输入 输出 样例输入 Copy 样例输出 Copy code 题目描述 输入一个整数n,输出数列1-1/31/5-……前n项的和。 输入 输入只有一个整数n。 输出 结果保留2为小数,单独占一行。 样例输入 Copy 3 样例输出 Copy 0.87 code import java.util…...
C++【适配器模式】
简单介绍 适配器模式是一种结构型设计模式 | 它能使接口不兼容的对象能够相互合作。(是适配各种不同接口的一个中间件) 基础理解 举个例子:当你引用了一个第三方数据分析库,但这个库的接口只能兼容JSON 格式的数据。但你需要它…...
go | 上传文件分析 | http协议分析 | 使用openssl 实现 https 协议 server.key、server.pem
是这样的,现在分析抓包数据 test.go package mainimport ("fmt""log""github.com/gin-gonic/gin" )func main() {r : gin.Default()// Upload single filer.MaxMultipartMemory 8 << 20r.POST("/upload", func(c *g…...
南京马鞍山网站建设/网站优化公司怎么选
筛选信息的方法()A:时序法、程序研究法、询问法B:时序法、类比法、查重法C:时序法、类比法、研究法D:时序法、研究法、查重法框架筛域即筛管分子的侧壁上特化的初生纹孔场。A:对B:错选项山茶科植物的雌蕊具有A:下位子房具侧膜胎座B:下位子房具基生胎座C:上位子房具中轴胎座D:上…...
做泵阀到哪个网站好/全国人大常委会委员长
1.问题背景默认情况下,线上的mysql复制都是异步复制,因此在极端情况下,主备切换时,会有一定的概率备库比主库数据少,因此切换后,我们会通过工具进行回滚回补,确保数据不丢失。半同步复制则要求主…...
如何给公司做网站推广宣传/seo网站优化培训
(1) 10gen,它既是一个云平台,又是一个可下载的开放源代码包,可用于创建您自己的私有云。10gen 是类似于 App Engine 的一个软件栈,它提供与 App Engine 类似的功能 — 但有一些不同之处。通过 10gen&#x…...
软件工程做项目网站/google adsense
文章目录一、sed二、awk一、sed sed是一种新型的,非交互式的流编辑器,它能执行与编辑器 vi 和 ex 相同的编辑任务。sed 编辑器没有提供交互式使用方式,使用者只能在命令行输入编辑命令、指定文件名,然后在屏幕上查看输出。 工作…...
wordpress建一个网站/手机seo排名
由于项目需要实现一个垂直的Slider,滑动条使用UIlabel实现,按钮使用UIButton,按钮可以设置背景图片,代码如下 VerticalSlider.h // // VerticalSlider.h // EXOTerra // // Created by huang zhengguo on 2019/8/30. // Copyr…...
怎么自己做网站吗/福州seo管理
linux selinuxSELinux的历史 在美国国家安全局(NSA)内部启动了涉及开发安全增强型Linux(SELinux)(该系统提供强制访问控制)的项目。 安全计算公司(SCC)和MITER公司以及许多研究实验…...