Dubbo的高级特性:服务治理篇
王有志,一个分享硬核Java技术的互金摸鱼侠
加入Java人的提桶跑路群:共同富裕的Java人
上一篇中,我们已经在Spring Boot应用中集成了Dubbo,并注册了一个服务提供方和一个服务使用方。当然,生产环境中应用往往会部署多个节点,以此来保证服务的高可用,那么如何配置Dubbo的负载均衡策略呢?
下面我们以此为切入点,来介绍Dubbo在服务治理方面提供的高级特性的配置与使用。Dubbo默认支持6种配置来源:
JVM System Properties,JVM -D参数
System environment,JVM进程的环境变量
Externalized Configuration,外部化配置,从配置中心读取
Application Configuration,应用的属性配置,从Spring应用的Environment中提取"dubbo"打头的属性集
API//注解等编程接口采集的配置可以被理解成配置来源的一种,是直接面向用户编程的配置采集方式
从classpath读取配置文件 dubbo.properties
在今天的内容中,我们只会涉及到Application Configuration,XML和注解这3种常见的配置方式。
Tips:本篇为基础内容,重点在配置和使用,不涉及任何实现原理和算法原理。
负载均衡
微服务中,负载均衡指的是将请求“合理”的分配在服务的不同节点间,以达到优化使用资源,提供高吞吐量,降低响应时间的目的。Dubbo 3.X中提供了7种负载均衡策略:
| 算法 | 特性 | 配置值 | 默认配置 | 说明 |
|---|---|---|---|---|
| Weighted Random LoadBalance | 加权随机 | random | 是 | 默认算法,默认权重相同 |
| RoundRobin LoadBalance | 加权轮询 | roundrobin | 否 | 借鉴于 Nginx 的平滑加权轮询算法,默认权重相同, |
| LeastActive LoadBalance | 最少活跃优先 + 加权随机 | leastactive | 否 | 背后是能者多劳的思想 |
| Shortest-Response LoadBalance | 最短响应优先 + 加权随机 | shortestresponse | 否 | 更加关注响应速度 |
| ConsistentHash LoadBalance | 一致性哈希 | consistenthash | 否 | 确定的入参,确定的提供者,适用于有状态请求 |
| P2C LoadBalance | Power of Two Choice | p2c | 否 | 随机选择两个节点后,继续选择“连接数”较小的那个节点。 |
| Adaptive LoadBalance | 自适应负载均衡 | adaptive | 否 | 在 P2C 算法基础上,选择二者中 load 最小的那个节点 |
Dubbo支持为服务提供方和服务使用方配置负载均衡策略,当两者都配置了负载均衡策略,以服务使用方的负载均衡策略为准。
首先我们来看XML文件的配置方式,通过XML文件,可以为接口,方法配置负载均衡策略,先为服务提供方的DubboDemoService接口配置负载均衡策略:
<dubbo:service interface="com.wyz.api.DubboDemoService" ref="dubboDemoServiceImpl" loadbalance="roundrobin"/>
接着我们为服务使用方在调用DubboDemoService#say方法时配置负载均很策略:
<dubbo:reference id="DubboDemoService" interface="com.wyz.api.DubboDemoService">
<dubbo:method name="say" loadbalance="roundrobin"/>
</dubbo:reference>
接着我们使用Application文件配置负载均衡策略,通过Application文件,可以配置Dubbo应用的全局负载均衡策略,内容如下:
dubbo:
provider:
loadbalance: roundrobin
consumer:
loadbalance: roundrobin
最后注解的形式配置负载均衡策略,可以为接口和方法配置负载均衡策略配置,代码如下:
@DubboService(loadbalance = "roundrobin")
public class DubboDemoServiceImpl implements DubboDemoService {
@Override
@DubboService(loadbalance = "leastactive")
public String say(String message) {
return "DubboProvider say : " + message;
}
}
集群容错
当配置好负载均衡策略后,程序一直稳定运行。可是突然有一天,集群中的某个节点不可用了,当请求“命中”了不可用的节点后,Dubbo会如何处理呢?
Dubbo提供了集群容错的能力,实现了9中针对集群中节点故障的处理方案:
| 策略 | 配置值 | 默认配置 | 特性 | 应用场景 |
|---|---|---|---|---|
| Failover Cluster | failover | 是 | 失败自动切换,当出现失败,重试其它服务器 | 通常用于读操作,可以配置重试次数 |
| Failfast Cluster | failfast | 否 | 快速失败,失败后立即报错 | 通常用于非幂等写操作 |
| Failsafe Cluster | failsafe | 否 | 失败安全,出现异常时,直接忽略 | 通常用于写入审计日志 |
| Failback Cluster | failback | 否 | 失败自动恢复,后台记录失败请求,定时重发 | 通常用于消息通知 |
| Forking Cluster | forking | 否 | 并行调用多个服务器,只要一个成功即返回 | 通常用于实时性要求较高的读操作 |
| Broadcast Cluster | broadcast | 否 | 广播调用所有提供者,逐个调用,任意一台报错则报错 | 缓存更新 |
| Available Cluster | available | 否 | 调用目前可用的实例(只调用一个),如果当前没有可用的实例,则抛出异常 | 不需要负载均衡的场景 |
| Mergeable Cluster | mergeable | 否 | 将集群中的调用结果聚合起来返回结果,通常和group一起配合使用 | / |
| ZoneAware Cluster | / | 否 | 多注册中心订阅的场景,注册中心集群间的负载均衡 | / |
XML文件的形式依旧提供了接口及接口方法级别的集群容错策略配置:
<dubbo:service interface="com.wyz.api.DubboDemoService" ref="dubboDemoServiceImpl" cluster="failover" retries="2"/>
其中retries是Failover Cluster策略的参数,设定了接口重试的次数(不含正常调用次数),例如,在上述配置中,正常调用失败后,至多会再调用两次。通过XML配置方法级别的集群容错策略与配置负载均衡策略一致,这里就不过多赘述了。
Application文件中可以配置全局的集群容错策略,内容如下:
dubbo:
provider:
cluster: failover
retries: 2
最后是注解配置方式,依旧是通过@DubboService来配置接口和接口方法级别的集群容错策略,代码如下:
@DubboService(cluster = "failover", retries = 2)
public class DubboDemoServiceImpl implements DubboDemoService {
@Override
@DubboService(cluster = "failover", retries = 2)
public String say(String message) {
return "DubboProviderXML say : " + message;
}
}
服务降级
Dubbo自身提供的服务降级功能较为简陋,只提供了mock功能,如果想要体验功能完善的限流熔断等功能,可以使用Sentinel,Hystrix以及Resilience4j等Dubbo支持的专业的技术组件。由于Dubbo的服务降级功能较为简陋,这里只通过3种XML文件的配置方式了解服务降级的功能的配置即可。
配置方式一
<dubbo:service interface="com.wyz.api.DubboDemoService" ref="dubboDemoServiceImpl" mock="true"/>
这种方式的配置中,需要在相同包下有类名 + Mock后缀的实现类,例如:DubboDemoServiceMock。
public class DubboDemoServiceMock implements DubboDemoService {
@Override
public String say(String message) {
return "服务出错了!";
}
}
配置方式二
通过Mock类的全限名配置:
<dubbo:service interface="com.wyz.api.DubboDemoService" ref="dubboDemoServiceImpl" mock="com.wyz.api.DubboDemoServiceMock"/>
配置方式三
使用Dubbo定义的表达式:mock="[fail|force]return|throw xxx"。
[fail|force],默认值fail,表示调用失败后,或不进行方法调用直接强制执行mock方法;return xxx,表示返回指定结果,需要符合接口的返回类型;throw xxx,表示抛出指定异常。
我们举几个例子:
<dubbo:service interface="com.wyz.api.DubboDemoService" ref="dubboDemoServiceImpl" mock="return fail"/>
<dubbo:service interface="com.wyz.api.DubboDemoService" ref="dubboDemoServiceImpl" mock="force:return false"/>
<dubbo:service interface="com.wyz.api.DubboDemoService" ref="dubboDemoServiceImpl" mock="fail:throw java.lang.NullPointException"/>
服务分组
允许通过分组的方式来区分同一个接口的不同实现方式。例如:为DubboXMLService接口添加两个不同的实现DubboXMLServiceImpl和NewDubboXMLServiceImpl。
public interface DubboXMLService {
String say(String message);
}
public class DubboXMLServiceImpl implements DubboXMLService {
@Override
public String say(String message) {
return "DubboProviderXML say : " + message;
}
}
public class NewDubboXMLServiceImpl implements DubboXMLService {
@Override
public String say(String message) {
return "NewDubboProviderXML say : " + message;
}
}
首先是通过XML文件配置服务提供方:
<bean id="dubboXMLServiceImpl" class="com.wyz.service.impl.DubboXMLServiceImpl"/>
<dubbo:service interface="com.wyz.api.DubboXMLService" ref="dubboXMLServiceImpl" group="XML-Provider"/>
<bean id="newDubboXMLServiceImpl" class="com.wyz.service.impl.NewDubboXMLServiceImpl"/>
<dubbo:service interface="com.wyz.api.DubboXMLService" ref="newDubboXMLServiceImpl" group="New-XML-Provider"/>
接着来看服务使用方的配置:
<dubbo:reference id="dubboXMLService" interface="com.wyz.api.DubboXMLService" group="XML-Provider"/>
<dubbo:reference id="newDubboXMLService" interface="com.wyz.api.DubboXMLService" group="New-XML-Provider"/>
使用的话也非常简单,可以直接通过@Autowired方式注入不同分组的服务:
public class DubboConsumerXMLService implements CommandLineRunner {
@Autowired
DubboXMLService dubboXMLService;
@Autowired
DubboXMLService newDubboXMLService;
@Override
public void run(String... args) {
String message = dubboXMLService.say("wyz");
System.out.println(message);
String newMessage = newDubboXMLService.say("wyz");
System.out.println(newMessage);
}
}
再来看如何通过注解的方式进行配置:
@DubboService(group = "Annotation-Provider")
public class DubboAnnotationServiceImpl implements DubboAnnotationService {
@Override
public String say(String message) {
return "DubboProviderAnnotation say : " + message;
}
}
@DubboService(group = "New-Annotation-Provider")
public class NewDubboAnnotationServiceImpl implements DubboAnnotationService {
@Override
public String say(String message) {
return "NewDubboProviderAnnotation say : " + message;
}
}
最后是通过注解使用不同分组的服务,注意这里要使用@DubboReference注入Bean:
@Component
public class DubboConsumerAnnotationService implements CommandLineRunner {
@DubboReference(group = "Annotation-Provider")
DubboAnnotationService dubboAnnotationService;
@DubboReference(group = "New-Annotation-Provider")
DubboAnnotationService newDubboAnnotationService;
@Override
public void run(String... args) {
String message = dubboAnnotationService.say("wyz-Annotation");
System.out.println(message);
String newMessage = newDubboAnnotationService.say("wyz-Annotation");
System.out.println(newMessage);
}
}
Tips:不推荐通过Application文件的方式进行配置。
服务版本
Dubbo中,接口并不能唯一的确定一个服务,只有明确接口+分组+版本号才能唯一的确定一个服务,例如:
<dubbo:service interface="com.wyz.api.DubboXMLService" ref="dubboXMLServiceImpl" group="XML-Provider" version="1.0.0"/>
服务区分版本常见于版本发布验证的场景中,集群中部分节点升级服务,并切换少许流量,验证成功后,再大范围升级节点,可以降低服务升级带来的风险。
服务版本的配置与使用方式与服务分组一样,这里只展示XML文件的配置方式:
<bean id="dubboXMLServiceImpl" class="com.wyz.service.impl.DubboXMLServiceImpl"/>
<dubbo:service interface="com.wyz.api.DubboXMLService" ref="dubboXMLServiceImpl" version="1.0.0"/>
服务使用者的XML文件配置:
<dubbo:reference id="dubboXMLService" interface="com.wyz.api.DubboXMLService" version="1.0.0"/>
XML文件的配置方式可以直接使用@Autowired注入不同版本的服务,我们这里就不赘述了。
今天,我们一起了解并学习了如何配置和使用Dubbo提供的服务治理的能力。
除了上面提到的服务治理能力外,Dubbo还提供了服务路由的能力,Dubbo 2.7之前,可以通过<dubbo:route>标签来配置路由规则,但在Dubbo 2.7之后,官方移除了<dubbo:route>标签,引入了一套依赖于注册中心和配置中心的全新路由配置机制,后面会出一篇番外篇,将注册中心迁移到Nacos上,并学习如何配置路由规则。
如果本文对你有帮助的话,还请多多点赞支持。如果文章中出现任何错误,还请批评指正。最后欢迎大家关注分享硬核技术的金融摸鱼侠王有志,我们下次再见!
Dubbo的高级特性:服务治理篇的更多相关文章
- Dubbo之高级特性
Dubbo 注意当启动服务时,该服务会占用本机一个端口号,故在一台电脑启动多个服务时需要在配置文件中更占用本机的端口号 <!--服务占用本机的端口-当本机启动多个服务时须保持不同--> & ...
- Dubbo高级特性实践-泛化调用
引言 当后端Java服务用Dubbo协议作为RPC方案的基础,但部分消费方是前端Restful的PHP服务,不能直接调用,于是在中间架设了Router服务提供统一的基于HTTP的后端调用入口. 而Ro ...
- Dubbo 高级特性实践-泛化调用
引言 当后端Java服务用Dubbo协议作为RPC方案的基础,但部分消费方是前端Restful的PHP服务,不能直接调用,于是在中间架设了Router服务提供统一的基于HTTP的后端调用入口. 而Ro ...
- 微服务浅谈&服务治理的演变过程
这两天对互联网的架构演变进行了简单了解,并对微服务的出现很感兴趣,所以对相关知识进行了简单的整理与总结. 本篇文章先简单介绍了互联网架构的演变,进而介绍了服务化,最后介绍了微服务及最新的服务网格(Se ...
- 基于Nginx dyups模块的站点动态上下线并实现简单服务治理
简介 今天主要讨论一下,对于分布式服务,站点如何平滑的上下线问题. 分布式服务 在分布式服务下,我们会用nginx做负载均衡, 业务站点访问某服务站点的时候, 统一走nginx, 然后nginx根据一 ...
- 分布式服务治理框架Dubbo的前世今生及应用实战
Dubbo的出现背景 Dubbo从开源到现在,已经出现了接近10年时间,在国内各大企业被广泛应用. 它到底有什么魔力值得大家去追捧呢?本篇文章给大家做一个详细的说明. 大规模服务化对于服务治理的要求 ...
- 分布式服务治理框架dubbo
Dubbo最主要功能有两个 1 RPC调用 2 SOA服务治理方案 Dubbo的架构 Dubbo常见的注册中心有2中,zookeeper以及redis 这篇文章讲解的是采用的zookeeper,要求读 ...
- Dubbo框架中的应用(两)--服务治理
Dubbo服务治理了看法 watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGlzaGVoZQ==/font/5a6L5L2T/fontsize/400/fi ...
- Dubbo框架应用之(二)--服务治理
Dubbo服务治理全貌图 当我们现有ITOO平台系统的业务随着用户的逐渐增大,设计的业务越来越广,系统会异常的复杂,在大规模服务之前,我们可以采用的是RMI或Hessian等工具,暴露和引用远程服务, ...
- Dubbo 服务治理-mock实例
转: Dubbo 服务治理-mock实例 老生住长亭 2017.02.28 10:56* 字数 514 阅读 2552评论 10喜欢 2 Dubbo的mock自己折腾的实例,配置信息有点简陋,有点粗鄙 ...
随机推荐
- 帝国cms将没有搜索到结果的关键字存入到数据库的方法
在帝国cms网站前台搜索一个关键字,如果在网站中查询到了,这个关键字会被记录入搜索关键字表中,但是如果在网站中没有搜索到,就不会记录入搜索关键字表中,那怎么把没有搜索结果的关键字才能记录到数据库中,方 ...
- 探究公众号接口漏洞:从后台登录口到旁站getshell
探究公众号接口漏洞:从后台登录口到旁站getshell 1.入口 发现与利用公众号接口安全漏洞 某120公众号提供了一处考核平台,通过浏览器处打开该网站. 打开可以看到一处密码登录口,试了一下常用的手 ...
- [2]SpinalHDL教程——Scala简单入门
第一个 Scala 程序 shell里面输入 $ scala scala> 1 + 1 res0: Int = 2 scala> println("Hello World!&qu ...
- 3.1 JAVA方法:
JAVA方法: 何为方法 方法是语句的集合,这个集合执行一个功能 方法包含于类或对象中 方法在程序中被创建,在其他地方被引用 java全是值传递 方法的定义和调用 方法的定义: 修饰符 返回类型 方法 ...
- [ Docker ] 部署 nps 和 npc 实现内网穿透
https://www.cnblogs.com/yeungchie/ 云主机上运行 nps 创建映射目录 mkdir -p ~/docker/nps/config 拉取镜像 docker pull o ...
- Java常见的线程池的创建及使用
文章目录 线程池是什么? 线程池的主要参数 线程池的拒绝策略 创建线程池的方式 关闭线程池 大家好,我是Leo!今天准备和大家一起分享的知识是线程池,刚好今天在看八股文,就顺带写一下并把一些实践的例子 ...
- 在nuxt下引入外部js
最近在踩nuxt.js的坑,遇到了许多问题,在这里记录一下,方便以后查阅. 1.如何引入外部js 如果是插件,可以在package.json中写明名字和版本,在nuxt.config.js中注册,然后 ...
- 2022-12-12:有n个城市,城市从0到n-1进行编号。小美最初住在k号城市中 在接下来的m天里,小美每天会收到一个任务 她可以选择完成当天的任务或者放弃该任务 第i天的任务需要在ci号城市完成,
2022-12-12:有n个城市,城市从0到n-1进行编号.小美最初住在k号城市中 在接下来的m天里,小美每天会收到一个任务 她可以选择完成当天的任务或者放弃该任务 第i天的任务需要在ci号城市完成, ...
- 2020-09-13:判断一个正整数是a的b次方,a和b是整数,并且大于等于2,如何求解?
福哥答案2020-09-13: 首先确定b的范围,b的范围一定在[2,logN]里.然后遍历b,求a的范围,如果范围长度等于0,说明这个正整数是a的b次方.1.遍历b范围.二分法求a,a初始范围是[2 ...
- 2022-02-22:机器人大冒险。 力扣团队买了一个可编程机器人,机器人初始位置在原点(0, 0)。小伙伴事先给机器人输入一串指令command,机器人就会无限循环这条指令的步骤进行移动。指令有两种
2022-02-22:机器人大冒险. 力扣团队买了一个可编程机器人,机器人初始位置在原点(0, 0).小伙伴事先给机器人输入一串指令command,机器人就会无限循环这条指令的步骤进行移动.指令有两种 ...