1.dubbo多协议支持
某些场景下,可能接口是使用的老的协议去发布的,此时希望接口能够以一种新的协议去发布,老的服务按照老的协议去调用,新的服务按照新的协议去调用 而dubbo服务就可以支持发布多种协议,如 dubbo / hessian / thrift / grps http2.0/ protobuff, rest 等,如果要切换某种协议,只需要添加该协议对应的依赖包即可
以rest协议为例,它是基于JAX-RS 来实现的,dubbo发布rest服务是基于 RESTEasy的,同时需要容器的支持, 先修改 配置文件,指定服务发布的协议:
然后在服务实现类上面指定发布的协议:
@DubboService(registry = {“shanghai”, “nanjing”}, protocol = {“dubbo”,“rest”}) 注解中配置protocol = {“dubbo”,“rest”} , 那么SayHelloServiceImpl 这个类会发布基于dubbo协议和rest协议的服务,既可以通过dubbo协议来访问服务,也可以通过rest协议来访问服务,但是rest协议还需要额外加个配置:
(1) pom依赖
<!-- 基于resteasy -->
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jaxrs</artifactId>
<version>3.13.0.Final</version>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-client</artifactId>
<version>3.13.0.Final</version>
</dependency>
<!-- jetty依赖,须注意与dubbo版本兼容问题-->
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<version>9.4.19.v20190610</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-servlet</artifactId>
<version>9.4.19.v20190610</version>
</dependency>
添加jetty容器,注意与dubbo版本的兼容关系
通过HTTP协议发布rest风格的服务:
启动注册中心(这里用zookeeper)和provider服务,这样就可以通过浏览器去访问这个rest协议的接口了:http://localhost:8888/say
服务的消费方也可以指定使用dubbo协议来进行消费:
启动消费方服务进行调用:
provider端消息打印:
2.Dubbo负载均衡
从dubbo架构图中可以看到,provider如果有多个的话,consumer调用provider时必然会涉及到负载均衡,dubbo已经默认配置了负载均衡策略,即使不配置,也会有默认的的负载均衡,从dubbo源码中可以看到dubbo可以支持如下5种负载均衡算法:
加权随机负载均衡(默认的负载均衡算法);
加权轮询负载均衡—— 根据权重大小生成区间,然后生成一个随机数,根据随机数所落的区间来决定哪个服务器来处理请求
一致性hash算法—— 解决数据分片场景下,增加/减少节点后hash计算带来的数据迁移的问题(本质是数据读取不到,假设存入时hash%服务器数量后数据存到了第一台服务器,这时扩容了,要去查询这个数据,再次用相同参数对服务器数量进行hash取模运算,得到的服务器可能就不是当初存储数据的那台服务器了) ,dubbo的一致性hash算法默认根据第一个参数进行取模
一致性hash算法详细介绍: https://www.cnblogs.com/myseries/p/10956835.html
配置负载均衡算法:
如果负载均衡算法配置的是一致性hash算法,针对请求参数相同的请求,会落到同一台服务器上。
负载均衡算法名字如果不知道的话,可以去具体的负载均衡算法类里面找:
3.集群容错
容忍错误的能力(出现错误之后怎么去处理)
分布式集群下,客户端请求会存在三态问题:成功/失败/未知
- failover cluster(默认)
失败自动重试(重试其他服务器)—— 失败自动切换
@DubboService(cluster = “failover”, retries = 2, registry = {“shanghai”, “nanjing”}, version = “2.0”)
这种场景下,如果时事务型操作,需要保证幂等,多次重试的结果相同 并且最终成功 - failfast cluster
快速失败 ,如果插入数据失败,立即报错,适用于不需要幂等的场景 - failsafe cluster
失败安全,出现异常时直接将异常吞掉。 - failback cluster
失败自动恢复 :记录失败请求,定时重发,保证最终一致 - forking cluster
并行调用多个服务节点,只要其中一个节点成功返回,就直接用这个节点的结果进行返回 - broadcast cluster
广播调用,一个请求调用所有的服务提供者,只要其中一个节点报错,则认为这个请求失败;
比如更新服务器上的缓存等操作
4.Dubbo泛化
dubbo泛化解决的问题:针对跨语言调用dubbo服务的场景下,服务的消费端没有公共契约(api服务)时,如何去调用dubbo服务;
这种场景下,接口定义直接写在服务提供端(而不是api服务中),服务的消费端
消费方泛化调用:
启动nacos注册中心,访问 demo接口:
代码:https://gitee.com/liuch890228/dubbo-learn/tree/dubbo-protocol-rest
5.服务降级
dubbo的服务降级很容易实现,只需要在DubboReference注解中加一个mock属性,值为新增的服务降级处理类的全路径名
启动nacos注册中心和provider,consumer测试:
演示代码:https://gitee.com/liuch890228/dubbo-learn/tree/dubbo-fallback
6.Dubbo常用配置
- 启动检查
解决服务之间相互依赖时,被依赖的服务未启动导致当前服务无法启动的问题
(1)对消费端服务
如上,DubboReference注解配置check=true则表示开启启动检查,此时provider未启动,则会启动失败,如果改为false则能够正常启动(consumer中所有使用 @DubboReference注解的地方 都需要加)
(2)针对注册中心不可用的场景,配置dubbo.registry.check=false 则是 关闭注册中心启动时检查。
更多启动检查配置,参考: dubbo启动检查 - 主机绑定
源码:org.apache.dubbo.config.ServiceConfig#findConfigedHosts
(1)查找环境变量中是否存在启动参数 DUBBO_IP_TO_BIND,(-d DUBBO_IP_TO_BIND=xx )如果存在则取这个值作为服务注册的ip
(2)读取配置文件dubbo.protocols.dubbo.host 作为服务注册的ip
(3)hostToBind = InetAddress.getLocalHost().getHostAddress(); 获取本机IP地址作为服务注册的ip
(4)如果(3)中 获取的ip不合法,则通过socket去连接注册中心获取本机IP:
(5)轮询本机网卡,找到合适的IP
上面获取到的ip是bindIP, 如果需要作为服务注册中心的ip,还会读取环境变量 DUBBO_IP_TO_REGISTRY的值,如果这个值没配置,才会将绑定ip作为注册中心的ip
- 配置优先级
方法级别的配置> 接口级别的配置
客户端没配置,服务提供端为准
客户端和服务端都配置,以客户端为准
配置加载优先级:环境变量 外部配置(application.properties) API 本地文件(dubbo.properties)