dubbo

news/2024/10/24 0:19:54

一、Dubbo是什么?

Dubbo是一款高性能、轻量级的Java RPC(远程过程调用)框架,主要用于实现服务的分布式调用。由阿里巴巴公司开发并开源。
其核心组件主要包括服务提供者、服务消费者、注册中心、和监控中心。

什么是RPC?

RPC全称为remote procedure call,即远程过程调用。
比如两台服务器A和B,A服务器上部署一个应用,B服务器上部署一个应用,A服务器上的应用想调用B服务器上的应用提供的方法,由于两个应用不在一个内存空间,不能直接调用,所以需要通过网络来表达调用的语义和传达调用的数据。
需要注意的是RPC并不是一个具体的技术,而是指整个网络远程调用过程。
RPC是一个泛化的概念,严格来说一切远程过程调用手段都属于RPC范畴。
各种开发语言都有自己的RPC框架。Java中的RPC框架比较多,广泛使用的有RMI、Hessian、Dubbo等。

二、Dubbo 的架构图解

 节点角色说明:

节点角色名称
Provider 暴露服务的服务提供方
Consumer 调用远程服务的服务消费方
Registry 服务注册与发现的注册中心
Monitor 统计服务的调用次数和调用时间的监控中心
Container 服务运行容器

调用关系说明:

  • 0、服务容器负责启动,加载,运行服务提供者。
  • 1、服务提供者在启动时,向注册中心注册自己提供的服务。
  • 2、服务消费者在启动时,向注册中心订阅自己所需的服务。
  • 3、注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。
  • 4、服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
  • 5、服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。

那么,整个发布-订阅的过程就非常的简单了:

  • 启动容器,加载,运行服务提供者。
  • 服务提供者在启动时,在注册中心发布注册自己提供的服务。
  • 服务消费者在启动时,在注册中心订阅自己所需的服务。

如果考虑失败或变更的情况,就需要考虑下面的过程:

  • 注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。
  • 服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
  • 服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。

三、核心组件

1. 服务提供者(Provider)

  • 1.负责实际提供服务的实现。
  • 2.在服务启动时,将服务接口实现注册到注册中心,以便消费者能够发现并调用该服务。
  • 3.实现业务逻辑,并通过暴露的接口对外提供服务。
  • 4.支持服务的多版本控制,不同版本的服务可以共存。

2. 服务消费者(Consumer)

  • 1.调用远程服务的角色,通过服务接口调用服务提供者的实现。
  • 2.通过注册中心发现服务,并通过Dubbo框架透明地进行远程调用。
  • 3.可以配置负载均衡策略,从多个服务提供者中选择最优的服务实例。
  • 4.支持调用超时、失败重试等机制,增强服务调用的稳定性。

3. 注册中心(Registry)

  • 1.Dubbo分布式系统的核心组件之一,负责管理服务的元数据信息,包括服务的注册和发现。
  • 2.所有的服务提供者在启动时都会将自己注册到注册中心,而服务消费者则从注册中心订阅自己需要的服务。
  • 3.保存服务提供者的元数据信息,如服务接口、地址、版本等。
  • 4.向服务消费者提供动态的服务地址列表,支持服务的动态扩展和缩减。
  • 5.支持服务的健康检查,移除失效的服务实例。
  • 6.注册中心的高可用性对系统的稳定性至关重要,常用的注册中心有ZookeeperNacos等。

4. 监控中心(Monitor)

  • 1.Dubbo分布式系统中的关键组件,用于统计和监控服务的调用情况。
  • 2.收集和记录服务调用的各种数据,如调用次数、调用时间、成功率、失败率等。
  • 3.提供可视化的监控界面,方便运维人员实时查看服务的运行状态和性能指标。
  • 4.支持报警功能,当服务调用出现异常或性能指标达到阈值时,能够自动触发报警通知相关人员。
  • 5.通过监控数据,可以帮助开发者和运维人员及时发现并解决服务调用中的问题,提升系统的稳定性和可靠性。
  • 6.常用的监控中心实现有Dubbo自带的简单监控中心、基于Zookeeper的监控中心等,也可以集成第三方监控工具如Prometheus、Grafana等。

四、其他常用组件

Dubbo框架除了核心组件外,还有其他常用组件:

1. 协议(Protocol)

  • Dubbo进行远程调用的核心,决定了服务之间如何通信。
  • Dubbo支持多种协议,如Dubbo自身的二进制协议、RMI、HTTP等。选择合适的协议可以大大提高服务的性能和兼容性。
  • 协议定义了服务之间的通信方式,包括序列化、反序列化、编码、解码等,确保服务调用的可靠性和高效性。

2. 远程调用(RPC)

  • Dubbo的核心功能之一,负责将服务消费者的调用请求传递给服务提供者。
  • Dubbo提供了一整套机制来处理远程调用的请求和响应,包括序列化、反序列化、网络传输、超时控制、失败重试等。
  • 远程调用过程中,消费者的调用请求会被封装为远程调用请求,并通过网络传输到服务提供者。服务提供者处理请求后,响应会被返回给消费者。

3. 负载均衡(Load Balance)

  • Dubbo中的重要组件,负责在多个服务提供者实例中选择最优的实例来处理请求。
  • Dubbo提供了多种负载均衡策略,如随机策略(Random)、轮询策略(Round Robin)、最少活跃调用数策略(Least Active)、一致性哈希策略(Consistent Hash)等,以应对不同的业务场景。

五、Dubbo 和 Spring Cloud区别

1、通信方式不同:Dubbo 使用的是 RPC 通信,而Spring Cloud 使用的是HTTP RESTFul 方式。

