1. 程式人生 > >Spring Cloud Ribbon 全解 (8)

Spring Cloud Ribbon 全解 (8)

一般SpringCloud環境下是Ribbon+Eureka一起使用的:

SpringCloud環境下Ribbon+Eureka配置

示例專案

新增依賴:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-ribbon</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId
>
<artifactId>spring-cloud-starter-eureka</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.retry</groupId
>
<artifactId>spring-retry</artifactId> </dependency>

新增配置:

spring.application.name=Scanfold-SpringCloud-RibbonWithEureka
server.port=8081

######## ribbon ########
#ribbon連線超時
test-service-provider.ribbon.ConnectTimeout=50
#ribbon讀超時
test-service-provider.ribbon.ReadTimeout
=8000 #最多重試多少臺伺服器 test-service-provider.ribbon.MaxAutoRetriesNextServer=1 #每臺伺服器最多重試次數,但是首次呼叫不包括在內 test-service-provider.ribbon.MaxAutoRetries=1 test-service-provider.ribbon.retryableStatusCodes=500 test-service-provider.ribbon.OkToRetryOnAllOperations=true #服務過期時間配置,超過這個時間沒有接收到心跳EurekaServer就會將這個例項剔除 #注意,EurekaServer一定要設定eureka.server.eviction-interval-timer-in-ms否則這個配置無效,這個配置一般為服務重新整理時間配置的三倍 #預設90s eureka.instance.lease-expiration-duration-in-seconds=15 #服務重新整理時間配置,每隔這個時間會主動心跳一次 #預設30s eureka.instance.lease-renewal-interval-in-seconds=5 #eureka client重新整理本地快取時間 #預設30s eureka.client.registryFetchIntervalSeconds=5 #eureka客戶端ribbon重新整理時間 #預設30s ribbon.ServerListRefreshInterval=1000 eureka.instance.preferIpAddress=true eureka.client.serviceUrl.defaultZone=http://127.0.0.1:8211/eureka/

原始碼分析

類似於純Ribbon的初始化,也是通過Intereceptor初始化Configuration,只不過這次主角是EurekaRibbonClientConfiguration:

@Bean
@ConditionalOnMissingBean
public IPing ribbonPing(IClientConfig config) {
    if (this.propertiesFactory.isSet(IPing.class, this.serviceId)) {
        return (IPing)this.propertiesFactory.get(IPing.class, config, this.serviceId);
    } else {
        NIWSDiscoveryPing ping = new NIWSDiscoveryPing();
        ping.initWithNiwsConfig(config);
        return ping;
    }
}

@Bean
@ConditionalOnMissingBean
public ServerList<?> ribbonServerList(IClientConfig config, Provider<EurekaClient> eurekaClientProvider) {
    if (this.propertiesFactory.isSet(ServerList.class, this.serviceId)) {
        return (ServerList)this.propertiesFactory.get(ServerList.class, config, this.serviceId);
    } else {
        DiscoveryEnabledNIWSServerList discoveryServerList = new DiscoveryEnabledNIWSServerList(config, eurekaClientProvider);
        DomainExtractingServerList serverList = new DomainExtractingServerList(discoveryServerList, config, this.approximateZoneFromHostname);
        return serverList;
    }
}

@Bean
public ServerIntrospector serverIntrospector() {
    return new EurekaServerIntrospector();
}

@PostConstruct
public void preprocess() {
    String zone = ConfigurationManager.getDeploymentContext().getValue(ContextKey.zone);
    if (this.clientConfig != null && StringUtils.isEmpty(zone)) {
        String availabilityZone;
        if (this.approximateZoneFromHostname && this.eurekaConfig != null) {
            availabilityZone = ZoneUtils.extractApproximateZone(this.eurekaConfig.getHostName(false));
            log.debug("Setting Zone To " + availabilityZone);
            ConfigurationManager.getDeploymentContext().setValue(ContextKey.zone, availabilityZone);
        } else {
            availabilityZone = this.eurekaConfig == null ? null : (String)this.eurekaConfig.getMetadataMap().get("zone");
            if (availabilityZone == null) {
                String[] zones = this.clientConfig.getAvailabilityZones(this.clientConfig.getRegion());
                availabilityZone = zones != null && zones.length > 0 ? zones[0] : null;
            }

            if (availabilityZone != null) {
                ConfigurationManager.getDeploymentContext().setValue(ContextKey.zone, availabilityZone);
            }
        }
    }

    RibbonUtils.setRibbonProperty(this.serviceId, CommonClientConfigKey.DeploymentContextBasedVipAddresses.key(), this.serviceId);
    RibbonUtils.setRibbonProperty(this.serviceId, CommonClientConfigKey.EnableZoneAffinity.key(), "true");
}

通過原始碼,可以看出,IPing的預設實現變成了NIWSDiscoveryPing,ServerList的預設實現變成DomainExtractingServerList;

NIWSDiscoveryPing之前的文章裡面我們分析過其原始碼,ServerList的預設實現是基於DiscoveryEnabledNIWSServerList(之前也分析過)外面再包一層DomainExtractingServerList

這個DomainExtractingServerList其實就是在DiscoveryEnabledNIWSServerList返回的Server基礎上封裝了Zone資訊,主要獲取和更新邏輯還是DiscoveryEnabledNIWSServerList

至於呼叫還有重試和之前純Ribbon的邏輯是一樣的,這裡不再贅述