- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
王有志 ,一个分享硬核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的高级特性:服务治理篇的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
对于相当简单的表结构,即。人员、标准和 PersonCriteria(组合表),我现在设置了一个查询,选择所有符合所有选定条件的人。 此时查询本身看起来像这样: SELECT p.PersonID
我在使用高级 SQL 查询时遇到了一些问题,而且我已经有很长时间没有使用 SQL 数据库了。我们使用 MySQL。 背景: 我们将使用两个表: “交易表” 表:expire_history +----
我找不到错误。也许你可以帮助我:我的代码如下: var data = {"product":[{"config":[{"id":"1","price":"100","sku":"1054879634
我有一个列表列表的列表(最后一个列表并不重要) data = [[[['f', 0], 'C'], [['X', 0], 'X']], [[['s', 1], 'X'], [['X', 0], 'X'
我想准备将使用表格的 session ,并在另一个网站上将新项目添加到 session 中。 默认.cs string[] tab = new string[100];
我知道有一些像: Bubble sort Insertion sort Shell sort Merge sort Heapsort Quicksort Bucket sort Radix sort
像https://softwareengineering.stackexchange.com/questions/150616/return-random-list-item-by-its-weigh
我正在开发一个 posix 脚本 (Linux),它获取一个网页,将内容存储在一个变量中并查找字符串“SUCCESS”。如果找到字符串,则不执行循环内容,如果没有找到字符串,则反复执行循环,直到找到为
我不确定这个问题是否已在其他地方得到解答,而且我似乎无法通过谷歌找到任何不是“Hello World”示例的内容...我正在使用 C# .NET 4.0 进行编码。 我正在尝试开发一个控制台应用程序,
我创建了一个房地产网站,我希望按照列表的最后更新和完整性对列表进行排序。所以我一直想弄清楚如何结合最近更新的列表按mysql中的字段(completion_score)进行排序。完成分数将采用 1
只所以称为“高级”用法,是因为我连switch的最基础的用法都还没有掌握,so,接下来讲的其实还是它的基础用法! switch 语句和具有同样表达式的一系列的 IF 语句相似。很多场合下需要把同一
之前的章节中,我们学习了 XML DOM,并使用了 XML DOM 的 getElementsByTagName() 方法从 XML 文档中取回数据 本章节我们将继续学习其它重要的 XML DOM
我对我尝试编写的 SQL 查询有疑问。 我需要从数据库中查询数据。该数据库除其他外,还包括以下 3 个字段: Account_ID #, Date_Created, Time_Created 我需要编
我正在使用非常激进的视频压缩,例如 -crf 51 .我将其用于“艺术”效果,因此从普通视频压缩的角度来看,我所做的可能没有意义。 到目前为止,我只使用了非常基本的压缩控制,只使用了 -crf。或 -
我真的在学习 lucene 和 ravendb 上的绳索 - 我在 Raven 中有以下文档 - { "InternalEvent": { "Desec": "MachineInfo: 1
通常 grep 命令用于显示包含指定模式的行。有没有办法在包含指定模式的行之前和之后显示 n 行? 这可以使用awk来实现吗? 最佳答案 是的,使用 grep -B num1 -A num2 在匹配之
我搜索了高低,并尝试了几个小时来操纵似乎适合的各种其他查询,但我没有快乐。 我试图加入 Microsoft SQL Server 2005 中的几个表,其中一个示例是: Company Table (
我有一个如下所示的 XML 文件: teacher1Name
我将如何在 CF 中创建此语句? 显然括号不起作用,但说明了我想要完成的工作。这是什么语法? 编辑: 好的,我了解如何使用 EQ 等等。我有点匆忙地发布了这个。我的问题是关于括号。以这种方式使用它们
主要问题:我需要使用具体对象结构对任何对象结构进行类型扩展。 我在 VS Code 中测试的默认值。 我的解决方案: /** @template A @typedef {{[Ki in keyof A
我是一名优秀的程序员,十分优秀!