2、组成不一样:

  • dubbo的服务注册中心为Zookeerper,服务监控中心为dubbo-monitor,无消息总线、服务跟踪、批量任务等组件;
  • Spring Cloud的服务注册中心为spring-cloud netflix enruka,服务监控中心为spring-boot admin,有消息总线、数据流、服务跟踪、批量任务等组件;

六、Dubbo入门案例

1 服务端

首先,我们先把服务端的接口写好,因为其实dubbo的作用简单来说就是给消费端提供接口。

接口定义

/*** xml方式服务提供者接口*/
public interface ProviderService {String SayHello(String word);
}

 

这个接口非常简单,只是包含一个 SayHello 的方法。

接着,定义它的实现类

/*** xml方式服务提供者实现类*/
public class ProviderServiceImpl implements ProviderService{public String SayHello(String word) {return word;}
}

 

这样我们就把我们的接口写好了,那么我们应该怎么将我们的服务暴露出去呢?

导入 maven 依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.ouyangsihai</groupId><artifactId>dubbo-provider</artifactId><version>1.0-SNAPSHOT</version><dependencies><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>3.8.1</version><scope>test</scope></dependency><!-- https://mvnrepository.com/artifact/com.alibaba/dubbo --><dependency><groupId>com.alibaba</groupId><artifactId>dubbo</artifactId><version>2.6.6</version></dependency><dependency><groupId>org.apache.zookeeper</groupId><artifactId>zookeeper</artifactId><version>3.4.10</version></dependency><dependency><groupId>com.101tec</groupId><artifactId>zkclient</artifactId><version>0.5</version></dependency><dependency><groupId>io.netty</groupId><artifactId>netty-all</artifactId><version>4.1.32.Final</version></dependency><dependency><groupId>org.apache.curator</groupId><artifactId>curator-framework</artifactId><version>2.8.0</version></dependency><dependency><groupId>org.apache.curator</groupId><artifactId>curator-recipes</artifactId><version>2.8.0</version></dependency></dependencies>
</project>

 

这里使用的dubbo的版本是2.6.6,需要注意的是,如果你只导入dubbo的包的时候是会报错的,找不到nettycurator的依赖,所以,在这里我们需要把这两个的依赖加上,就不会报错了。

另外,这里我们使用 zookeeper 作为注册中心。

到目前为止,dubbo 需要的环境就已经可以了,下面,我们就把上面刚刚定义的接口暴露出去。

暴露接口xml 配置方法)

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"xsi:schemaLocation="http://www.springframework.org/schema/beans        http://www.springframework.org/schema/beans/spring-beans.xsd        http://code.alibabatech.com/schema/dubbo        http://code.alibabatech.com/schema/dubbo/dubbo.xsd"><!--当前项目在整个分布式架构里面的唯一名称,计算依赖关系的标签--><dubbo:application name="provider" owner="sihai"><dubbo:parameter key="qos.enable" value="true"/><dubbo:parameter key="qos.accept.foreign.ip" value="false"/><dubbo:parameter key="qos.port" value="55555"/></dubbo:application><dubbo:monitor protocol="registry"/><!--dubbo这个服务所要暴露的服务地址所对应的注册中心--><!--<dubbo:registry address="N/A"/>--><dubbo:registry address="N/A" /><!--当前服务发布所依赖的协议;webservice、Thrift、Hessain、http--><dubbo:protocol name="dubbo" port="20880"/><!--服务发布的配置,需要暴露的服务接口--><dubbo:serviceinterface="com.sihai.dubbo.provider.service.ProviderService"ref="providerService"/><!--Bean bean定义--><bean id="providerService" class="com.sihai.dubbo.provider.service.ProviderServiceImpl"/></beans>

 

 说明:

1、上面的文件其实就是类似 spring 的配置文件,而且,dubbo 底层就是 spring。
2、节点:dubbo:application
就是整个项目在分布式架构中的唯一名称,可以在name属性中配置,另外还可以配置owner字段,表示属于谁。
下面的参数是可以不配置的,这里配置是因为出现了端口的冲突,所以配置。
3、节点:dubbo:monitor
监控中心配置, 用于配置连接监控中心相关信息,可以不配置,不是必须的参数。
4、节点:dubbo:registry
配置注册中心的信息,比如,这里我们可以配置 zookeeper 作为我们的注册中心。address 是注册中心的地址,这里我们配置的是 N/A 表示由 dubbo 自动分配地址。或者说是一种直连的方式,不通过注册中心。
5、节点:dubbo:protocol
服务发布的时候 dubbo 依赖什么协议,可以配置 dubbo、webservice、http等协议。
6、节点:dubbo:service
这个节点就是我们的重点了,当我们服务发布的时候,我们就是通过这个配置将我们的服务发布出去的。interface 是接口的包路径,ref 是第 ⑦ 点配置的接口的 bean。
7、最后,我们需要像配置spring的接口一样,配置接口的 bean。
到这一步,关于服务端的配置就完成了,下面我们通过 main 方法将接口发布出去。

发布接口

package com.sihai.dubbo.provider;import com.alibaba.dubbo.config.ApplicationConfig;
import com.alibaba.dubbo.config.ProtocolConfig;
import com.alibaba.dubbo.config.RegistryConfig;
import com.alibaba.dubbo.config.ServiceConfig;
import com.alibaba.dubbo.container.Main;
import com.sihai.dubbo.provider.service.ProviderService;
import com.sihai.dubbo.provider.service.ProviderServiceImpl;
import org.springframework.context.support.ClassPathXmlApplicationContext;import java.io.IOException;/*** xml方式启动**/
public class App 
{public static void main( String[] args ) throws IOException {//加载xml配置文件启动ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("META-INF/spring/provider.xml");context.start();System.in.read(); // 按任意键退出
    }
}

 

发布接口非常简单,因为dubbo底层就是依赖 spring 的,所以,我们只需要通过 ClassPathXmlApplicationContext 拿到我们刚刚配置好的 xml ,然后调用 context.start() 方法就启动了。

