解密Spring Cloud微服务调用:如何轻松获取请求目标方的IP和端口

这篇具有很好参考价值的文章主要介绍了解密Spring Cloud微服务调用:如何轻松获取请求目标方的IP和端口。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

公众号「架构成长指南」,专注于生产实践、云原生、分布式系统、大数据技术分享。

目的

Spring Cloud 线上微服务实例都是2个起步,如果出问题后,在没有ELK等日志分析平台,如何确定调用到了目标服务的那个实例,以此来排查问题

效果

可以看到服务有几个实例是上线,并且最终调用了那个实例

考虑到Spring Cloud在版本升级中使用了两种负载均衡实现,RobinLoadBalancer,下面我们提供两种实现方案

Robin实现方案

1. 技术栈

  • Spring Cloud: Hoxton.SR6
  • Spring Boot: 2.3.1.RELEASE
  • Spring-Cloud-Openfeign: 2.2.3.RELEASE

2. 继承RoundRobinRule,并重写choose方法

/**
 * 因为调用目标机器的时候,如果目标机器本身假死或者调用目标不通无法数据返回,那么feign无法打印目标机器。这种场景下我们需要在调用失败(目标机器没有返回)的时候也能把目标机器的ip打印出来,这种场景需要我们切入feign选择机器的逻辑,注入我们自己的调度策略(默认是roundrobin),在里面打印选择的机器即可。
*/
@Slf4j
public class FeignRule extends RoundRobinRule {

    @Override
    public Server choose(Object key) {
        Server server = super.choose(key);
        if (Objects.isNull(server)) {
            log.info("server is null");
            return null;
        }
        log.info("feign rule ---> serverName:{}, choose key:{}, final server ip:{}", server.getMetaInfo().getAppName(), key, server.getHostPort());
        return server;
    }

    @Override
    public Server choose(ILoadBalancer lb, Object key) {
        Server chooseServer = super.choose(lb, key);

        List<Server> reachableServers = lb.getReachableServers();
        List<Server> allServers = lb.getAllServers();
        int upCount = reachableServers.size();
        int serverCount = allServers.size();
        log.info("serverName:{} upCount:{}, serverCount:{}", Objects.nonNull(chooseServer) ? chooseServer.getMetaInfo().getAppName() : "", upCount, serverCount);
        for (Server server : allServers) {
            if (server instanceof DiscoveryEnabledServer) {
                DiscoveryEnabledServer dServer = (DiscoveryEnabledServer) server;
                InstanceInfo instanceInfo = dServer.getInstanceInfo();
                if (instanceInfo != null) {
                    InstanceInfo.InstanceStatus status = instanceInfo.getStatus();
                    if (status != null) {
                        log.info("serverName:{} server:{}, status:{}", server.getMetaInfo().getAppName(), server.getHostPort(), status);
                    }
                }
            }
        }

        return chooseServer;
    }
}

3.修改RibbonClients配置

import org.springframework.cloud.netflix.ribbon.RibbonClients;
import org.springframework.context.annotation.Configuration;
/**
 * @description:feign 配置
 */
@Configuration
@RibbonClients(defaultConfiguration = {FeignRule.class})
public class FeignConfig {
}

LoadBalancer实现方案

1. 技术栈

  • Spring Cloud: 2021.0.4
  • Spring Boot: 2.7.17
  • Spring-Cloud-Openfeign: 3.1.4

2. 继承ReactorServiceInstanceLoadBalancer,并实现相关方法

@Slf4j
public class CustomRoundRobinLoadBalancer implements ReactorServiceInstanceLoadBalancer {
    final AtomicInteger position;
    final String serviceId;
    ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider;

    public CustomRoundRobinLoadBalancer(ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider, String serviceId) {
        this(serviceInstanceListSupplierProvider, serviceId, (new Random()).nextInt(1000));
    }

    public CustomRoundRobinLoadBalancer(ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider, String serviceId, int seedPosition) {
        this.serviceId = serviceId;
        this.serviceInstanceListSupplierProvider = serviceInstanceListSupplierProvider;
        this.position = new AtomicInteger(seedPosition);
    }

    public Mono<Response<ServiceInstance>> choose(Request request) {
        ServiceInstanceListSupplier supplier = this.serviceInstanceListSupplierProvider.getIfAvailable(NoopServiceInstanceListSupplier::new);
        return supplier.get(request).next().map((serviceInstances) -> {
            return this.processInstanceResponse(supplier, serviceInstances);
        });
    }

    private Response<ServiceInstance> processInstanceResponse(ServiceInstanceListSupplier supplier, List<ServiceInstance> serviceInstances) {
        Response<ServiceInstance> serviceInstanceResponse = this.getInstanceResponse(serviceInstances);
        if (supplier instanceof SelectedInstanceCallback && serviceInstanceResponse.hasServer()) {
            ((SelectedInstanceCallback)supplier).selectedServiceInstance((ServiceInstance)serviceInstanceResponse.getServer());
        }

        return serviceInstanceResponse;
    }

    private Response<ServiceInstance> getInstanceResponse(List<ServiceInstance> instances) {
        if (instances.isEmpty()) {
            if (log.isWarnEnabled()) {
                log.warn("No servers available for service: " + this.serviceId);
            }

            return new EmptyResponse();
        } else {

            int pos = this.position.incrementAndGet() & Integer.MAX_VALUE;
            ServiceInstance instance = instances.get(pos % instances.size());
            log.info("serverName:{} upCount:{}",instance.getServiceId(),instances.size());
            log.info("feign rule ---> serverName:{}, final server ip:{}:{}", instance.getServiceId(), instance.getHost(),instance.getPort());
            return new DefaultResponse(instance);
        }
    }
}

2.修改LoadBalancerClients配置

