feign集成了ribbon,主要是通过ribbon来实现负载均衡
spring初始化默认加载resource下META-INF下spring.factory配置,其中FeignLoadBalancerAutoConfiguration是feign实现负载均衡的核心
HttpClientFeignLoadBalancerConfiguration:ApacheHttpClient请求配置
OkHttpFeignLoadBalancerConfiguration:OkHttpClient网络请求方式
DefaultFeignLoadBalancerConfiguration:默认HttpURLConnection
实现负载均衡的核心:FeignBlockingLoadBalancerClient中的LoadBalancerClient,LoadBalancerClient是调用的ribbon组件,通过ribbon来获取服务列表信息实现负载均衡
/*
* Copyright 2013-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.openfeign.loadbalancer;
import java.io.IOException;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import feign.Client;
import feign.Request;
import feign.Response;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.http.HttpStatus;
import org.springframework.util.Assert;
/**
* A {@link Client} implementation that uses {@link LoadBalancerClient} to select a
* {@link ServiceInstance} to use while resolving the request host.
*
* @author Olga Maciaszek-Sharma
* @since 2.2.0
*/
public class FeignBlockingLoadBalancerClient implements Client {
private static final Log LOG = LogFactory
.getLog(FeignBlockingLoadBalancerClient.class);
/**
* 网络请求方式
*/
private final Client delegate;
/**
* 获取的ribbon服务
*/
private final LoadBalancerClient loadBalancerClient;
public FeignBlockingLoadBalancerClient(Client delegate,
LoadBalancerClient loadBalancerClient) {
this.delegate = delegate;
this.loadBalancerClient = loadBalancerClient;
}
/**
* 发起网络调用
* @param request
* @param options
* @return
* @throws IOException
*/
@Override
public Response execute(Request request, Request.Options options) throws IOException {
final URI originalUri = URI.create(request.url());
String serviceId = originalUri.getHost();
Assert.state(serviceId != null,
"Request URI does not contain a valid hostname: " + originalUri);
ServiceInstance instance = loadBalancerClient.choose(serviceId);
if (instance == null) {
String message = "Load balancer does not contain an instance for the service "
+ serviceId;
if (LOG.isWarnEnabled()) {
LOG.warn(message);
}
return Response.builder().request(request)
.status(HttpStatus.SERVICE_UNAVAILABLE.value())
.body(message, StandardCharsets.UTF_8).build();
}
String reconstructedUrl = loadBalancerClient.reconstructURI(instance, originalUri)
.toString();
Request newRequest = Request.create(request.httpMethod(), reconstructedUrl,
request.headers(), request.body(), request.charset(),
request.requestTemplate());
return delegate.execute(newRequest, options);
}
// Visible for Sleuth instrumentation
public Client getDelegate() {
return delegate;
}
}
通过RetryableFeignLoadBalancer类来选择服务
通过调用ribbon选择服务
选择服务
负载均衡默认是轮询方案
ribbon选择服务的方式
AvailabilityFilteringRule:在RoundRibbon的基础上,选择满足条件的服务,如果10次了还没得到,则在满足条件的服务列表中,再用RoundRibbon算法选择.
BestAvailableRule:选择最小请求数
ClientConfigEnabledRoundRobinRule:轮询
RandomRule:随机选择一个server
RetryRule:根据轮询的方式重试
RoundRobinRule:轮询选择server
ZoneAvoidanceRule:根据server的zone区域和可用性来轮询选择
WeightedResponseTimeRule:根据响应时间去分配一个weight(权重),权重越低,被选择的可能性越低