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

本文涉及的产品
注册配置 MSE Nacos/ZooKeeper,118元/月
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
云原生网关 MSE Higress,422元/月
简介: 从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;
相关文章
|
16天前
|
人工智能 前端开发 Java
基于开源框架Spring AI Alibaba快速构建Java应用
本文旨在帮助开发者快速掌握并应用 Spring AI Alibaba,提升基于 Java 的大模型应用开发效率和安全性。
基于开源框架Spring AI Alibaba快速构建Java应用
|
30天前
|
人工智能 开发框架 Java
总计 30 万奖金,Spring AI Alibaba 应用框架挑战赛开赛
Spring AI Alibaba 应用框架挑战赛邀请广大开发者参与开源项目的共建,助力项目快速发展,掌握 AI 应用开发模式。大赛分为《支持 Spring AI Alibaba 应用可视化调试与追踪本地工具》和《基于 Flow 的 AI 编排机制设计与实现》两个赛道,总计 30 万奖金。
|
1月前
|
人工智能 Java API
阿里云开源 AI 应用开发框架:Spring AI Alibaba
近期,阿里云重磅发布了首款面向 Java 开发者的开源 AI 应用开发框架:Spring AI Alibaba(项目 Github 仓库地址:alibaba/spring-ai-alibaba),Spring AI Alibaba 项目基于 Spring AI 构建,是阿里云通义系列模型及服务在 Java AI 应用开发领域的最佳实践,提供高层次的 AI API 抽象与云原生基础设施集成方案,帮助开发者快速构建 AI 应用。本文将详细介绍 Spring AI Alibaba 的核心特性,并通过「智能机票助手」的示例直观的展示 Spring AI Alibaba 开发 AI 应用的便利性。示例源
|
23天前
|
消息中间件 自然语言处理 Java
知识科普:Spring Cloud Alibaba基本介绍
知识科普:Spring Cloud Alibaba基本介绍
56 2
|
1月前
|
人工智能 Java API
阿里云开源 AI 应用开发框架:Spring AI Alibaba
阿里云开源 Spring AI Alibaba,旨在帮助 Java 开发者快速构建 AI 应用,共同构建物理新世界。
|
1月前
|
人工智能 文字识别 Java
SpringCloud+Python 混合微服务,如何打造AI分布式业务应用的技术底层?
尼恩,一位拥有20年架构经验的老架构师,通过其深厚的架构功力,成功指导了一位9年经验的网易工程师转型为大模型架构师,薪资逆涨50%,年薪近80W。尼恩的指导不仅帮助这位工程师在一年内成为大模型架构师,还让他管理起了10人团队,产品成功应用于多家大中型企业。尼恩因此决定编写《LLM大模型学习圣经》系列,帮助更多人掌握大模型架构,实现职业跃迁。该系列包括《从0到1吃透Transformer技术底座》、《从0到1精通RAG架构》等,旨在系统化、体系化地讲解大模型技术,助力读者实现“offer直提”。此外,尼恩还分享了多个技术圣经,如《NIO圣经》、《Docker圣经》等,帮助读者深入理解核心技术。
SpringCloud+Python 混合微服务,如何打造AI分布式业务应用的技术底层?
|
2月前
|
人工智能 开发框架 Java
重磅发布!AI 驱动的 Java 开发框架:Spring AI Alibaba
随着生成式 AI 的快速发展,基于 AI 开发框架构建 AI 应用的诉求迅速增长,涌现出了包括 LangChain、LlamaIndex 等开发框架,但大部分框架只提供了 Python 语言的实现。但这些开发框架对于国内习惯了 Spring 开发范式的 Java 开发者而言,并非十分友好和丝滑。因此,我们基于 Spring AI 发布并快速演进 Spring AI Alibaba,通过提供一种方便的 API 抽象,帮助 Java 开发者简化 AI 应用的开发。同时,提供了完整的开源配套,包括可观测、网关、消息队列、配置中心等。
2133 18
|
2月前
|
Java 对象存储 开发者
故障隔离与容错处理:Hystrix在Spring Cloud和Netflix OSS中的应用
故障隔离与容错处理:Hystrix在Spring Cloud和Netflix OSS中的应用
53 3
|
2月前
|
人工智能 前端开发 Java
Spring Cloud Alibaba AI,阿里AI这不得玩一下
🏀闪亮主角: 大家好,我是JavaDog程序狗。今天分享Spring Cloud Alibaba AI,基于Spring AI并提供阿里云通义大模型的Java AI应用。本狗用SpringBoot+uniapp+uview2对接Spring Cloud Alibaba AI,带你打造聊天小AI。 📘故事背景: 🎁获取源码: 关注公众号“JavaDog程序狗”,发送“alibaba-ai”即可获取源码。 🎯主要目标:
86 0
|
3月前
|
人工智能 前端开发 Java
【实操】Spring Cloud Alibaba AI,阿里AI这不得玩一下(含前后端源码)
本文介绍了如何使用 **Spring Cloud Alibaba AI** 构建基于 Spring Boot 和 uni-app 的聊天机器人应用。主要内容包括:Spring Cloud Alibaba AI 的概念与功能,使用前的准备工作(如 JDK 17+、Spring Boot 3.0+ 及通义 API-KEY),详细实操步骤(涵盖前后端开发工具、组件选择、功能分析及关键代码示例)。最终展示了如何成功实现具备基本聊天功能的 AI 应用,帮助读者快速搭建智能聊天系统并探索更多高级功能。
1340 2
【实操】Spring Cloud Alibaba AI,阿里AI这不得玩一下(含前后端源码)