@Configuration
@LoadBalancerClients(defaultConfiguration = CustomLoadBalancerConfiguration.class)
public class CustomLoadBalancerConfig {
}

@Configuration
class CustomLoadBalancerConfiguration {
    /**
     * 参考默认实现
     * @see org.springframework.cloud.loadbalancer.annotation.LoadBalancerClientConfiguration#reactorServiceInstanceLoadBalancer
     * @return
     */
    @Bean
    public ReactorLoadBalancer<ServiceInstance> reactorServiceInstanceLoadBalancer(Environment environment, LoadBalancerClientFactory loadBalancerClientFactory) {
        String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
        return new CustomRoundRobinLoadBalancer(loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class), name);
    }
}

以上两部完成大功告成!

源码下载:

https://github.com/dongweizhao/spring-cloud-example/tree/SR6-OpenFeign
https://github.com/dongweizhao/spring-cloud-example/tree/EurekaOpenFeign文章来源地址https://www.toymoban.com/news/detail-748289.html

到了这里,关于解密Spring Cloud微服务调用:如何轻松获取请求目标方的IP和端口的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Spring Cloud之负载均衡与服务调用(Ribbon)

    目录 Ribbon 简介 负载均衡 简介 负载均衡方式 服务端负载均衡 工作原理 特点 客户端负载均衡 工作原理 特点 对比 实现 负载均衡策略 切换负载均衡策略 定制负载均衡策略 超时与重试 单个服务配置 全局配置 服务调用 示例         Ribbon 是 Netflix 公司发布的开源组件,其

    2024年02月08日
    浏览(51)
  • Ribbon:Spring Cloud负载均衡与服务调用组件

    负载均衡? Ribbon实现服务调用? Ribbon实现负载均衡? 切换负载均衡策略? 定制负载均衡策略? 负载均衡 负载均衡(Load Balance),将用户的请求平分到多个服务器上运行,以扩展服务器带宽、增强数据处理能力、增加吞吐量、提高网络的可用性和灵活性的目的。 服务端负载

    2024年02月03日
    浏览(46)
  • 【Spring Cloud】如何使用Feign实现远程调用

    本次示例代码的文件结构如下图所示。 在 order-service 的 pom.xml 文件中导入 Feign 的依赖坐标。 在 order-service 的启动类上添加注解 @EnableFeignClients ,以开启 Feign 功能。 Feign 采用了 Spring MVC 的注解的方式发起远程调用。只需要把发 HTTP 请求的信息声明在一个接口中,并添加注解

    2024年02月13日
    浏览(45)
  • 使用Feign进行微服务之间的接口调用:Spring Cloud Alibaba中的声明式服务调用

            Feign是一个声明式的 HTTP客户端框架 ,用于简化微服务架构中服务之间的通信。它是Spring Cloud框架的一部分,旨在提供一种优雅且易于使用的方式来定义和调用HTTP请求。         Feign的设计目标是让服务之间的通信变得更加简单和直观。通常情况下,在微服务

    2024年02月15日
    浏览(38)
  • Spring Cloud Gateway如何优雅地进行feign调用

    之前写过一篇文章,介绍微服务场景下的权限处理,方案如下: 在实践中,上面的网关选型为Spring Cloud Gateway,所以这里就存在一个问题,即网关如何调用用户服务进行鉴权的问题。 在微服务场景下,服务间的调用可以通过feign的方式,但这里的问题是,网关是reactor模式,即

    2024年02月08日
    浏览(47)
  • Spring Cloud Alibaba全家桶(四)——微服务调用组件Feign

    本文小新为大家带来 微服务调用组件Feign 的相关知识,具体内容包含 什么是Feign , Spring Cloud Alibaba快速整合OpenFeign , Spring Cloud Feign的自定义配置及使用 (包括: 日志配置 、 契约配置 、 自定义拦截器实现认证逻辑 、 超时时间配置 、 客户端组件配置 、 GZIP 压缩配置 )等

    2024年02月19日
    浏览(43)
  • 优化 spring cloud gateway+nacos时服务恢复调用太慢问题

    问题描述 在使用 spring cloud gateway + nacos 做服务发现时,会发现当下游的服务器恢复了,但是还有经过一段时间 gateway 才成功转发请求到刚恢复的下游服务上。于是我就深入源码进行企图通过修改相关配置的方式优化gateway服务发现的恢复时间。 相关依赖版本 源码 经过漫长的

    2024年02月01日
    浏览(57)
  • Spring Cloud OpenFeign:基于Ribbon和Hystrix的声明式服务调用

    💗wei_shuo的个人主页 💫wei_shuo的学习社区 🌐Hello World ! Spring Cloud OpenFeign是一个声明式的服务调用框架,基于Feign并整合了Ribbon和Hystrix;目标是简化分布式系统中编写服务间调用的代码,并提供一种更加优雅和便捷的方式来进行服务之间的通信 依赖导入 application.yml配置 启

    2024年02月05日
    浏览(50)
  • Spring Cloud Day2 Nacos配置管理、Feign远程调用与Gateway服务网关

    Nacos除了可以做注册中心,同样可以做配置管理来使用。 当微服务部署的实例越来越多,达到数十、数百时,逐个修改微服务配置就会让人抓狂,而且很容易出错。我们需要一种统一配置管理方案,可以集中管理所有实例的配置。 Nacos一方面可以将配置集中管理,另一方可以

    2024年02月10日
    浏览(61)
  • Spring Cloud Alibaba【OpenFeign实现服务降级、Dubbo实现服务生产者、 Dubbo消费者调用接口 】(三)

    目录 服务调用_OpenFeign实现服务降级 服务调用_Dubbo实现服务生产者 

    2024年02月17日
    浏览(48)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包