看到下面的截图,就算是启动成功了,接口也就发布出去了。

 你以为到这里就结束了了,并不是的,我们拿到 dubbo 暴露出去的 url分析分析。

Dubbo 暴露的 URL

dubbo://192.168.234.1:20880/com.sihai.dubbo.provider.service.ProviderService?anyhost=true&application=provider&bean.name=com.sihai.dubbo.provider.service.ProviderService&bind.ip=192.168.234.1&bind.port=20880&dubbo=2.0.2&generic=false&interface=com.sihai.dubbo.provider.service.ProviderService&methods=SayHello&owner=sihai&pid=8412&qos.accept.foreign.ip=false&qos.enable=true&qos.port=55555&side=provider&timestamp=1562077289380

 

分析如下:

1、首先,在形式上我们发现,其实这么牛逼的 dubbo 也是用类似于 http 的协议发布自己的服务的,只是这里我们用的是dubbo协议。
2、dubbo://192.168.234.1:20880/com.sihai.dubbo.provider.service.ProviderService
上面这段链接就是 ? 之前的链接,构成:协议://ip:端口/接口。发现是不是也没有什么神秘的。

3、anyhost=true&application=provider&bean.name=com.sihai.dubbo.provider.service.ProviderService&bind.ip=192.168.234.1&bind.port=20880&dubbo=2.0.2&

generic=false&interface=com.sihai.dubbo.provider.service.ProviderService&methods=SayHello&owner=sihai&pid=8412&qos.

accept.foreign.ip=false&qos.enable=true&qos.port=55555&side=provider&timestamp=1562077289380

?之后的字符串,分析后你发现,这些都是刚刚在provider.xml中配置的字段,然后通过 & 拼接而成的,闻到了 http 的香味了吗?

终于,dubbo 服务端入门了。下面我们看看拿到了 url 后,怎么消费呢?

2 消费端

上面提到,我们在服务端提供的只是点对点的方式提供服务,并没有使用注册中心,所以,下面的配置也是会有一些不一样的。

消费端环境配置

首先,我们在消费端的 resource 下建立配置文件 consumer.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"xsi:schemaLocation="http://www.springframework.org/schema/beans        http://www.springframework.org/schema/beans/spring-beans.xsd        http://code.alibabatech.com/schema/dubbo        http://code.alibabatech.com/schema/dubbo/dubbo.xsd"><!--当前项目在整个分布式架构里面的唯一名称,计算依赖关系的标签--><dubbo:application name="consumer" owner="sihai"/><!--dubbo这个服务所要暴露的服务地址所对应的注册中心--><!--点对点的方式--><dubbo:registry address="N/A" /><!--<dubbo:registry address="zookeeper://localhost:2181" check="false"/>--><!--生成一个远程服务的调用代理--><!--点对点方式--><dubbo:reference id="providerService"
interface="com.sihai.dubbo.provider.service.ProviderService"
url="dubbo://192.168.234.1:20880/com.sihai.dubbo.provider.service.ProviderService"/><!--<dubbo:reference id="providerService"  interface="com.sihai.dubbo.provider.service.ProviderService"/>-->
</beans>

分析如下所示:

1、发现这里的 dubbo:application 和 dubbo:registry 是一致的
2、dubbo:reference :我们这里采用点对点的方式,所以,需要配置在服务端暴露的 url

maven 依赖

和服务端一样

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.ouyangsihai</groupId><artifactId>dubbo-consumer</artifactId><version>1.0-SNAPSHOT</version><dependencies><dependency><groupId>com.ouyangsihai</groupId><artifactId>dubbo-provider</artifactId><version>1.0-SNAPSHOT</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>3.8.1</version><scope>test</scope></dependency><!-- https://mvnrepository.com/artifact/com.alibaba/dubbo --><dependency><groupId>com.alibaba</groupId><artifactId>dubbo</artifactId><version>2.6.6</version></dependency><dependency><groupId>org.apache.zookeeper</groupId><artifactId>zookeeper</artifactId><version>3.4.10</version></dependency><dependency><groupId>com.101tec</groupId><artifactId>zkclient</artifactId><version>0.5</version></dependency><dependency><groupId>io.netty</groupId><artifactId>netty-all</artifactId><version>4.1.32.Final</version></dependency><dependency><groupId>org.apache.curator</groupId><artifactId>curator-framework</artifactId><version>2.8.0</version></dependency><dependency><groupId>org.apache.curator</groupId><artifactId>curator-recipes</artifactId><version>2.8.0</version></dependency></dependencies>
</project>

 

调用服务

package com.sihai.dubbo.consumer;import com.alibaba.dubbo.config.ApplicationConfig;
import com.alibaba.dubbo.config.ReferenceConfig;
import com.alibaba.dubbo.config.RegistryConfig;
import com.sihai.dubbo.provider.service.ProviderService;
import org.springframework.context.support.ClassPathXmlApplicationContext;import java.io.IOException;/*** xml的方式调用**/
public class App 
{public static void main( String[] args ) throws IOException {ClassPathXmlApplicationContext context=new ClassPathXmlApplicationContext("consumer.xml");context.start();ProviderService providerService = (ProviderService) context.getBean("providerService");String str = providerService.SayHello("hello");System.out.println(str);System.in.read();}
}

这里和服务端的发布如出一辙

 如此,我们就成功调用接口了。

七, 加入zookeeper作为注册中心

在前面的案例中,我们没有使用任何的注册中心,而是用一种直连的方式进行的。

但是,实际上很多时候,我们都是使用dubbo + zookeeper的方式,使用 zookeeper 作为注册中心,这里,我们就介绍一下 zookeeper 作为注册中心的使用方法。

