接上篇 https://cloud.tencent.com/developer/article/1109591
dubbo 版本2.5.3
通过代码可以看到failback,failover,failsafe,forking,failfast都通过了父类的select方法选择服务提供者(invoker) 这个方法里,也包含有dubbo处理集群的机制,包括使用负载均衡的策略。通知可以看到available和broadcast方案目前没用到负载均衡策略,先看先看select方法
/**
* 使用loadbalance选择invoker.</br>
* a)先lb选择,如果在selected列表中 或者 不可用且做检验时,进入下一步(重选),否则直接返回</br>
* b)重选验证规则:selected > available .保证重选出的结果尽量不在select中,并且是可用的
*
* @param availablecheck 如果设置true,在选择的时候先选invoker.available == true
* @param selected 已选过的invoker.注意:输入保证不重复
*/
protected Invoker<T> select(LoadBalance loadbalance, Invocation invocation, List<Invoker<T>> invokers, List<Invoker<T>> selected) throws RpcException {
if (invokers == null || invokers.size() == 0)
return null;
String methodName = invocation == null ? "" : invocation.getMethodName();
//是否启用sticky 粘性连接,让客户端总是连接同一提供者
boolean sticky = invokers.get(0).getUrl().getMethodParameter(methodName, Constants.CLUSTER_STICKY_KEY, Constants.DEFAULT_CLUSTER_STICKY);
{
//ignore overloaded method
//可选提供者列表已不包含,上次的stickyInvoker,设置为null
if (stickyInvoker != null && !invokers.contains(stickyInvoker)) {
stickyInvoker = null;
}
//ignore cucurrent problem
//stickyInvoker不为null,并且没在已选列表中,返回上次的服务提供者stickyInvoker,但之前强制校验可达性。
//由于stickyInvoker不能包含在selected列表中,通过代码看,可以得知forking和failover集群策略,用不了sticky属性
if (sticky && stickyInvoker != null && (selected == null || !selected.contains(stickyInvoker))) {
if (availablecheck && stickyInvoker.isAvailable()) {
return stickyInvoker;
}
}
}
//利用负载均衡选一个提供者
Invoker<T> invoker = doselect(loadbalance, invocation, invokers, selected);
if (sticky) {
stickyInvoker = invoker;
}
return invoker;
}
这个方法实现里,包含了dubbo的sticky特性的实现,看下doselect方法
private Invoker<T> doselect(LoadBalance loadbalance, Invocation invocation, List<Invoker<T>> invokers, List<Invoker<T>> selected) throws RpcException {
if (invokers == null || invokers.size() == 0)
return null;
//只有一个,不用选了,直接返回
if (invokers.size() == 1)
return invokers.get(0);
//如果只有两个invoker,退化成轮循
if (invokers.size() == 2 && selected != null && selected.size() > 0) {
return selected.get(0) == invokers.get(0) ? invokers.get(1) : invokers.get(0);
}
//大于两个,利用负载均衡选择一个
Invoker<T> invoker = loadbalance.select(invokers, getUrl(), invocation);
//如果选择的提供者,已在selected中包含(优先判断) 或者
// 不可用&&availablecheck=true
// 则重新选择
if ((selected != null && selected.contains(invoker))
|| (!invoker.isAvailable() && getUrl() != null && availablecheck)) {
try {
//重新选择
Invoker<T> rinvoker = reselect(loadbalance, invocation, invokers, selected, availablecheck);
if (rinvoker != null) {
invoker = rinvoker;
} else {
//如果重新选择失败,看下第一次选的位置,如果不是最后,选+1位置.
int index = invokers.indexOf(invoker);
try {
//最后再避免碰撞
invoker = index < invokers.size() - 1 ? invokers.get(index + 1) : invoker;
} catch (Exception e) {
logger.warn(e.getMessage() + " may because invokers list dynamic change, ignore.", e);
}
}
} catch (Throwable t) {
logger.error("clustor relselect fail reason is :" + t.getMessage() + " if can not slove ,you can set cluster.availablecheck=false in url", t);
}
}
return invoker;
}
这个方法里,处理了只有一个或者两个提供者的特殊情况和invoker的重新选择。在看,重选方法:
/**
* 重选,先从非selected的列表中选择,没有在从selected列表中选择.
*
* @param loadbalance
* @param invocation
* @param invokers
* @param selected
* @return
* @throws RpcException
*/
private Invoker<T> reselect(LoadBalance loadbalance, Invocation invocation,
List<Invoker<T>> invokers, List<Invoker<T>> selected, boolean availablecheck)
throws RpcException {
//预先分配一个,这个列表是一定会用到的.
List<Invoker<T>> reselectInvokers = new ArrayList<Invoker<T>>(invokers.size() > 1 ? (invokers.size() - 1) : invokers.size());
//先从非select中选
//把不包含在已选列表中的提供者,放入重选列表reselectInvokers,让负载均衡器选择
if (availablecheck) { //选isAvailable 的非select
for (Invoker<T> invoker : invokers) {
if (invoker.isAvailable()) {
if (selected == null || !selected.contains(invoker)) {
reselectInvokers.add(invoker);
}
}
}
if (reselectInvokers.size() > 0) {
return loadbalance.select(reselectInvokers, getUrl(), invocation);
}
} else { //选全部非select
for (Invoker<T> invoker : invokers) {
if (selected == null || !selected.contains(invoker)) {
reselectInvokers.add(invoker);
}
}
if (reselectInvokers.size() > 0) {
return loadbalance.select(reselectInvokers, getUrl(), invocation);
}
}
//以上都没选择好,最后从select中选可用的.
{
if (selected != null) {
for (Invoker<T> invoker : selected) {
if ((invoker.isAvailable()) //优先选available
&& !reselectInvokers.contains(invoker)) {
reselectInvokers.add(invoker);
}
}
}
if (reselectInvokers.size() > 0) {
return loadbalance.select(reselectInvokers, getUrl(), invocation);
}
}
return null;
}
这个方法,就是实现尽量不从已选列表中选择invoker
dubbo负载均衡 https://cloud.tencent.com/developer/article/1109586