好几年没有更新博客了,满屋子都是灰尘
只提出最重要的代码 代码里 “// 重点” 的地方
public class RibbonLoadBalancerClient implements LoadBalancerClient {
public <T> T execute(String serviceId, LoadBalancerRequest<T> request, Object hint) throws IOException {
ILoadBalancer loadBalancer = getLoadBalancer(serviceId);
Server server = getServer(loadBalancer, hint); // 重点
if (server == null) {
throw new IllegalStateException("No instances available for " + serviceId);
}
RibbonServer ribbonServer = new RibbonServer(serviceId, server, isSecure(server,
serviceId), serverIntrospector(serviceId).getMetadata(server));
return execute(serviceId, ribbonServer, request);
}
protected Server getServer(ILoadBalancer loadBalancer, Object hint) {
if (loadBalancer == null) {
return null;
}
// Use 'default' on a null hint, or just pass it on?
return loadBalancer.chooseServer(hint != null ? hint : "default"); // 重点
}
}
public class BaseLoadBalancer {
// 轮询负载均衡策略
private final static IRule DEFAULT_RULE = new RoundRobinRule(); // 重点
protected IRule rule = DEFAULT_RULE; // 重点
public Server chooseServer(Object key) {
if (counter == null) {
counter = createCounter();
}
counter.increment();
if (rule == null) {
return null;
} else {
try {
return rule.choose(key); // 重点
} catch (Exception e) {
logger.warn("LoadBalancer [{}]: Error choosing server for key {}", name, key, e);
return null;
}
}
}
}
// Server 元数据
public class Server {
public static final String UNKNOWN_ZONE = "UNKNOWN";
private String host;
private int port = 80;
private String scheme;
private volatile String id;
private volatile boolean isAliveFlag;
private String zone = UNKNOWN_ZONE;
private volatile boolean readyToServe = true;
}
1. 首先从注册中心获取provider的列表
2. 通过一定的策略选择其中一个节点
3. 再返回给restTemplate调用
public class LoadBalancerFeignClient implements Client {
@Override
public Response execute(Request request, Request.Options options) throws IOException {
try {
URI asUri = URI.create(request.url());
String clientName = asUri.getHost();
URI uriWithoutHost = cleanUrl(request.url(), clientName);
FeignLoadBalancer.RibbonRequest ribbonRequest = new FeignLoadBalancer.RibbonRequest(
this.delegate, request, uriWithoutHost);
IClientConfig requestConfig = getClientConfig(options, clientName);
return lbClient(clientName).executeWithLoadBalancer(ribbonRequest,
requestConfig).toResponse();
}
catch (ClientException e) {
IOException io = findIOException(e);
if (io != null) {
throw io;
}
throw new RuntimeException(e);
}
}
}
public static class Options {
private final int connectTimeoutMillis;
private final int readTimeoutMillis;
private final boolean followRedirects;
public Options() {
this(10 * 1000, 60 * 1000);
}
}
eign:
client:
config:
default:
connectTimeout: 2000
readTimeout: 2000
execution.isolation.strategy
THREAD 线程池(默认)
SEMAPHORE 信号量(信号量适用于接口并发量高的情况,如每秒数千次调用的情况,导致的线程开销过高,通常只适用于非网络调用,执行速度快)
execution.isolation.thread.timeoutInMilliseconds
如果使用Hystrix,要设置该时间,该时间要比Ribbon和Feign的优先级高
execution.timeout.enabled
execution.isolation.semaphore.maxConcurrentRequests(隔离策略为 信号量的时候,如果达到最大并发数时,后续请求会被拒绝,默认是10)