这里,我们在前面的入门实例中进行改造。

1 服务端

在服务端中,我们只需要修改 provider.xml 即可。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"xsi:schemaLocation="http://www.springframework.org/schema/beans        http://www.springframework.org/schema/beans/spring-beans.xsd        http://code.alibabatech.com/schema/dubbo        http://code.alibabatech.com/schema/dubbo/dubbo.xsd"><!--当前项目在整个分布式架构里面的唯一名称,计算依赖关系的标签--><dubbo:application name="provider" owner="sihai"><dubbo:parameter key="qos.enable" value="true"/><dubbo:parameter key="qos.accept.foreign.ip" value="false"/><dubbo:parameter key="qos.port" value="55555"/></dubbo:application><dubbo:monitor protocol="registry"/><!--dubbo这个服务所要暴露的服务地址所对应的注册中心--><!--<dubbo:registry address="N/A"/>--><dubbo:registry address="zookeeper://localhost:2181" check="false"/><!--当前服务发布所依赖的协议;webservice、Thrift、Hessain、http--><dubbo:protocol name="dubbo" port="20880"/><!--服务发布的配置,需要暴露的服务接口--><dubbo:serviceinterface="com.sihai.dubbo.provider.service.ProviderService"ref="providerService"/><!--Bean bean定义--><bean id="providerService" class="com.sihai.dubbo.provider.service.ProviderServiceImpl"/></beans>

重点关注这句话

<dubbo:registry address="zookeeper://localhost:2181" />

 

在 address 中,使用我们的 zookeeper 的地址。

如果是zookeeper集群的话,使用下面的方式。

<dubbo:registry protocol="zookeeper" address="192.168.11.129:2181,192.168.11.137:2181,192.168.11.138:2181"/>

服务端的配置就好了,其他的跟 入门案例 一样。

2 消费端

跟服务端一样,在消费端,我们也只需要修改 consumer.xml 即可。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"xsi:schemaLocation="http://www.springframework.org/schema/beans        http://www.springframework.org/schema/beans/spring-beans.xsd        http://code.alibabatech.com/schema/dubbo        http://code.alibabatech.com/schema/dubbo/dubbo.xsd"><!--当前项目在整个分布式架构里面的唯一名称,计算依赖关系的标签--><dubbo:application name="consumer" owner="sihai"/><!--dubbo这个服务所要暴露的服务地址所对应的注册中心--><!--点对点的方式--><!--<dubbo:registry address="N/A" />--><dubbo:registry address="zookeeper://localhost:2181" check="false"/><!--生成一个远程服务的调用代理--><!--点对点方式--><!--<dubbo:reference id="providerService"interface="com.sihai.dubbo.provider.service.ProviderService"url="dubbo://192.168.234.1:20880/com.sihai.dubbo.provider.service.ProviderService"/>--><dubbo:reference id="providerService"interface="com.sihai.dubbo.provider.service.ProviderService"/></beans>

1、注册中心配置跟服务端一样

<dubbo:registry address="zookeeper://localhost:2181"/>

 

2、dubbo:reference

由于我们这里使用 zookeeper 作为注册中心,所以,跟点对点的方式是不一样的,这里不再需要 dubbo 服务端提供的 url 了,只需要直接引用服务端提供的接口即可

<dubbo:reference id="providerService"interface="com.sihai.dubbo.provider.service.ProviderService"/>

好了,消费端也配置好了,这样就可以使用修改的入门案例,重新启动运行了。

 同样成功了。

这时候的区别在于,将 dubbo 发布的url注册到了 zookeeper,消费端从 zookeeper 消费,zookeeper 相当于一个中介,给消费者提供服务。

八, 多种配置方式

在入门实例的时候,我们使用的是 xml 配置的方式,对 dubbo 的环境进行了配置,但是,官方还提供了其他的配置方式,这里我们也一一分解。

API配置方式

这种方式其实官方是不太推荐的,官方推荐使用xml配置的方式,但是,在有的时候测试的时候,还是可以用的到的,另外,为了保证完整性,这些内容还是有必要讲讲的。

首先还是回到服务端工程。

 这里我们使用 api 的方式配置,所以,provider.xml 这个配置文件就暂时不需要了,我们只需要在上面的 AppApi 这个类中的 main 方法中用 api配置及启动即可。

package com.sihai.dubbo.provider;import com.alibaba.dubbo.config.ApplicationConfig;
import com.alibaba.dubbo.config.ProtocolConfig;
import com.alibaba.dubbo.config.RegistryConfig;
import com.alibaba.dubbo.config.ServiceConfig;
import com.sihai.dubbo.provider.service.ProviderService;
import com.sihai.dubbo.provider.service.ProviderServiceImpl;import java.io.IOException;/*** Api方式启动* api的方式调用不需要其他的配置,只需要下面的代码即可。* 但是需要注意,官方建议:* Api方式用于测试用例使用,推荐xml的方式*/
public class AppApi
{public static void main( String[] args ) throws IOException {// 服务实现ProviderService providerService = new ProviderServiceImpl();// 当前应用配置ApplicationConfig application = new ApplicationConfig();application.setName("provider");application.setOwner("sihai");// 连接注册中心配置RegistryConfig registry = new RegistryConfig();registry.setAddress("zookeeper://localhost:2181");
//        registry.setUsername("aaa");
//        registry.setPassword("bbb");// 服务提供者协议配置ProtocolConfig protocol = new ProtocolConfig();protocol.setName("dubbo");protocol.setPort(20880);//protocol.setThreads(200);// 注意:ServiceConfig为重对象,内部封装了与注册中心的连接,//以及开启服务端口// 服务提供者暴露服务配置// 此实例很重,封装了与注册中心的连接,请自行缓存,//否则可能造成内存和连接泄漏ServiceConfig<ProviderService> service = new ServiceConfig<ProviderService>(); service.setApplication(application);// 多个注册中心可以用setRegistries()
        service.setRegistry(registry); // 多个协议可以用setProtocols()
        service.setProtocol(protocol); service.setInterface(ProviderService.class);service.setRef(providerService);service.setVersion("1.0.0");// 暴露及注册服务
        service.export();}
}

 

