关键词:负载均衡 轮询算法 随机算法
Dubbo源码版本:
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
<version>2.6.9</version>
</dependency>
负载均衡分为两种模式:客户端模式和服务端模式。客户端模式是服务消费者(调用方)从注册中心获取可用的服务列表,然后根据负载均衡算法选择一个服务进行调用,Dubbo中的负载均衡就是使用的客户端模式。服务端模式,是服务消费者直接调用一个服务,由该服务进行负载均衡,比如Nginx使用的是服务端模式。
一般在集群模式中,服务都是多个的。服务调用方与服务提供方一般都是多对多的关系。当一个服务调用方需要调用一个功能接口时,提供该功能接口的服务是多个,因此需要从这些服务提供者中选择一个服务进行调用。这样的过程就叫负载均衡。
负载均衡是有策略的,也就是从多个服务提供者中如何确定出一个用于本次的服务调用。这个如何确定的过程就是负载均衡策略,也叫负载均衡算法。一般有轮询、随机等。
█ 服务调用
详细的服务调用说明请戳《服务调用-Dubbo篇》
通过上面的内容获取到了服务接口的代理对象,比如有这样一个接口:CatService:
public interface CatService {
void say();
}
生成的代理对象就是这样的(伪代码):
public class CatServiceProxy implements CatService{
@Override
public void say() {
// 逻辑会被转发到MockClusterInvoker的invoke方法中
// invocation里面封装了接口、调用方法等信息
mockClusterWrapper.invoke(invocation);
}
}
MockClusterWrapper.invoke:
public Result invoke(Invocation invocation) throws RpcException {
Result result = null;
// mock功能,服务调用失败后的容错处理
String value = this.directory.getUrl().getMethodParameter(invocation.getMethodName(), "mock", Boolean.FALSE.toString()).trim();
// 使用了mock功能
if (value.length() != 0 && !value.equalsIgnoreCase("false")) {
if (value.startsWith("force")) {
if (logger.isWarnEnabled()) {
logger.info("force-mock: " + invocation.getMethodName() + " force-mock enabled , url : " + this.directory.getUrl());
}
result = this.doMockInvoke(invocation, (RpcException)null);
} else {
try {
result = this.invoker.invoke(invocation);
} catch (RpcException var5) {
if (var5.isBiz()) {
throw var5;
}
if (logger.isWarnEnabled()) {
logger.warn("fail-mock: " + invocation.getMethodName() + " fail-mock enabled , url : " + this.directory.getUrl(), var5);
}
result = this.doMockInvoke(invocation, var5);
}
}
} else {
// 没有使用mock功能,直接调用this.invoker.invoke
result = this.invoker.invoke(invocation);
}
return result;
}
this.invoker.invoke:
MockClusterWrapper中持有的是FailoverClusterInvoker,所以会调用FailoverClusterInvoker中的invoke方法,FailoverClusterInvoker继承了AbstractClusterInvoker,invoke是AbstractClusterInvoker中的方法:
public Result invoke(Invocation invocation) throws RpcException {
......
LoadBalance loadbalance = null;
......
// 获取服务列表
List<Invoker<T>> invokers = this.list(invocation);
// 获取LoadBalance,负载均衡器,可通过配置指定,默认为RandomLoadBalance
if (invokers != null && !invokers.isEmpty()) {
loadbalance = (LoadBalance)ExtensionLoader.getExtensionLoader(LoadBalance.class).getExtension(((Invoker)invokers.get(0)).getUrl().getMethodParameter(RpcUtils.getMethodName(invocation), "loadbalance", "random"));
}
RpcUtils.attachInvocationIdIfAsync(this.getUrl(), invocation);
return this.doInvoke(invocation, invokers, loadbalance);
}
this.doInvoke:
doInvoke是AbstractClusterInvoker定义的抽象方法,具体要看子类实现,进入FailoverClusterInvoker的doInvoke方法: