从0到1 手把手搭建spring cloud alibaba 微服务大型应用框架(六)开发篇-如何解决微服务开发环境请求实例转发到别人机器问题

本文涉及的产品
云原生网关 MSE Higress,422元/月
注册配置 MSE Nacos/ZooKeeper,118元/月
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
简介: 从0到1 手把手搭建spring cloud alibaba 微服务大型应用框架(六)开发篇-如何解决微服务开发环境请求实例转发到别人机器问题

image.png当前公司内微服务开发一般有两种模式


1.开发启动所有服务,注册中心,网关,认证服务等都在自己机器启动


优点:可以保证自己发送的请求(经过网关的请求或者通过fegin调用的请求)都能达到自己机器的服务


缺点:如果服务过多,电脑有可能会承受不住


2.开发只启动自己需要开发的服务,注册中心,网关,认证服务等都在一个公用的服务器启动,所有人启动的服务都注册到了这个公用服务上


优点:只需要启动自己开发的服务,方便快捷,节省电脑资源

缺点:由于自己开发的服务不一定只有自己启动了,有可能有别人同时启动了该服务,所以当从前端请求或者通过fegin请求时,可能请求会发送到了别人机器启动的服务上


模式2会有请求发送到别人机器对应服务的情况,具体情况明细图如下


1.png

图1

说明:

图1 通过网关请求后台服务A ,由于两个开发人员都启动了服务A并且注册到了公用注册中心上,使用默认负载均衡策略得话,此时请求到的不一定是小李的还是小张的电脑的服务A

1.png

图2


说明:

图二 通过fegin请求后台服务A ,由于两个开发人员都启动了服务A并且注册到了公用注册中心上,使用默认负载均衡策略得话,所以此时请求到的不一定是小李的还是小张的电脑的服务A

解决方案,由于上面问题都是在负载均衡获取实例时随机去到了一个实例,所以解决方式就是重写负载均衡路由指定获取特定的实例

网关端重写路由解决方案解决图1问题

1.png

代码,添加如下这几个类

1.png

CustomRibbonRule.java

public class CustomRibbonRule extends RoundRobinRule {
    private String version;
    public void setVersion(String version) {
        this.version = version;
    }
    @Override
    public Server choose(ILoadBalancer lb, Object key) {
        List<Server> targetList = null;
        List<Server> upList = lb.getReachableServers();
        if (StrUtil.isEmpty(version)) {
            version = ReqeustHeaderContextHolder.getVersion();
        }
        if (StrUtil.isNotEmpty(version)) {
            //取指定版本号的实例
            targetList = upList.stream().filter(
                    server -> version.equals(
                            ((NacosServer) server).getMetadata().get("version")
                    )
            ).collect(Collectors.toList());
        }
        if (CollUtil.isEmpty(targetList)) {
            //只取无版本号的实例
            targetList = upList.stream().filter(
                    server -> {
                        String metadataVersion = ((NacosServer) server).getMetadata().get("version");
                        return StrUtil.isEmpty(metadataVersion);
                    }
            ).collect(Collectors.toList());
        }
        if (CollUtil.isNotEmpty(targetList)) {
            return getServer(targetList);
        }
        return super.choose(lb, key);
    }
    private Server getServer(List<Server> upList) {
        int nextInt = RandomUtil.randomInt(upList.size());
        return upList.get(nextInt);
    }
}

RibbonConfiguration.java

@Configuration
public class RibbonConfiguration {
    @Value("${spring.cloud.nacos.discovery.metadata.version:#{null}}")
    private String version;
    @Bean
    public IRule defaultLBStrategy() {
        CustomRibbonRule customIsolationRule = new CustomRibbonRule();
        customIsolationRule.setVersion(version);
        return customIsolationRule;
    }
}

ReqeustHeaderContextHolder.java

public class ReqeustHeaderContextHolder {
    private static final FastThreadLocal fastThreadLocal = new FastThreadLocal();
    public static void putVersion(String version){
        fastThreadLocal.set(version);
    }
    public static String getVersion(){
        return Objects.isNull(fastThreadLocal.get())?null:(String) fastThreadLocal.get();
    }
    public static void clear(){
        fastThreadLocal.remove();
    }
}

OrderedGatewayFilter.java

