聊聊ribbon的超時時間設置

本文主要研究一下ribbon的超時時間設置java

配置

實例

ribbon:
  ReadTimeout: 10000
  ConnectTimeout: 10000
  MaxAutoRetries: 0
  MaxAutoRetriesNextServer: 1
  eureka:
    enabled: true

RibbonClientConfiguration

spring-cloud-netflix-ribbon-2.0.0.RELEASE-sources.jar!/org/springframework/cloud/netflix/ribbon/RibbonClientConfiguration.javagit

@SuppressWarnings("deprecation")
@Configuration
@EnableConfigurationProperties
//Order is important here, last should be the default, first should be optional
// see https://github.com/spring-cloud/spring-cloud-netflix/issues/2086#issuecomment-316281653
@Import({HttpClientConfiguration.class, OkHttpRibbonConfiguration.class, RestClientRibbonConfiguration.class, HttpClientRibbonConfiguration.class})
public class RibbonClientConfiguration {

	public static final int DEFAULT_CONNECT_TIMEOUT = 1000;
	public static final int DEFAULT_READ_TIMEOUT = 1000;

	@RibbonClientName
	private String name = "client";

	// TODO: maybe re-instate autowired load balancers: identified by name they could be
	// associated with ribbon clients

	@Autowired
	private PropertiesFactory propertiesFactory;

	@Bean
	@ConditionalOnMissingBean
	public IClientConfig ribbonClientConfig() {
		DefaultClientConfigImpl config = new DefaultClientConfigImpl();
		config.loadProperties(this.name);
		config.set(CommonClientConfigKey.ConnectTimeout, DEFAULT_CONNECT_TIMEOUT);
		config.set(CommonClientConfigKey.ReadTimeout, DEFAULT_READ_TIMEOUT);
		return config;
	}

	//......
}
  • 這裏設置默認的超時值,都是1000毫秒,設置在DefaultClientConfigImpl

AbstractLoadBalancingClient

spring-cloud-netflix-ribbon-2.0.0.RELEASE-sources.jar!/org/springframework/cloud/netflix/ribbon/support/AbstractLoadBalancingClient.javagithub

public abstract class AbstractLoadBalancingClient<S extends ContextAwareRequest, T extends IResponse, D> extends
		AbstractLoadBalancerAwareClient<S, T> implements ServiceInstanceChooser {

	protected int connectTimeout;

	protected int readTimeout;

	//......

	@Override
	public void initWithNiwsConfig(IClientConfig clientConfig) {
		super.initWithNiwsConfig(clientConfig);
		RibbonProperties ribbon = RibbonProperties.from(clientConfig);
		this.connectTimeout = ribbon.connectTimeout(DEFAULT_CONNECT_TIMEOUT);
		this.readTimeout = ribbon.readTimeout(DEFAULT_READ_TIMEOUT);
		this.secure = ribbon.isSecure();
		this.followRedirects = ribbon.isFollowRedirects();
		this.okToRetryOnAllOperations = ribbon.isOkToRetryOnAllOperations();
	}

	//......
}
  • 這裏從RibbonProperties讀取超時參數,而後放到類成員變量connectTimeout及readTimeout
  • RibbonProperties就最後是從IClientConfig讀取

RibbonLoadBalancingHttpClient

spring-cloud-netflix-ribbon-2.0.0.RELEASE-sources.jar!/org/springframework/cloud/netflix/ribbon/apache/RibbonLoadBalancingHttpClient.javaspring

// TODO: rename (ie new class that extends this in Dalston) to ApacheHttpLoadBalancingClient
public class RibbonLoadBalancingHttpClient extends
		AbstractLoadBalancingClient<RibbonApacheHttpRequest, RibbonApacheHttpResponse, CloseableHttpClient> {
	//......

	@Override
	public RibbonApacheHttpResponse execute(RibbonApacheHttpRequest request,
											final IClientConfig configOverride) throws Exception {
		IClientConfig config = configOverride != null ? configOverride : this.config;
		RibbonProperties ribbon = RibbonProperties.from(config);
		RequestConfig requestConfig = RequestConfig.custom()
				.setConnectTimeout(ribbon.connectTimeout(this.connectTimeout))
				.setSocketTimeout(ribbon.readTimeout(this.readTimeout))
				.setRedirectsEnabled(ribbon.isFollowRedirects(this.followRedirects))
				.build();

		request = getSecureRequest(request, configOverride);
		final HttpUriRequest httpUriRequest = request.toRequest(requestConfig);
		final HttpResponse httpResponse = this.delegate.execute(httpUriRequest);
		return new RibbonApacheHttpResponse(httpResponse, httpUriRequest.getURI());
	}

	//......
}
  • 這裏execute方法從IClientConfig構造RequestConfig,會設置connectTimeout及socketTimeout
  • 若是configOverride爲null,則使用抽象類的默認配置

OkHttpLoadBalancingClient