分析说明如下所示:

看到上面的代码是不是云里雾里,不要慌,我们通过对照 xml 的方式分析一下。

registry 的 xml方式

<dubbo:registry protocol="zookeeper" address="localhost:2181"/>

API 的方式

RegistryConfig registry = new RegistryConfig();
registry.setAddress("zookeeper://localhost:2181");

dubbo:registry节点对应RegistryConfig ,xml 的属性对应 API 方式用 set 方法就可以了。对比之下,你就会发现,如果 API 的方式不熟悉,可以对照 xml 配置方式就可以。

其他 API

org.apache.dubbo.config.ServiceConfig
org.apache.dubbo.config.ReferenceConfig
org.apache.dubbo.config.ProtocolConfig
org.apache.dubbo.config.RegistryConfig
org.apache.dubbo.config.MonitorConfig
org.apache.dubbo.config.ApplicationConfig
org.apache.dubbo.config.ModuleConfig
org.apache.dubbo.config.ProviderConfig
org.apache.dubbo.config.ConsumerConfig
org.apache.dubbo.config.MethodConfig
org.apache.dubbo.config.ArgumentConfig

我们再看看我配置的消费端的Api方式。

消费端

同样,我们不需要 consumer.xml 配置文件了,只需要在 main 方法中启动即可。

 

package com.sihai.dubbo.consumer;import com.alibaba.dubbo.config.ApplicationConfig;
import com.alibaba.dubbo.config.ReferenceConfig;
import com.alibaba.dubbo.config.RegistryConfig;
import com.sihai.dubbo.provider.service.ProviderService;/*** api的方式调用* api的方式调用不需要其他的配置,只需要下面的代码即可。* 但是需要注意,官方建议:* Api方式用于测试用例使用,推荐xml的方式*/
public class AppApi {public static void main(String[] args) {// 当前应用配置ApplicationConfig application = new ApplicationConfig();application.setName("consumer");application.setOwner("sihai");// 连接注册中心配置RegistryConfig registry = new RegistryConfig();registry.setAddress("zookeeper://localhost:2181");// 注意:ReferenceConfig为重对象,内部封装了与注册中心的连接,//以及与服务提供方的连接// 引用远程服务ReferenceConfig<ProviderService> reference = new ReferenceConfig<ProviderService>(); // 此实例很重,封装了与注册中心的连接以及与提供者的连接,请自行缓存,否则可能造成内存和连接泄漏
        reference.setApplication(application);reference.setRegistry(registry); // 多个注册中心可以用setRegistries()reference.setInterface(ProviderService.class);// 和本地bean一样使用xxxServiceProviderService providerService = reference.get(); // 注意:此代理对象内部封装了所有通讯细节,对象较重,请缓存复用providerService.SayHello("hello dubbo! I am sihai!");}
}

 

这部分的 API 配置的方式就到这了,注意:官方推荐 xml 的配置方法

2 注解配置方式

注解配置方式还是需要了解一下的,现在微服务都倾向于这种方式,这也是以后发展的趋势,0 配置应该是这几年的趋势。

那么如何对 dubbo 使用注解的方式呢?我们先看服务端。

服务端

 第一步:定义接口及实现类,在上面的截图中的 annotation 包下

package com.sihai.dubbo.provider.service.annotation;/*** 注解方式接口*/
public interface ProviderServiceAnnotation {String SayHelloAnnotation(String word);
}

 

package com.sihai.dubbo.provider.service.annotation;import com.alibaba.dubbo.config.annotation.Service;/*** 注解方式实现类*/
@Service(timeout = 5000)
public class ProviderServiceImplAnnotation implements ProviderServiceAnnotation{public String SayHelloAnnotation(String word) {return word;}
}

 

@Service

@Service 用来配置 Dubbo 的服务提供方。

第二步:组装服务提供方。

通过 Spring 中 Java Config 的技术(@Configuration)和 annotation 扫描(@EnableDubbo)来发现、组装、并向外提供Dubbo的服务。

package com.sihai.dubbo.provider.configuration;import com.alibaba.dubbo.config.ApplicationConfig;
import com.alibaba.dubbo.config.ProtocolConfig;
import com.alibaba.dubbo.config.ProviderConfig;
import com.alibaba.dubbo.config.RegistryConfig;
import com.alibaba.dubbo.config.spring.context.annotation.EnableDubbo;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;/*** 注解方式配置*/
@Configuration
@EnableDubbo(scanBasePackages = "com.sihai.dubbo.provider.service.annotation")
public class DubboConfiguration {@Bean // #1 服务提供者信息配置public ProviderConfig providerConfig() {ProviderConfig providerConfig = new ProviderConfig();providerConfig.setTimeout(1000);return providerConfig;}@Bean // #2 分布式应用信息配置public ApplicationConfig applicationConfig() {ApplicationConfig applicationConfig = new ApplicationConfig();applicationConfig.setName("dubbo-annotation-provider");return applicationConfig;}@Bean // #3 注册中心信息配置public RegistryConfig registryConfig() {RegistryConfig registryConfig = new RegistryConfig();registryConfig.setProtocol("zookeeper");registryConfig.setAddress("localhost");registryConfig.setPort(2181);return registryConfig;}@Bean // #4 使用协议配置,这里使用 dubbopublic ProtocolConfig protocolConfig() {ProtocolConfig protocolConfig = new ProtocolConfig();protocolConfig.setName("dubbo");protocolConfig.setPort(20880);return protocolConfig;}
}

 

分析说明如下:
1、通过 @EnableDubbo 指定在com.sihai.dubbo.provider.service.annotation 下扫描所有标注有 @Service 的类

这其中就包括了:

ProviderConfig:服务提供方配置
ApplicationConfig:应用配置
RegistryConfig:注册中心配置
ProtocolConfig:协议配置

 

第三步:启动服务

package com.sihai.dubbo.provider;import com.alibaba.dubbo.config.spring.context.annotation.DubboComponentScan;
import com.sihai.dubbo.provider.configuration.DubboConfiguration;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import sun.applet.Main;import java.io.IOException;/*** 注解启动方式*/
public class AppAnnotation {public static void main(String[] args) throws IOException {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(DubboConfiguration.class); context.start();System.in.read(); }
}

 

发现输出下面信息就表示 success 

