《Spring Cloud 》Eureka服务调用服务超时重试机制

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了《Spring Cloud 》Eureka服务调用服务超时重试机制相关的知识,希望对你有一定的参考价值。

参考技术A 问题根源有二:
1):业务耗时时间比较长,超过服务调用超时时间配置,由于Spring Cloud 服务调用超时重试机制默认开启,所以会导致服务被调用了两次。
2):服务端未做幂等性,导致重复的业务处理。

增大配置超时时间
ribbon.ReadTimeout=10000
ribbon.ConnectTimeout=10000

eureka服务调用重试开关的配置属性:

默认开启。

重试机制:对于连接超时的异常,feign都会触发重试机制,对于读取超时,会根据请求类型判断,如果是GET异常,触发重试;其他异常,不会触发重试。

服务响应超时时间,默认5s,连接的超时时间为2s。

同一实例最大重试次数为1

负载均衡的其他实例的重试次数为2

对所有操作请求都进行重试,默认false,建议不要开启。

Spring Cloud Eureka服务注册源码分析

Eureka是怎么work的

那eureka client如何将本地服务的注册信息发送到远端的注册服务器eureka server上。通过下面的源码分析,看出Eureka Client的定时任务调用Eureka Server的Reset接口,而Eureka接收到调用请求后会处理服务的注册以及Eureka Server中的数据同步的问题。

服务注册

源码分析,看出服务注册可以认为是Eureka client自己完成,不需要服务本身来关心。

 

Eureka Client的定时任务调用Eureka Server的提供接口

在com.netflix.discovery.DiscoveryClient启动的时候,会初始化一个定时任务,定时的把本地的服务配置信息,即需要注册到远端的服务信息自动刷新到注册服务器上。
首先看一下Eureka的代码,在spring-cloud-netflix-eureka-server工程中可以找到这个依赖eureka-client-1.4.11.jar查看代码可以看到,
com.netflix.discovery.DiscoveryClient.java中的1240行可以看到Initializes all scheduled tasks,在1277行,可以看到InstanceInfoReplicator定时任务

 

在DiscoveryClient中初始化一个InstanceInfoReplicator,其实里面封装了以定时任务。

/**
     * Initializes all scheduled tasks.
     */
    private void initScheduledTasks() {
        if (clientConfig.shouldFetchRegistry()) {
            // registry cache refresh timer
            int registryFetchIntervalSeconds = clientConfig.getRegistryFetchIntervalSeconds();
            int expBackOffBound = clientConfig.getCacheRefreshExecutorExponentialBackOffBound();
            scheduler.schedule(
                    new TimedSupervisorTask(
                            "cacheRefresh",
                            scheduler,
                            cacheRefreshExecutor,
                            registryFetchIntervalSeconds,
                            TimeUnit.SECONDS,
                            expBackOffBound,
                            new CacheRefreshThread()
                    ),
                    registryFetchIntervalSeconds, TimeUnit.SECONDS);
        }
        if (clientConfig.shouldRegisterWithEureka()) {
            int renewalIntervalInSecs = instanceInfo.getLeaseInfo().getRenewalIntervalInSecs();
            int expBackOffBound = clientConfig.getHeartbeatExecutorExponentialBackOffBound();
            logger.info("Starting heartbeat executor: " + "renew interval is: " + renewalIntervalInSecs);
            // Heartbeat timer
            scheduler.schedule(
                    new TimedSupervisorTask(
                            "heartbeat",
                            scheduler,
                            heartbeatExecutor,
                            renewalIntervalInSecs,
                            TimeUnit.SECONDS,
                            expBackOffBound,
                            new HeartbeatThread()
                    ),
                    renewalIntervalInSecs, TimeUnit.SECONDS);
            // InstanceInfo replicator
            /**************************封装了定时任务**********************************/
            instanceInfoReplicator = new InstanceInfoReplicator(
                    this,
                    instanceInfo,
                    clientConfig.getInstanceInfoReplicationIntervalSeconds(),
                    2); // burstSize
            statusChangeListener = new ApplicationInfoManager.StatusChangeListener() {
                @Override
                public String getId() {
                    return "statusChangeListener";
                }
                @Override
                public void notify(StatusChangeEvent statusChangeEvent) {
                    if (InstanceStatus.DOWN == statusChangeEvent.getStatus() ||
                            InstanceStatus.DOWN == statusChangeEvent.getPreviousStatus()) {
                        // log at warn level if DOWN was involved
                        logger.warn("Saw local status change event {}", statusChangeEvent);
                    } else {
                        logger.info("Saw local status change event {}", statusChangeEvent);
                    }
                    instanceInfoReplicator.onDemandUpdate();
                }
            };
            if (clientConfig.shouldOnDemandUpdateStatusChange()) {
                applicationInfoManager.registerStatusChangeListener(statusChangeListener);
            }
            //点击可以查看start方法
            instanceInfoReplicator.start(clientConfig.getInitialInstanceInfoReplicationIntervalSeconds());
        } else {
            logger.info("Not registering with Eureka server per configuration");
        }
    }

 

EurekaHttpClient :提供eureka 的客户端API方法

 



以上是关于《Spring Cloud 》Eureka服务调用服务超时重试机制的主要内容,如果未能解决你的问题,请参考以下文章

服务治理:Spring Cloud Eureka

服务治理:Spring Cloud Eureka

springcloud学习03-spring cloud eureka

Java之 Spring Cloud 微服务 Eureka (第一个阶段)SpringBoot项目实现商品服务器端是调用

spring cloud中微服务之间的调用以及eureka的自我保护机制

Spring Cloud 入门 -- 搭建Eureka注册中心 实现服务者与消费者的服务调用