dubbo肥朝系列读书笔记

480 阅读7分钟

第一篇容错架构篇:主要讲几个过程:

  • 1.从directory获取所有的invokers
  • 2.使用route进一步过滤删选出可执行的invokers
  • 3.最终使用负载策略获取最终执行方法的那个invoker

第二篇:directory:主要讲directory的invokers是何时写入?

  • 有个回调notify方法,注册中心变更时候调用,会实时同步更新

第三篇:route:将具体的实现路由策略:

  • 如何实现?怎么写嵌套列表?换行后先空三个,再写+ - *等
    • route.chain方法
invokers = routerChain.route(getConsumerUrl(), invocation);
public List<Invoker<T>> route(URL url, Invocation invocation) {
        List<Invoker<T>> finalInvokers = invokers;
        for (Router router : routers) {
            finalInvokers = router.route(finalInvokers, url, invocation);
        }
        return finalInvokers;
    }
  • 具体route规则看图

第四篇:cluster讲解

  • cluster对用户来讲是个黑盒的概念,里面相当于封装了一堆的invokers,在使用dubbo的时后用户只需要知道有个cluster就可以
  • 这一节主要讲了cluster在dubbo中的九种实现,最需要关注的是缺省的failover实现,失败后快速重试,包含这九种底层实现应该掌握几种主要的

第五篇:loadbalance篇

1.loadbalance顶层接口:select方法和getWeight方法(预热前逐渐降权)

  • getweight:
protected int getWeight(Invoker<?> invoker, Invocation invocation) {
	//获取权重值,默认为100
	int weight = invoker.getUrl().getMethodParameter(invocation.getMethodName(), "weight",100);
	if (weight > 0) {
		//服务提供者启动时间戳
		long timestamp = invoker.getUrl().getParameter("remote.timestamp", 0L);
		if (timestamp > 0L) {
			//当前时间-启动时间=运行时长
			int uptime = (int) (System.currentTimeMillis() - timestamp);
			//获取服务预热时间 默认10分钟 
			int warmup = invoker.getUrl().getParameter("warmup", 600000 );
			//如果服务运行时间小于预热时间,即服务启动未到达10分钟
			if (uptime > 0 && uptime < warmup) {
				//重新计算服务权重
				weight = calculateWarmupWeight(uptime, warmup, weight);
			}
		}
	}
	return weight;
}

当满足程序执行时间小于预热时间的话就重新计算权重,这也就是个降权的过程;

运行时长 公式 权重
1分钟 1/10*100 10
2分钟 2/10*100 20
3分钟 3/10*100 30
5分钟 5/10*100 50
10分钟 10/10*100 100

为什么要这样做? 是为了在服务启动之初不至于承受高负载的压力,进行一段的服务预热,类似的还jvm预热

2.关注算法实现:

a.randomloadbalance(权重随机)

(1).判断是否随机

  for (int i = 1; i < length; i++) {
            int weight = getWeight(invokers.get(i), invocation);
            // save for later use
            weights[i] = weight;
            // Sum
            totalWeight += weight;
            if (sameWeight && weight != firstWeight) {
                sameWeight = false;
            }
        }

(2).执行选择算法,方法比较巧妙

   // If (not every invoker has the same weight & at least one invoker's weight>0), select randomly based on totalWeight.
            int offset = ThreadLocalRandom.current().nextInt(totalWeight);
            // Return a invoker based on the random value.
            for (int i = 0; i < length; i++) {
                offset -= weights[i];
                if (offset < 0) {
                    return invokers.get(i);
                }
            }

重点: 虽然这个随机算法理解起来是比较容易的,面试一般不会问这个,但是假如我们要实现类似的功能,他这个代码实现的思路还是很优雅的,非常具有借鉴意义.他这个实现思路从纯数学角度是很好理解的,我们还是按照上面数学分析中的前提条件.我们知道总权重为10(1+2+3+4),那么怎么做到按权重随机呢?根据10随机出一个整数,假如为随机出来的是2.然后依次和权重相减,比如2(随机数)-1(A的权重) = 1,然后1(上一步计算的结果)-2(B的权重) = -1,此时-1 < 0,那么则调用B,其他的以此类推

b.RoundRobinLoadBalance(轮询)
  • 基础轮询:就是让invokers的每一个依次去执行方法,然后一轮过后执行下一轮,普通轮询适合各个机器性能完全一样,大家随便挨着一个个来 www.baidu.com
  • 关注加权轮询:机器性能不一样,比较差的挨不住那么狠,就得根据性能划分,牛逼的机器多跑,差机器少执行,所以来加权:
