dubbo 负载均衡
在系统中可以启动多个 provider 实例,consumer 发起远程调用时,根据指定的负载均衡算法选择一个 provider。
在本机配置多个 provider,使用不同的端口:
<dubbo:protocol name="dubbo" port="20880"/> <dubbo:protocol name="dubbo" port="20881"/> <dubbo:protocol name="dubbo" port="20882"/>
consumer 配置 loadbalance:
<dubbo:reference id="hello" loadbalance="roundrobin" interface="com.zhang.HelloService" />
dubbo 2.1.2 提供了4种不同的负载均衡算法,在 /META-INF/dubbo/com.alibaba.dubbo.rpc.cluster.LoadBalance 文件中:
adptive=com.alibaba.dubbo.rpc.cluster.loadbalance.LoadBalanceAdptive
random=com.alibaba.dubbo.rpc.cluster.loadbalance.RandomLoadBalance
roundrobin=com.alibaba.dubbo.rpc.cluster.loadbalance.RoundRobinLoadBalance
leastactive=com.alibaba.dubbo.rpc.cluster.loadbalance.LeastActiveLoadBalance
consistenthash=com.alibaba.dubbo.rpc.cluster.loadbalance.ConsistentHashLoadBalance
分别对应随机、轮询、最少活跃、一致性哈希。
随机、轮训都是先考虑权重,如果没有设置权重或者每个 provider 的权重相同,则退化成完全的随机和轮训,最少活跃没看明白。
负载均衡的粒度是单个方法,例: com.zhang.HelloService.sayHello() 有一个负载均衡的 selector。
轮询思想就是:维持一个 map,“接口名 + 方法名”作为建,一个计数器作为值,每次调用接口时,增加计数器然后取模。
public class RoundRobinLoadBalance extends AbstractLoadBalance {
public static final String NAME = "roundrobin";
private final ConcurrentMap<String, AtomicPositiveInteger> sequences = new ConcurrentHashMap<String, AtomicPositiveInteger>();
private final ConcurrentMap<String, AtomicPositiveInteger> weightSequences = new ConcurrentHashMap<String, AtomicPositiveInteger>();
protected <T> Invoker<T> doSelect(List<Invoker<T>> invokers, Invocation invocation) {
String key = invokers.get(0).getUrl().getServiceKey() + "." + invocation.getMethodName();
// 省略权重部分代码
AtomicPositiveInteger sequence = sequences.get(key);
if (sequence == null) {
sequences.putIfAbsent(key, new AtomicPositiveInteger());
sequence = sequences.get(key);
}
// 取模轮循
return invokers.get(sequence.getAndIncrement() % length);
}
}
重点分析下一致性哈希吧,它的思想和jedis如出一辙。假定现在有invoker1,invoker2,invoker3,从invoker1衍生出160个符号,根据这些符号计算哈希值,然后把哈希值和 invoker 作为键值对放到 TreeMap 上。同样操作invoker2和invoker3。在选择invoker时,根据调用参数获取哈希值,然后从TreeMap上搜索对应的键值。
// com.alibaba.dubbo.rpc.cluster.loadbalance.ConsistentHashLoadBalance.ConsistentHashSelector
public ConsistentHashSelector(List<Invoker<T>> invokers, String methodName, int identityHashCode) {
this.virtualInvokers = new TreeMap<Long, Invoker<T>>();
this.identityHashCode = System.identityHashCode(invokers);
URL url = invokers.get(0).getUrl(); // hash.nodes 默认为160,表示1个invoker对应160个符号,或者说160个符号指向这个invoker
this.replicaNumber = url.getMethodParameter(methodName, "hash.nodes", 160);
// hash.arguments 默认为0,默认取调用方法的第1个参数值计算哈希值
String[] index = Constants.COMMA_SPLIT_PATTERN.split(url.getMethodParameter(methodName, "hash.arguments", "0"));
argumentIndex = new int[index.length];
for (int i = 0; i < index.length; i ++) {
argumentIndex[i] = Integer.parseInt(index[i]);
}
for (Invoker<T> invoker : invokers) {
for (int i = 0; i < replicaNumber / 4; i++) {
byte[] digest = md5(invoker.getUrl().toFullString() + i);
for (int h = 0; h < 4; h++) {
long m = hash(digest, h);
// 把键值对挂到TreeMap上
virtualInvokers.put(m, invoker);
}
}
}
} public Invoker<T> select(Invocation invocation) {
//获取参数值
String key = toKey(invocation.getArguments());
//md5计算
byte[] digest = md5(key);
//计算哈希值,从TreeMap上取invoker
Invoker<T> invoker = sekectForKey(hash(digest, 0));
return invoker;
} private String toKey(Object[] args) {
StringBuilder buf = new StringBuilder();
for (int i : argumentIndex) {
if (i >= 0 && i < args.length) {
buf.append(args[i]);
}
}
return buf.toString();
} private Invoker<T> sekectForKey(long hash) {
Invoker<T> invoker;
Long key = hash;
if (!virtualInvokers.containsKey(key)) {
SortedMap<Long, Invoker<T>> tailMap = virtualInvokers.tailMap(key);
if (tailMap.isEmpty()) {
key = virtualInvokers.firstKey();
} else {
key = tailMap.firstKey();
}
}
invoker = virtualInvokers.get(key);
return invoker;
}
假定存在方法:
void com.zhang.HelloService.f1(int userid);
void com.zhang.HelloService.f2(int userid);
void com.zhang.HelloService.f3(int userid, Object param);
如果采用一致性哈希负载均衡,可以肯定的是,f1(10086) 的调用都会被转发到同一个的 provider,那 f1(10086) 和 f2(10086) 是否会转发到同一个 provider 呢?如果希望 f3(10086, param1) 和 f3(10086, param2) 都转发到相同的 provider,应该怎么做?
当然,我们也可以实现 AbstractLoadBalance 接口,使用自定义的负载均衡算法。
如果考虑到 provider 会下线,或者有新的 porvider 上线,则一致性哈希的 virtualInvokers 会重新计算。为什么要使用这种一致性哈希算法?
dubbo 负载均衡的更多相关文章
- Dubbo负载均衡与集群容错机制
1 Dubbo简介 Dubbo是一款高性能.轻量级的开源Java RPC框架,它提供了三大核心能力:面向接口的远程方法调用,智能容错和负载均衡,以及服务自动注册和发现. 作为一个轻量级RPC框架,D ...
- dubbo负载均衡策略和集群容错策略都有哪些
dubbo负载均衡策略 random loadbalance 默认情况下,dubbo是random load balance随机调用实现负载均衡,可以对provider不同实例设置不同的权重,会按照权 ...
- dubbo负载均衡策略和集群容错策略
dubbo负载均衡策略 random loadbalance 默认情况下,dubbo是random load balance随机调用实现负载均衡,可以对provider不同实例设置不同的权重,会按照权 ...
- 一文讲透Dubbo负载均衡之最小活跃数算法
本文是对于Dubbo负载均衡策略之一的最小活跃数算法的详细分析.文中所示源码,没有特别标注的地方均为2.6.0版本. 为什么没有用截止目前的最新的版本号2.7.4.1呢?因为2.6.0这个版本里面有两 ...
- 3.dubbo 负载均衡策略和集群容错策略都有哪些?动态代理策略呢?
作者:中华石杉 面试题 dubbo 负载均衡策略和集群容错策略都有哪些?动态代理策略呢? 面试官心理分析 继续深问吧,这些都是用 dubbo 必须知道的一些东西,你得知道基本原理,知道序列化是什么协议 ...
- 分布式的几件小事(四)dubbo负载均衡策略和集群容错策略
1.dubbo负载均衡策略 ①random loadbalance 策略 默认情况下,dubbo是random loadbalance 随机调用实现负载均衡,可以对provider不同实例设置不同的权 ...
- Dubbo入门到精通学习笔记(十一):Dubbo服务启动依赖检查、Dubbo负载均衡策略、Dubbo线程模型(结合Linux线程数限制配置的实战分享)
文章目录 Dubbo服务启动依赖检查 Dubbo负载均衡策略 Dubbo线程模型(结合Linux线程数限制配置的实战分享) 实战经验分享( ** 属用性能调优**): Dubbo服务启动依赖检查 Du ...
- 面试系列24 dubbo负载均衡策略和集群容错策略
(1)dubbo负载均衡策略 1)random loadbalance 默认情况下,dubbo是random load balance随机调用实现负载均衡,可以对provider不同实例设置不同的权重 ...
- 面试系列16 dubbo负载均衡策略和集群容错策略都有哪些?动态代理策略呢
(1)dubbo负载均衡策略 1)random loadbalance 默认情况下,dubbo是random load balance随机调用实现负载均衡,可以对provider不同实例设置不同的权重 ...
- Dubbo 负载均衡的实现
前言 负载均衡是指在集群中,将多个数据请求分散在不同单元上进行执行,主要为了提高系统容错能力和加强系统对数据的处理能力. 在 Dubbo 中,一次服务的调用就是对所有实体域 Invoker 的一次筛选 ...
随机推荐
- Oracle Single-Row Functions(单行函数)——NULL-Related Functions
参考资料:http://docs.oracle.com/database/122/SQLRF/Functions.htm#SQLRF006 Single-row functions return a ...
- eureka 和zookeeper 区别 优势【转】
作为服务注册中心,Eureka比Zookeeper好在哪里 著名的CAP理论指出,一个分布式系统不可能同时满足C(一致性).A(可用性)和P(分区容错性).由于分区容错性在是分布式系统中必须要保证的, ...
- python 部分函数
abs(number) ,返回数字的绝对值cmath.sqrt(number) ,返回平方根,也可以应用于负数float(object) ,把字符串和数字转换为浮点数help() ,提供交互式帮助in ...
- c代码,输出i,j,k互不相同的三位数
#include <stdio.h> int main() { int i,j,k; printf("\n"); for(i=1;i<5;i++){ for(j= ...
- Selenium 页面自动化测试 面试 问题汇总
1. 专业技术 在学习完Selenium的大部分接口或者方法之后,你可能会去面试自动化测试,主要是Selenium的自动化测试.下面这些问题总结,可能会对你有所帮助. 什么是Selenium? S ...
- c++ cmakelist 详解
基本元素 首先cmaklist必须包括以下几个部分: #工程名 project(study_case) #cmake最低版本需求 cmake_minimum_required(VERSION 2.8. ...
- 【转】Qt鼠标键盘事件
http://blog.csdn.net/lovebird_27/article/details/50351336 Qt 程序需要在main()函数创建一个QCoreApplication对象,然后调 ...
- OpenModelica部分库缺失问题解决
问题:写下面这段代码时,保存时没有出错,但执行时提示找不到initialState这个函数. when time > redTime then state1 := Modelica.Math.R ...
- Vscode中运行js文件或部分代码 ,在下面cmd输出中显示结果
重启 vscode, 这个插件 真好用,, 赞个 ....
- js获取url传递得参数
方法一:正则法 function getQueryString(name) { var reg = new RegExp('(^|&)' + name + '=([^&]*)(& ...