 消费端

 

同样我们下看看消费端的工程,有一个感性认识。

 第一步:引用服务

package com.sihai.dubbo.consumer.Annotation;import com.alibaba.dubbo.config.annotation.Reference;
import com.sihai.dubbo.provider.service.annotation.ProviderServiceAnnotation;
import org.springframework.stereotype.Component;/*** 注解方式的service*/
@Component("annotatedConsumer")
public class ConsumerAnnotationService {@Referenceprivate ProviderServiceAnnotation providerServiceAnnotation;public String doSayHello(String name) {return providerServiceAnnotation.SayHelloAnnotation(name);}
}

 

ConsumerAnnotationService 类中,通过 @Reference 引用服务端提供的类,然后通过方法调用这个类的方式,给消费端提供接口。

注意:如果这里找不到 ProviderServiceAnnotation 类,请在服务端先把服务端工程用 Maven intall 一下,然后将服务端的依赖放到消费端的 pom 中。如下:

<dependency><groupId>com.ouyangsihai</groupId><artifactId>dubbo-provider</artifactId><version>1.0-SNAPSHOT</version>
</dependency>

 

解释一下:引入的jar包里面只是未被实现的接口,rpc需要在客户端服务端定义一套统一的接口,然后在服务端实现接口,实际上还是网络通信,只不过长得像本地实现

第二步:组装服务消费者

这一步和服务端是类似的,这里就不在重复了。

package com.sihai.dubbo.consumer.configuration;import com.alibaba.dubbo.config.ApplicationConfig;
import com.alibaba.dubbo.config.ConsumerConfig;
import com.alibaba.dubbo.config.RegistryConfig;
import com.alibaba.dubbo.config.spring.context.annotation.EnableDubbo;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;import java.util.HashMap;
import java.util.Map;/*** 注解配置类*/
@Configuration
@EnableDubbo(scanBasePackages = "com.sihai.dubbo.consumer.Annotation")
@ComponentScan(value = {"com.sihai.dubbo.consumer.Annotation"})
public class ConsumerConfiguration {@Bean // 应用配置public ApplicationConfig applicationConfig() {ApplicationConfig applicationConfig = new ApplicationConfig();applicationConfig.setName("dubbo-annotation-consumer");Map<String, String> stringStringMap = new HashMap<String, String>();stringStringMap.put("qos.enable","true");stringStringMap.put("qos.accept.foreign.ip","false");stringStringMap.put("qos.port","33333");applicationConfig.setParameters(stringStringMap);return applicationConfig;}@Bean // 服务消费者配置public ConsumerConfig consumerConfig() {ConsumerConfig consumerConfig = new ConsumerConfig();consumerConfig.setTimeout(3000);return consumerConfig;}@Bean // 配置注册中心public RegistryConfig registryConfig() {RegistryConfig registryConfig = new RegistryConfig();registryConfig.setProtocol("zookeeper");registryConfig.setAddress("localhost");registryConfig.setPort(2181);return registryConfig;}
}

 

第三步:发起远程调用

main方法中通过启动一个 Spring Context,从其中查找到组装好的Dubbo的服务消费者,并发起一次远程调用。

package com.sihai.dubbo.consumer;import com.sihai.dubbo.consumer.Annotation.ConsumerAnnotationService;
import com.sihai.dubbo.consumer.configuration.ConsumerConfiguration;
import com.sihai.dubbo.provider.service.ProviderService;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;import java.io.IOException;/*** 注解方式启动**/
public class AppAnnotation
{public static void main( String[] args ) throws IOException {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ConsumerConfiguration.class); context.start(); // 启动ConsumerAnnotationService consumerAnnotationService = context.getBean(ConsumerAnnotationService.class); String hello = consumerAnnotationService.doSayHello("annotation"); // 调用方法System.out.println("result: " + hello); // 输出结果
}
}

 

结果如下所示:

九, 常用场景

在下面的讲解中,都会是以xml配置的方式来讲解的,这也是dubbo官方比较推荐的方式。以下的操作都是在服务端的 xml 配置文件和消费端的配置文件来讲解的。

1 启动时检查

Dubbo 缺省会在启动时检查依赖的服务是否可用,不可用时会抛出异常,阻止 Spring 初始化完成,以便上线时,能及早发现问题,默认 check="true"

但是,有的时候,我们并不是都需要启动时就检查的,比如测试的时候,我们是需要更快速的启动,所以,这种场景的时候,我们是需要关闭这个功能的。

下面,我们看看如何使用这个功能。

在服务端注册的时候(客户端注册时同样适用);

<dubbo:registry protocol="zookeeper" address="localhost:2181,localhost:2182,localhost:2183" check="false"/>

在客户端引用服务端服务的时候;

<dubbo:reference check="false" id="providerService"interface="com.sihai.dubbo.provider.service.ProviderService"/>

 

2 集群容错

dubbo 也是支持集群容错的,同时也有很多可选的方案,其中,默认的方案是 failover,也就是重试机制。