protected <T> Invoker<T> doSelect(List<Invoker<T>> invokers, URL url, Invocation invocation) {

	//全限定类型+方法名
	String key = invokers.get(0).getUrl().getServiceKey() + "." + invocation.getMethodName();
	//服务提供者数量
	int length = invokers.size();
	//最大权重
	int maxWeight = 0;
	//最小权重
	int minWeight = Integer.MAX_VALUE;
	final LinkedHashMap<Invoker<T>, IntegerWrapper> invokerToWeightMap = 
				new LinkedHashMap<Invoker<T>, IntegerWrapper>();
	int weightSum = 0;
	//循环主要用于查找最大和最小权重,计算权重总和等
	for (int i = 0; i < length; i++) {
		int weight = getWeight(invokers.get(i), invocation);
		maxWeight = Math.max(maxWeight, weight); // Choose the maximum weight
		minWeight = Math.min(minWeight, weight); // Choose the minimum weight
		if (weight > 0) {
			//将Invoker对象和对应的权重大小IntegerWrapper放入Map中
			invokerToWeightMap.put(invokers.get(i), new IntegerWrapper(weight));
			weightSum += weight;
		}
	}
}
此处参考:https://juejin.cn/post/6844903806841405448

核心就是靠取模执行,代码执行看起来晦涩,参考这位老哥的说法: blog.csdn.net/weixin_3376… 自己跑几下类似代码就能大体看懂了,主要还是借助--让权重小的早早退出后续批次操作,实现权重效果

c.LeastActiveLoadBalance 最少活跃数算法:
  • 算法步骤:
  • 1.初始化最小活跃数-1,最小活跃数下标数组,相同最小活跃数的长度
  • 2.执行循环,找出最小活跃数,下标数组和权重是否相同
  • 3.长度只有一个那么直接调用即可
  • 4.长度不为1看是否所有权重都相同,那么随机一个
  • 5.按照权重系数进行选择,同最初的随机算法一样,用减法来确定分配
  for (int i = 0; i < length; i++) {
            Invoker<T> invoker = invokers.get(i);
            int active = RpcStatus.getStatus(invoker.getUrl(), invocation.getMethodName()).getActive(); // 活跃数
            int weight = invoker.getUrl().getMethodParameter(invocation.getMethodName(), Constants.WEIGHT_KEY, Constants.DEFAULT_WEIGHT); // 权重
            if (leastActive == -1 || active < leastActive) { // 发现更小的活跃数,重新开始
                leastActive = active; // 记录最小活跃数
                leastCount = 1; // 重新统计相同最小活跃数的个数
                leastIndexs[0] = i; // 重新记录最小活跃数下标
                totalWeight = weight; // 重新累计总权重
                firstWeight = weight; // 记录第一个权重
                sameWeight = true; // 还原权重相同标识
            } else if (active == leastActive) { // 累计相同最小的活跃数
                leastIndexs[leastCount++] = i; // 累计相同最小活跃数下标
                totalWeight += weight; // 累计总权重
                // 判断所有权重是否一样
                if (sameWeight && i > 0
                        && weight != firstWeight) {
                    sameWeight = false;
                }
            }
        }
        // assert(leastCount > 0)
        if (leastCount == 1) {
            // 如果只有一个最小则直接返回
            return invokers.get(leastIndexs[0]);
        }
        if (!sameWeight && totalWeight > 0) {
            // 如果权重不相同且权重大于0则按总权重数随机
            int offsetWeight = random.nextInt(totalWeight);
            // 并确定随机值落在哪个片断上
            for (int i = 0; i < leastCount; i++) {
                int leastIndex = leastIndexs[i];
                offsetWeight -= getWeight(invokers.get(leastIndex), invocation);
                if (offsetWeight <= 0)
                    return invokers.get(leastIndex);
            }
        }
        // 如果权重相同或权重为0则均等随机
        return invokers.get(leastIndexs[random.nextInt(leastCount)]);

关于最小活跃数算法:核心就是找到活跃值最小的invokers,给放到数组中,在找寻最小活跃数数组的过程中,也找到了总权重和是否权重都相同及权重数组,根据找到的最小活跃数的数量来执行对应 选择方法,一个就一个,多个再根据是否权重都相同来执行随机方法还是加权随机

敲黑板划重点
活跃数的变化是在com.alibaba.dubbo.rpc.filter.ActiveLimitFilter中,如果没有配置dubbo:reference的actives属性,默认是调用前活跃数+1,调用结束-1,鉴于很多人可能没用过这个属性,所以我把文档截图贴出来

另外如果使用该种负载均衡算法,则dubbo:service中还需要配置filter="activelimit"

d.一致性hash算法
  • 具体一致性算法参考对应文章
  • dubbo默认只对第一个参数进行hash
<dubbo:parameter key="hash.arguments" value="0,1" />
  • 默认160个虚拟节点,修改数量配置即可
<dubbo:parameter key="hash.nodes" value="320" />

关于一致性hash算法三个关键点:原理,down机后影响,虚拟节点

参考:https://juejin.cn/post/6844903806841405448 https://blog.csdn.net/weixin_33767813/article/details/91979961