public class OrderedGatewayFilter implements GatewayFilter, Ordered {
    private final GatewayFilter delegate;
    private final int order;
    public OrderedGatewayFilter(GatewayFilter delegate, int order) {
        this.delegate = delegate;
        this.order = order;
    }
    public GatewayFilter getDelegate() {
        return delegate;
    }
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        try{
            if(CollectionUtil.isNotEmpty(exchange.getRequest().getHeaders().get("version"))){
                String version = exchange.getRequest().getHeaders().get("version").get(0);
                ReqeustHeaderContextHolder.putVersion(version);
            }
            return this.delegate.filter(exchange, chain);
        }finally {
            ReqeustHeaderContextHolder.clear();
        }
    }
    @Override
    public int getOrder() {
        return this.order;
    }
    @Override
    public String toString() {
        return new StringBuilder("[").append(delegate).append(", order = ").append(order)
                .append("]").toString();
    }
}

fegin端重写路由解决方案解决图2问题

1.png

服务fegin的负载均衡路由,注册时将自己机器的服务A加上特定key属性注册到注册中心内,获取时优先获取有指定key的实例,没有找到再随机获取一个实例


代码:

各个应用部分可以添加如下类或者抽取出共通类

1.png

CustomRibbonRule.java

public class CustomRibbonRule extends RoundRobinRule {
    private String version;
    public void setVersion(String version) {
        this.version = version;
    }
    @Override
    public Server choose(ILoadBalancer lb, Object key) {
        List<Server> targetList = null;
        List<Server> upList = lb.getReachableServers();
        if (StrUtil.isNotEmpty(version)) {
            //取指定版本号的实例
            targetList = upList.stream().filter(
                    server -> version.equals(
                            ((NacosServer) server).getMetadata().get("version")
                    )
            ).collect(Collectors.toList());
        }
        if (CollUtil.isEmpty(targetList)) {
            //只取无版本号的实例
            targetList = upList.stream().filter(
                    server -> {
                        String metadataVersion = ((NacosServer) server).getMetadata().get("version");
                        return StrUtil.isEmpty(metadataVersion);
                    }
            ).collect(Collectors.toList());
        }
        if (CollUtil.isNotEmpty(targetList)) {
            return getServer(targetList);
        }
        return super.choose(lb, key);
    }
    private Server getServer(List<Server> upList) {
        int nextInt = RandomUtil.randomInt(upList.size());
        return upList.get(nextInt);
    }
}

RibbonConfiguration.java

@Configuration
public class RibbonConfiguration {
    @Value("${spring.cloud.nacos.discovery.metadata.version:#{null}}")
    private String version;
    @Bean
    public IRule defaultLBStrategy() {
        CustomRibbonRule customIsolationRule = new CustomRibbonRule();
        customIsolationRule.setVersion(version);
        return customIsolationRule;
    }
}

然后对应yml里面添加自己对应的version

1.png

大功告成,看看效果


首先在需要走自己机器的服务上加上对应version,都启动后如下图

1.png

1.png

我们通过postman 模拟前端请求网关访问看看是不是走的我们指定的xiaoli 的实例

1.png

可以看到我们网关自定义的负载路由去到了version=xiaoli的实例


再来看看fegin调用的时候是不是也是走的我们指定version的实例

1.png

可以看order调用商品服务的时候也是找了商品服务version为xiaoli的实例,整明两个问题都解决了