首先,我们先把所有的容错机制都整理一遍,然后再看看使用。

 使用实例

在发布服务或者引用服务的时候设置

<!--服务发布的配置,需要暴露的服务接口--><dubbo:service cluster="failover" retries="2"interface="com.sihai.dubbo.provider.service.ProviderService"ref="providerService"/>

 

<dubbo:reference cluster="failover" retries="2" check="false" id="providerService"interface="com.sihai.dubbo.provider.service.ProviderService"/>

3 负载均衡

负载均衡想必是一个再熟悉不过的概念了,所以,dubbo 支持也是再正常不过了,这里也总结一下dubbo支持的负载均衡的一些方案及使用方法。

4 直连提供者

在开发及测试环境下,经常需要绕过注册中心,只测试指定服务提供者,所以,这种情况下,我们只需要直接连接服务端的地即可,其实,这种方法在前面的讲解已经使用到了,第一种讲解的方式就是这种方式,因为这种方式简单。

使用方法如下所示:

<dubbo:reference id="providerService"interface="com.sihai.dubbo.provider.service.ProviderService"url="dubbo://192.168.234.1:20880/com.sihai.dubbo.provider.service.ProviderService"/>

 

说明:可以看到,只要在消费端在·dubbo:reference 节点使用url给出服务端的方法即可。

5 只订阅

只订阅就是只能够订阅服务端的服务,而不能够注册。

引用官方的使用场景如下:

  • 为方便开发测试,经常会在线下共用一个所有服务可用的注册中心,这时,如果一个正在开发中的服务提供者注册,可能会影响消费者不能正常运行。
  • 可以让服务提供者开发方,只订阅服务(开发的服务可能依赖其它服务),而不注册正在开发的服务,通过直连测试正在开发的服务。
<dubbo:registry register="false" protocol="zookeeper" address="localhost:2181,localhost:2182,localhost:2183" check="false"/>

 

1、使用只订阅方式
当在服务提供端使用 register="false" 的时候,我们使用下面的方式获取服务端的服务;

<dubbo:reference cluster="failover" retries="2" check="false" id="providerService"interface="com.sihai.dubbo.provider.service.ProviderService"/>

 

发现,这时候并不是向注册中心 zookeeper 注册,而只是做了发布服务和启动netty

2、不使用只订阅方式

<dubbo:registry protocol="zookeeper" address="localhost:2181,localhost:2182,localhost:2183" check="false"/>

 

可以发现,这里就向注册中心 zookeeper 注册了。

6 只注册

只注册正好跟前面的只订阅相反,这个时候可以向注册中心注册,但是,消费端却不能够读到服务。

应用场景

如果有两个镜像环境,两个注册中心,有一个服务只在其中一个注册中心有部署,另一个注册中心还没来得及部署,而两个注册中心的其它应用都需要依赖此服务。这个时候,可以让服务提供者方只注册服务到另一注册中心,而不从另一注册中心订阅服务。

 

使用说明

<dubbo:registry subscribe="false" address="localhost:2181"></dubbo:registry>

 

在服务端的 dubbo:registry 节点下使用 subscribe="false" 来声明这个服务是只注册的服务。

这个时候消费端调用的时候是不能调用的。

7 多协议机制

在前面我们使用的协议都是 dubbo 协议,但是 dubbo 除了支持这种协议外还支持其他的协议,比如,rmi、hessian等,另外,而且还可以用多种协议同时暴露一种服务。

使用方法

1、一种接口使用一种协议

先声明多种协议

 <!--当前服务发布所依赖的协议;webserovice、Thrift、Hessain、http--><dubbo:protocol name="dubbo" port="20880"/><dubbo:protocol name="rmi" port="1099" />

 

然后在发布接口的时候使用具体协议

<!--服务发布的配置,需要暴露的服务接口--><dubbo:service cluster="failover" retries="2"interface="com.sihai.dubbo.provider.service.ProviderService"ref="providerService"/><dubbo:service cluster="failover" retries="2"interface="com.sihai.dubbo.provider.service.ProviderService"ref="providerService" protocol="rmi"/>

在输出日志中,就可以找到rmi发布的接口。

rmi://192.168.234.1:1099/com.sihai.dubbo.provider.service.ProviderService?anyhost=true&application=provider&bean.name=com.sihai.dubbo.provider.service.ProviderService&cluster=failover&dubbo=2.0.2&generic=false&interface=com.sihai.dubbo.provider.service.ProviderService&methods=SayHello&owner=sihai&pid=796&retries=2&side=provider&timestamp=1564281053185, dubbo version: 2.6.6, current host: 192.168.234.1

 

2、一种接口使用多种协议

声明协议和上面的方式一样,在发布接口的时候有一点不一样。

<dubbo:service cluster="failover" retries="2"interface="com.sihai.dubbo.provider.service.ProviderService"ref="providerService" protocol="rmi,dubbo"/>

 

说明:protocol属性,可以用,隔开,使用多种协议。

8 多注册中心

Dubbo 支持同一服务向多注册中心同时注册,或者不同服务分别注册到不同的注册中心上去,甚至可以同时引用注册在不同注册中心上的同名服务。

服务端多注册中心发布服务

一个服务可以在不同的注册中心注册,当一个注册中心出现问题时,可以用其他的注册中心。

注册

<!--多注册中心--><dubbo:registry protocol="zookeeper" id="reg1" timeout="10000" address="localhost:2181"/><dubbo:registry protocol="zookeeper" id="reg2" timeout="10000" address="localhost:2182"/><dubbo:registry protocol="zookeeper" id="reg3" timeout="10000" address="localhost:2183"/>

发布服务