spring-cloud-netflix-ribbon-2.0.0.RELEASE-sources.jar!/org/springframework/cloud/netflix/ribbon/okhttp/OkHttpLoadBalancingClient.javaapache

public class OkHttpLoadBalancingClient
		extends AbstractLoadBalancingClient<OkHttpRibbonRequest, OkHttpRibbonResponse, OkHttpClient> {

	//......

	@Override
	public OkHttpRibbonResponse execute(OkHttpRibbonRequest ribbonRequest,
										final IClientConfig configOverride) throws Exception {
		boolean secure = isSecure(configOverride);
		if (secure) {
			final URI secureUri = UriComponentsBuilder.fromUri(ribbonRequest.getUri())
					.scheme("https").build().toUri();
			ribbonRequest = ribbonRequest.withNewUri(secureUri);
		}

		OkHttpClient httpClient = getOkHttpClient(configOverride, secure);
		final Request request = ribbonRequest.toRequest();
		Response response = httpClient.newCall(request).execute();
		return new OkHttpRibbonResponse(response, ribbonRequest.getUri());
	}

	OkHttpClient getOkHttpClient(IClientConfig configOverride, boolean secure) {
		IClientConfig config = configOverride != null ? configOverride : this.config;
		RibbonProperties ribbon = RibbonProperties.from(config);
		OkHttpClient.Builder builder = this.delegate.newBuilder()
				.connectTimeout(ribbon.connectTimeout(this.connectTimeout), TimeUnit.MILLISECONDS)
				.readTimeout(ribbon.readTimeout(this.readTimeout), TimeUnit.MILLISECONDS)
				.followRedirects(ribbon.isFollowRedirects(this.followRedirects));
		if (secure) {
			builder.followSslRedirects(ribbon.isFollowRedirects(this.followRedirects));
		}

		return builder.build();
	}

	//......
}
  • 這裏是經過configOverride或默認的config來構建指定超時參數的OkHttpClient
  • 相比較於apache httpclient經過request config來設置超時時間,OkHttpClient是經過client來設置的,這樣可能存在一個問題,就是OkHttpClient無法用單例,每次都得new一個

clientConfig傳遞

RibbonHttpRequest

spring-cloud-netflix-ribbon-2.0.0.RELEASE-sources.jar!/org/springframework/cloud/netflix/ribbon/RibbonHttpRequest.javasocket

public class RibbonHttpRequest extends AbstractClientHttpRequest {
	//......

	@Override
	protected ClientHttpResponse executeInternal(HttpHeaders headers)
			throws IOException {
		try {
			addHeaders(headers);
			if (outputStream != null) {
				outputStream.close();
				builder.entity(outputStream.toByteArray());
			}
			HttpRequest request = builder.build();
			HttpResponse response = client.executeWithLoadBalancer(request, config);
			return new RibbonHttpResponse(response);
		} catch (Exception e) {
			throw new IOException(e);
		}
	}

	//......
}
  • 這裏client.executeWithLoadBalancer(request, config)使用的是RibbonHttpRequest的config配置

RibbonClientHttpRequestFactory

spring-cloud-netflix-ribbon-2.0.0.RELEASE-sources.jar!/org/springframework/cloud/netflix/ribbon/RibbonClientHttpRequestFactory.javaide

public class RibbonClientHttpRequestFactory implements ClientHttpRequestFactory {

	private final SpringClientFactory clientFactory;

	public RibbonClientHttpRequestFactory(SpringClientFactory clientFactory) {
		this.clientFactory = clientFactory;
	}

	@Override
	@SuppressWarnings("deprecation")
	public ClientHttpRequest createRequest(URI originalUri, HttpMethod httpMethod)
			throws IOException {
		String serviceId = originalUri.getHost();
		if (serviceId == null) {
			throw new IOException(
					"Invalid hostname in the URI [" + originalUri.toASCIIString() + "]");
		}
		IClientConfig clientConfig = this.clientFactory.getClientConfig(serviceId);
		RestClient client = this.clientFactory.getClient(serviceId, RestClient.class);
		HttpRequest.Verb verb = HttpRequest.Verb.valueOf(httpMethod.name());

		return new RibbonHttpRequest(originalUri, verb, client, clientConfig);
	}

}
  • ClientHttpRequest是經過RibbonClientHttpRequestFactory這個工廠建立的
  • clientConfig是RibbonClientHttpRequestFactory這個工廠根據serviceId獲取的,默認是DefaultClientConfigImpl,從配置文件讀取,serviceId本身的個性化配置參數會覆蓋默認值,讀取不到的就是默認的參數。

小結

spring cloud netflix的ribbon,其超時時間配置有ReadTimeout以及ConnectTimeout,分別是設置的socketTimeout以及connectTimeout,建立請求的時候,會讀取指定配置,沒有的話,就取默認的配置,設置超時時間。ui

doc

相關文章
相關標籤/搜索