相关实践学习
DataV Board用户界面概览
本实验带领用户熟悉DataV Board这款可视化产品的用户界面
阿里云实时数仓实战 - 项目介绍及架构设计
课程简介 1)学习搭建一个数据仓库的过程,理解数据在整个数仓架构的从采集、存储、计算、输出、展示的整个业务流程。 2)整个数仓体系完全搭建在阿里云架构上,理解并学会运用各个服务组件,了解各个组件之间如何配合联动。 3&nbsp;)前置知识要求 &nbsp; 课程大纲 第一章&nbsp;了解数据仓库概念 初步了解数据仓库是干什么的 第二章&nbsp;按照企业开发的标准去搭建一个数据仓库 数据仓库的需求是什么 架构 怎么选型怎么购买服务器 第三章&nbsp;数据生成模块 用户形成数据的一个准备 按照企业的标准,准备了十一张用户行为表 方便使用 第四章&nbsp;采集模块的搭建 购买阿里云服务器 安装 JDK 安装 Flume 第五章&nbsp;用户行为数据仓库 严格按照企业的标准开发 第六章&nbsp;搭建业务数仓理论基础和对表的分类同步 第七章&nbsp;业务数仓的搭建&nbsp; 业务行为数仓效果图&nbsp;&nbsp;
相关文章
|
7天前
|
前端开发 Java 物联网
智慧班牌源码,采用Java + Spring Boot后端框架,搭配Vue2前端技术,支持SaaS云部署
智慧班牌系统是一款基于信息化与物联网技术的校园管理工具,集成电子屏显示、人脸识别及数据交互功能,实现班级信息展示、智能考勤与家校互通。系统采用Java + Spring Boot后端框架,搭配Vue2前端技术,支持SaaS云部署与私有化定制。核心功能涵盖信息发布、考勤管理、教务处理及数据分析,助力校园文化建设与教学优化。其综合性和可扩展性有效打破数据孤岛,提升交互体验并降低管理成本,适用于日常教学、考试管理和应急场景,为智慧校园建设提供全面解决方案。
77 16
|
2月前
|
前端开发 Java 数据库连接
Spring框架初识
Spring 是一个分层的轻量级开源框架,核心功能包括控制反转(IOC)和面向切面编程(AOP)。主要模块有核心容器、Spring 上下文、AOP、DAO、ORM、Web 模块和 MVC 框架。它通过 IOC 将配置与代码分离,简化开发;AOP 提供了声明性事务管理等增强功能。
99 21
Spring框架初识
|
2月前
|
存储 人工智能 开发框架
Spring AI Alibaba 应用框架挑战赛圆满落幕,恭喜获奖选手
第二届开放原子大赛 Spring AI Alibaba 应用框架挑战赛决赛于 2 月 23 日在北京圆满落幕。
160 17
|
1月前
|
前端开发 Java 数据库连接
Spring MVC 扩展和SSM框架整合
通过以上步骤,我们可以将Spring MVC扩展并整合到SSM框架中。这个过程包括配置Spring MVC和Spring的核心配置文件,创建控制器、服务层和MyBatis的Mapper接口及映射文件。在实际开发中,可以根据具体业务需求进行进一步的扩展和优化,以构建更加灵活和高效的企业级应用程序。
49 5
|
3月前
|
SQL Java 数据库连接
对Spring、SpringMVC、MyBatis框架的介绍与解释
Spring 框架提供了全面的基础设施支持,Spring MVC 专注于 Web 层的开发,而 MyBatis 则是一个高效的持久层框架。这三个框架结合使用,可以显著提升 Java 企业级应用的开发效率和质量。通过理解它们的核心特性和使用方法,开发者可以更好地构建和维护复杂的应用程序。
178 29
|
2月前
|
XML Java 开发者
通过springboot框架创建对象(一)
在Spring Boot中,对象创建依赖于Spring框架的核心特性——控制反转(IoC)和依赖注入(DI)。IoC将对象的创建和管理交由Spring应用上下文负责,开发者只需定义依赖关系。DI通过构造函数、setter方法或字段注入实现依赖对象的传递。Spring Boot的自动配置机制基于类路径和配置文件,自动为应用程序配置Spring容器,简化开发过程。Bean的生命周期包括定义扫描、实例化、依赖注入、初始化和销毁回调,均由Spring容器管理。这些特性提高了开发效率并简化了代码维护。
|
1月前
|
存储 监控 数据可视化
SaaS云计算技术的智慧工地源码,基于Java+Spring Cloud框架开发
智慧工地源码基于微服务+Java+Spring Cloud +UniApp +MySql架构,利用传感器、监控摄像头、AI、大数据等技术,实现施工现场的实时监测、数据分析与智能决策。平台涵盖人员、车辆、视频监控、施工质量、设备、环境和能耗管理七大维度,提供可视化管理、智能化报警、移动智能办公及分布计算存储等功能,全面提升工地的安全性、效率和质量。
|
2月前
|
传感器 监控 安全
智慧工地云平台的技术架构解析:微服务+Spring Cloud如何支撑海量数据?
慧工地解决方案依托AI、物联网和BIM技术,实现对施工现场的全方位、立体化管理。通过规范施工、减少安全隐患、节省人力、降低运营成本,提升工地管理的安全性、效率和精益度。该方案适用于大型建筑、基础设施、房地产开发等场景,具备微服务架构、大数据与AI分析、物联网设备联网、多端协同等创新点,推动建筑行业向数字化、智能化转型。未来将融合5G、区块链等技术,助力智慧城市建设。
109 0
|
5月前
|
设计模式 Java API
微服务架构演变与架构设计深度解析
【11月更文挑战第14天】在当今的IT行业中,微服务架构已经成为构建大型、复杂系统的重要范式。本文将从微服务架构的背景、业务场景、功能点、底层原理、实战、设计模式等多个方面进行深度解析,并结合京东电商的案例,探讨微服务架构在实际应用中的实施与效果。
296 6
|
5月前
|
设计模式 Java API
微服务架构演变与架构设计深度解析
【11月更文挑战第14天】在当今的IT行业中,微服务架构已经成为构建大型、复杂系统的重要范式。本文将从微服务架构的背景、业务场景、功能点、底层原理、实战、设计模式等多个方面进行深度解析,并结合京东电商的案例,探讨微服务架构在实际应用中的实施与效果。
138 1