<!--服务发布的配置,需要暴露的服务接口--><dubbo:service cluster="failover" retries="2"interface="com.sihai.dubbo.provider.service.ProviderService"ref="providerService" registry="reg1"/><dubbo:service cluster="failover" retries="2"interface="com.sihai.dubbo.provider.service.ProviderService"ref="providerService" protocol="rmi" registry="reg2"/>

 

说明:使用registry="reg2"指定该接口使用的注册中心,同时也可以使用多个用,隔开,例如,registry="reg1,,reg2"

消费端多注册中心引用服务

首先,先向不同注册中心注册;

<!--多注册中心--><dubbo:registry protocol="zookeeper" id="reg1" timeout="10000" address="localhost:2181"/><dubbo:registry protocol="zookeeper" id="reg2" timeout="10000" address="localhost:2182"/><dubbo:registry protocol="zookeeper" id="reg3" timeout="10000" address="localhost:2183"/>

其次,不同的消费端服务引用使用不同的注册中心;

<!--不同的服务使用不同的注册中心--><dubbo:reference cluster="failover" retries="2" check="false" id="providerService"interface="com.sihai.dubbo.provider.service.ProviderService" registry="reg1"/><dubbo:reference cluster="failover" retries="2" check="false" id="providerService2"interface="com.sihai.dubbo.provider.service.ProviderService" registry="reg2"/>

 

说明:上面分别使用注册中心1和注册中心2

9 多版本

不同的服务是有版本不同的,版本可以更新并且升级,同时,不同的版本之间是不可以调用的。

<!--服务发布的配置,需要暴露的服务接口--><dubbo:service cluster="failover" retries="2"interface="com.sihai.dubbo.provider.service.ProviderService"ref="providerService" registry="reg1" version="1.0.0"/><dubbo:service cluster="failover" retries="2"interface="com.sihai.dubbo.provider.service.ProviderService"ref="providerService" protocol="rmi" registry="reg2" version="1.0.0"/>

加入了版本控制。

10 日志管理

dubbo 也可以将日志信息记录或者保存到文件中的。

1、使用accesslog输出到log4j

<dubbo:protocol accesslog="true" name="dubbo" port="20880"/><dubbo:protocol accesslog="true" name="rmi" port="1099" />

2、输出到文件

<dubbo:protocol accesslog="http://localhost/log.txt" name="dubbo" port="20880"/><dubbo:protocol accesslog="http://localhost/log2.txt" name="rmi" port="1099" />

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.ryyt.cn/news/75285.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈,一经查实,立即删除!

相关文章

牛顿迭代法

$x_{i+1}=x_i-\frac{f(x_i)}{f(x_i)}$1 牛顿迭代法的作用 对于单个方程\(f(x)=0\),通过不断的迭代趋近于某一个单解,最终求出答案。但也有例外,比如出现无理数、无限循环小数等特殊情况,只能趋近,也就是结果是有限的。 2 牛顿迭代法的内容 2.1 怎么迭代 设\(x_1\)为你对\(…

Docker配置Trojan代理

1、遇到的问题 在做云计算作业,使用阿里云的ECS服务器尝试使用docker拉取镜像的时候,发现一直无法从仓库拉取,更换了多个镜像源也没有解决问题,于是决定学会去配置linux的代理,记录过程。 2、安装Trojan何为Trojan? Trojans是一种加密的代理协议,全称为Trojan-GFW,是目…

为什么大部分 PHP 程序员做不了架构师?

架构师一直是 PHP 程序员中梦寐以求的职位,它可望而不可及。我想大部分的 PHP 程序员心中都有一个架构师梦,但是这个梦基本上很难实现,梦终究还是梦,这是多么痛的领悟。大家好,我是码农先森。 架构师一直是 PHP 程序员中梦寐以求的职位,它可望而不可及。我想大部分的 PHP…

10.23每日总结

上次的正课可以说给了我极大的挑战,期中考试的复杂图形化可互动增删改查系统例题我可以说是毫无头绪,而选课系统在多方援助下也算大概完成,数据库、Java语言、编程深入结合,属实是我万万没想到的难度,还需努力,加油!!!

SMMU学习这一篇就够了

前言 最近朋友圈、微信群(ARM-Trustzone-TEE-AT)掀起一阵学习SMMU的热潮,作为一名安全领域的渣渣 ,势必要蹭一蹭这个“热点”,也学习一下吧,反正早晚都要学,因为它和安全的关系还是比较大的。学习是一件长期的过程,本文就先简单理一下概念吧。 1、SMMU总结 1.1、SMMU的ti…

Linux 的系统信息命令

Linux 查看操作系统、内核、服务器架构、CPU、GPU、内存和磁盘信息等命令。Author: ACatSmiling Since: 2024-10-22操作系统信息:方式一:uname -a。uname是 "Unix Name" 的缩写,这个命令主要用于打印与系统相关的信息,-a是 uname 命令的一个选项,这个选项的作用…

一个著名的日志系统是怎么设计出来的

原文:一个著名的日志系统是怎么设计出来的1 前言 Java 帝国在诞生之初就提供了集合、线程、IO、网络等常用功能,从 C 和 C++ 领地那里吸引了大量程序员过来加盟,但是却有意无意地忽略了一个重要的功能:输出日志。 对于这一点,IO 大臣其实非常清楚,日志是个很重要的东西,…

实验三蕉 C语言函数应用编程蕉

实验三蕉 C语言函数应用编程蕉可恶,是原始博士!什么时候!?😖😫额啊,我,我是,呃,香蕉?🤔对,我是香蕉🍌😃香🐵香🐵香🐵香🐵香🐵香🐵🍌蕉🍌蕉🍌蕉🍌蕉🍌蕉🍌蕉香🐵香🐵香🐵香🐵香🐵香🐵🍌蕉🍌蕉🍌蕉🍌蕉🍌蕉�…