《面向服务的软件系统》实验二:Dubbo环境搭建与服务部署

《面向服务的软件系统》实验报告

——实验二:Dubbo环境搭建与服务部署

姓名: 石卓凡 学号: 120L021011

Dubbo框架与Zookeeper框架之间的关系是什么?如何将Zookeeper框架与Dubbo框架进行集成?

关系:

关系概括:Dubbo框架中需要的服务注册中心可以由zookeeper来完成

为了解决微服务遇到的各种问题,产生主流微服务框架Dubbo和Spring Cloud,比如说dubbo是一个远程调用服务的分布式框架,可以实现远程通讯、动态配置、地址路由等等功能

功能 Dubbo SpringCloud
服务注册中心 Zookeeper Eureka(主流)、Consul、zookeeper
服务调用方式 RPC基于Dubbo协议 REST API 基于Http协议
服务监控 Dubbo-Monitor Spring Boot Admin

关于dubbo的众多功能中的服务注册中心功能,Dubbo目前支持4种注册中心,其中包括Zookeeper注册中心,并且Dubbo建议使用Zookeeper作为服务的注册中心,实现服务注册和发现

Dubbo使用zookeeper具体来说:

dubbo有很多服务的提供者和消费者,提供者和消费者需要一个管理中心来管理,这个时候用zookeeper来管理

如果没有zookeeper作为注册中心,具体流程如下图:

图1.1

Provider 暴露服务的服务提供方
Consumer 调用远程服务的服务消费方

如果使用zookeeper作为注册中心,具体流程

  1. 服务容器负责启动加载,运行Provider。
  2. Provider在启动时,向注册中心注册自己提供的服务。
  3. Consumer在启动时,向注册中心订阅自己所需的服务。
  4. 注册中心返回Provider地址列表给Consumer,如果有变更,注册中心将基于长连接推送变更数据给Consumer。
  5. Consumer,从Provider地址列表中,基于软负载均衡算法,选一台Provider进行调用,如果调用失败,再选另一台调用。

如下图:

图1.2

Provider 暴露服务的服务提供方
Consumer 调用远程服务的服务消费方
Zookeeper 注册中心

集成过程:

  1. 下载zookeeper并且解压

    图1.3

    目录中创建 data、logs 两个目录作为 zookeeper的数据文件夹和日志文件夹

    图1.4

  2. 下载dubbo-master,使用 maven 命令“mvn install -Dmaven.test.skip=true”编译 dubbo-master 项目,使得每一个模块都可以在target文件夹下获取war文件

    图1.5

  3. 将对应的.war文件放入tomcat的webapps文件夹对应位置

    1. 编辑 D:\apache-tomcat-7.0.91\conf\server.xml,在<Host>节点下添加节点 <Context docBase=”D:/dubbox-master/dubbo-admin/target/dubboadmin-2.8.4” path=”” reloadable=”false”/>

      图1.6

    2. 重新启动tomcat,等待tomcat的重新执行,此时就可以允许tomcat可以处理dubbo并且发布

  4. 在对应的provider和consumer的xml配置文件中找到dubbo:regegisry标签,将address属性设置为想要设定的注册中心地址

<dubbo:registry address=”zookeeper://127.0.0.1:2181”/>

  1. 启动zookeeper,tomcat,可以直接访问dubbo 内置管理界面

集成完毕

Dubbo框架中的Dubbo-master的作用是什么?

Dubbo-master的主要作用是,作为dubbo的稳定版本,里面封装了dubbo的文件内容,可以做到mvn编译之后即可开箱即用,供客户简单方便将dubbo与tomcat或者spring集成使用

Dubbo-master是dubbo在git仓库中的master分支的内容,一般是目前的最稳定的代码版本,master为主分支,也是用于部署生产环境的分支。

其他分支比如dubbo-2.4.11-dev则是dubbo的2.4.11的dev版本

Dubbo-master内容,包含了以下几个模块

公共逻辑模块 dubbo-common 包括Util类和通用模型
远程通信模块 dubbo-remoting 相当于dubbo协议的实现,如果RPC使用RRRMI协议则不需要使用此包
远程调用模块 dubbo-rpc 抽象各种协议,以及动态代理,包含一对一的调用,不关心集群的原理。
集群模块 dubbo-cluster 将多个服务提供方伪装成一个提供方,包括负载均衡,容错,路由等,集群的地址列表可以是静态配置的,也可以是注册中心下发的.
注册中心模块 dubbo-registry 基于注册中心下发的集群方式,以及对各种注册中心的抽象
监控模块 dubbo-monitor 统计服务调用次数,调用时间,调用链跟踪的服务
配置模块 dubbo-config 是dubbo对外的api,用户通过config使用dubbo,隐藏dubbo所有细节
容器模块 dubbo-container 是一个standlone的容器,以简单的main加载spring启动,因为服务通常不需要Tomcat/Jboss等web容器的特性,没必要用web容器去加载服务.

Dubbo框架下Service Provider发布服务的过程,及过程中的关键点。

Provider:

服务提供者,在注册中心注册作为服务提供的一方,发布服务到服务注册中心。本次实验provider模块作为提供者

发布服务过程:

  1. 服务容器负责启动加载,运行Provider。

    BootStrap中的ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(“META-INF/spring/provider.xml”);
    ctx.start();

    启动了spring的IOC容器,准备读取”META-INF/spring/provider.xml”文件作为应用程序上下文

  2. Provider在启动时,向注册中心注册自己提供的服务

    1. 读取provider模块中的”META-INF/spring/provider.xml”
      1. dubbo:application给应用配置基本信息
      2. dubbo:registry给dubbo配置注册中心zookeeper
      3. dubbo:protocol定义发布服务用到的dubbo和rest协议
      4. bean注册spring bean给容器管理
      5. Dubbo:service以dubbo或者rest协议发布服务去注册中心
    2. 运行后完成向注册中心注册自己提供的服务

本次实验,服务提供者代码分析:

  1. 在provider中的java目录下的service中存放实现多个Impl类(实现了api中的接口),比如UserRestServiceImpl,UserServiceImpl等,

这些类就是后续将通过dubbo的注册中心发布并给消费者订阅

2.在provider中的resources/META-INF/spring中的provider.xml文件中,实现了spring和dubbo的衔接,是xml config配置文件,配置提供者相关的spring和dubbo的相关内容

provider.xml提供者配置具体内容分析如下:

Dubbo:application标签:本application的信息

适用于向dubbo控制中心提供本application的信息

name 当前应用名称,用于注册中心计算应用间依赖关系
owner 应用负责人,用于服务治理
organization 组织名称(BU或部门),用于注册中心区分服务来源

并且可以在该标签下设置paramter属性比如qos

<**dubbo:application name=”provider” owner=”programmer” organization=”dubbox”**>

<**dubbo:parameter key=”qos.enable” value=”true”**/>

<**dubbo:parameter key=”qos.accept.foreign.ip” value=”false”**/>

<**dubbo:parameter key=”qos.port” value=”33333”**/>

</**dubbo:application**>

dubbo:registry标签:注册中心配置

其中的address为Provider指定注册中心的地址,使得provider去注册。

利用多个 <dubbo:registry> 标签,声明同时有多个不同的注册中心并在 <dubbo:service> 或 <dubbo:reference> 的 registry 属性指定使用的注册中心。

<!–zookeeper注册中心, 多地址间用”,”隔开 –>

<**dubbo:registry address=”zookeeper://127.0.0.1:2181”**/>

dubbo:protocol标签:服务提供者协议配置

为本次的provider后续的service发布提供了可选协议属性,比如这里定义了可以使用dubbo和rest协议

Dubbo协议采用单一长连接和 NIO 异步通讯,在消费者直接利用注册中心引入并使用ctx.getBean(XXXXX.class)即可使用

Rest协议需要消费者利用URL来调用,而本实验中的TestDubboRequest中不支持对于userRestService的getBean

<**dubbo:protocol name=”dubbo” serialization=”kryo”optimizer=”com.hit.lyx.dubbo.demo.api.common.SerializationOptimizerImpl”**/>

<dubbo:protocol name=”rest” port=”8888” threads=”500”

contextpath=”services” server=”tomcat” accepts=”500”

extension=”com.alibaba.dubbo.rpc.protocol.rest.support.LoggingFilter”/>

<bean>

spring的bean标签,在XML文件进行配置,让spring容器来生产和管理这些bean,类似于工厂模式管理类的实例

这里定义的bean被dubbo:service标签可以发布到注册中心

<!–普通的spring bean–>

<**bean id=”userService” class=”com.hit.lyx.dubbo.demo.service.UserServiceImpl”**/>

<**bean id=”userRestService” class=”com.hit.lyx.dubbo.demo.service.UserRestServiceImpl”**>

<**property name=”userService” ref=”userService”**/>

</**bean**>

dubbo:service标签: 服务提供者暴露服务配置

在这个标签中provider向注册中心发布以指定的协议想发布的服务,

interface 服务接口名
ref 服务对象实现引用
protocol 使用指定的协议暴露服务

以本实验代码为例:

第一个dubbo:service标签,让id为userService,实现接口为com.hit.lyx.dubbo.demo.api.service.UserService的bean,以dubbo协议发布到注册中心.在消费者TestDubboRequest中,可以利用cxf.getBean(userService.class)获取到bean

<!–服务提供者以dubbo协议发布服务–>

<dubbo:service interface=”com.hit.lyx.dubbo.demo.api.service.UserService”

ref=”userService” protocol=”dubbo”/>

<!–服务提供者发布rest服务–>

<dubbo:service interface=”com.hit.lyx.dubbo.demo.api.service.UserRestService”

ref=”userRestService” protocol=”rest”

validation=”true”/>

第二个dubbo:service标签,让id为userRestService,实现接口为com.hit.lyx.dubbo.demo.api.service.userRestService的bean,以rest协议发布到注册中心.

可以通过访问”http://127.0.0.1:8888/services/users/1.xml”或者”http://127.0.0.1:8888/services/users/1.json”来访问userRestService

启动类src/test/java/Bootstrap.java分析:

ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(“META-INF/spring/provider.xml”);

ctx.start();

创建 Spring 的 IOC 容器,生产管理了对应的bean实例以便于后续交给注册中心,被消费者所使用

关键点:

Q1:控制台报错信息Qos started failed,经过推断猜测qos端口与其他端口发生了冲突,导致无法正常启动Qos的服务

QoS,全称为Quality of Service,在Dubbo中,QoS这个概念被用于动态的对服务进行查询和控制在这类可以通过

<**dubbo:parameter key=”qos.port” value=”33333”**/>的命令修改dubbo中的qos默认配置从而解决问题

Q2:userRestService显示没有消费者

协议问题:

本次试验中除了userRestService以外其他采取的都是dubbo协议,userRestService是rest协议

Dubbo协议

在消费者直接利用注册中心引入

并使用ctx.getBean(XXXXX.class)即可使用

Rest协议

需要消费者利用URL来调用,而本实验中的TestDubboRequest中没有写入对于userRestService的rest调用

所以dubbo中显示userRestServic没有消费者

如果强行添加了ctx.getBean(UserRestService.class)会提示报错

Q3.userRestServiceImpl代码风格问题:

如果按照dubbo官方文档的推荐写法应该要加入“/”,本实验指导书给出的示例代码中缺少斜杠号/

@path(“users”)–应该为–>@path(“/users”)

@path(“{id: \\d+}”)–应该为–>@path(“/{id: \\d+}”)

图3.1

但是无论是否修改,都可以利用http://localhost:8080/users/load?id=1001来调用userRestService

Dubbo框架下Service Consumer消费服务的过程,及过程中的关键点。

Consumer:

服务消费者,通过注册中心协调,订阅可用的已注册的服务。

订阅服务过程:

  1. Consumer向注册中心订阅自己所需的服务。

    读取consumer模块中的”META-INF/spring/consumer.xml”

    1. dubbo:application给应用配置基本信息
      1. dubbo:registry给dubbo配置注册中心zookeeper
      2. Dubbo:refernce生成远程服务代理,声明消费者订阅了哪些被提供者发布的服务,允许消费者像使用本地bean一样使用远程服务
  2. Consumer启动,注册中心返回Provider地址列表给Consumer,如果有变更,注册中心将基于长连接推送变更数据给Consumer。

    TestDubboRequest启动,通过ClassPathXmlApplicationContext ctx=newClassPathXmlApplicationContext(“META-INF/spring/provider.xml”);ctx.start();启动了spring的IOC容器,读取provider.xml的应用程序上下文

  3. Consumer,从Provider地址列表中,基于软负载均衡算法,选一台Provider进行调用,如果调用失败,再选另一台调用。

    TestDubboRequest利用ctx对注册中心中被provider发布的服务进行订阅调用,可以直接ctx.getBean(UserService.class)来获取到userService的bean实例

本次实验,消费提供者代码分析:

  1. 在java目录下有个TestDubooRequest的启动类,负责启动消费者
  2. 在provider中的resources/META-INF/spring中的consumer.xml文件中,实现了spring和dubbo的衔接,是xml config配置文件,配置提供者相关的spring和dubbo的相关内容

Consumer.xml消费者配置具体内容分析如下:

同provider的标签

dubbo:application

dubbo:registry

不同标签:

dubbo:reference标签: 服务消费者引用服务配置

生成远程服务代理,可以像使用本地bean一样使用demoService

消费者订阅的服务, 默认情况下需要先发布服务才能订阅, 通过添加check=”false”可以直接订阅任意服务,只是调用时需要注意判断是否可用

id 服务引用BeanId
interface 服务接口名

比如第一个标签,指定了BeanId=”userRestService” 实现的接口是”com.hit.lyx.dubbo.demo.api.service.UserRestService”的bean被消费者引入

<**dubbo:reference id=”userRestService” interface=”com.hit.lyx.dubbo.demo.api.service.UserRestService”**/>

TestDubboRequest消费者启动类具体内容分析如下:

1.根据路径找到配置上下文,启动spring的IOC容器

ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(“META-INF/spring/consumer.xml”);

ctx.start();

2.通过IOC容器和注册中心的共同作用下,利用getBean()方法调用提供者的bean来给消费者进行使用

比如UserService service = ctx.getBean(UserService.class);调用了userSerivce的bean

关键点:

指导书展示效果原理分析

“b) 分别在启动 provider.Bootstrap、consumer. TestDubboRequest 后重新查看服务列表: ”

现象:出现了UserRestService提示没有消费者

原因:在消费者启动类中TestDubboRequest中,没有ctx.getBean(UserRestService)因此没有直接向注册中心调用

图4.1

现象:如果在TestDubboRequest中加入UserRestService userRestService = ctx.getBean(UserRestService.class);

提示报错:Error creating bean with name ‘userRestService’: FactoryBean threw exception on object creation;

图4.2

原因分析:在provider中我们发布userRestService是利用的rest协议,想要通过dubbo使用rest协议的服务还需要配置setter等,因此在本试验中不利用getBean直接获取,而得是通过URL获取。

其他的类由于是通过Dubbo协议发布,所以其他类可以利用getBean

“c) 在 consumer. TestDubboRequest 控制台中输入任意数字并回车,查看输出;”

现象:

控制台就得到

图4.3

原因分析:

在TestDubboRequest中获取System.in作为id参数,然后调用service.getUser(id)

图4.4

图4.5

方法将返回一个new User的toString(),然后这份String就输出在控制台中

“d) 在 浏 览 器 地 址 栏 输 入

127.0.0.1:8888/services/users/1.json 、

127.0.0.1:8888/services/users/1.xml

查 看 浏 览 器 及 provider.Bootstap 的输出:”

现象:

浏览器:

图4.6浏览器输出json

图4.7浏览器输出xml

控制台provider的输出:

图4.8控制台输出报错

图4.9控制台输出信息

问题:提示没有找到favicon.ico

原因分析:

Favicon是与某个网站或网页相关联的图标

比如说百度的

在本demo中的resources资源目录中没有存放favicon图标,spring在执行过程中发布网页之后自然无法找到。在springboot中可以通过在resources中提供favicon.ico图标即可将图标发布到Web上

问题:控制台信息是为什么输出这段内容

原因分析:

127.0.0.1:8888/services/users/1.json和127.0.0.1:8888/services/users/1.xml都对应的是provider在dubbo中以rest风格发布的userRestService

Rest协议就是将这个userRestService服务要实现的功能,提供如下URL,而任何客户端都可以将包含用户信息的JSON字符串POST到以上URL来完成用户注册

在userRestServiceImpl中:

图4.9代码

@Path(“/users”)指定访问UserRestService的URL相对路径是/users

@GET指定访问用HTTP GET方法

@Path(“/{id : \\d+}”)根据上面结合分析,访问的URL应当是“http://localhost:端口/users/ + 任意数字”,其中{id : \\d+}使用了正则表达式,要求是id为数字数字

代表路径为/users/{id},method为GET方式

@Consumes({MediaType.APPLICATION_JSON, MediaType.TEXT_XML})

指定接收JSON格式和xml格式的数据。REST框架会自动将JSON数据和xml数据,反序列化为User对象

@Produces({ContentType.APPLICATION_JSON_UTF_8,ContentType.TEXT_XML_UTF_8})

指定输出JSON格式或者xml格式的数据。框架会自动将User对象序列化为JSON数据或者xml格式。

因此:访问127.0.0.1:8888/services/users/1.json将传送json格式的数据给后端userRestServiceImpl然后,后端返回json格式数据展示在前端网页

详细描述你的服务的发布过程和被消费方式。

  1. 服务容器负责启动加载,通过BootStrap运行Provider。

    BootStrap中的ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(“META-INF/spring/provider.xml”);
    ctx.start();

    启动了spring的IOC容器,准备读取”META-INF/spring/provider.xml”文件作为应用程序上下文

  2. Provider在启动时,向注册中心注册自己提供的服务

    1. 读取provider模块中的”META-INF/spring/provider.xml”
      1. dubbo:application给应用配置基本信息
      2. dubbo:registry给dubbo配置注册中心zookeeper
      3. dubbo:protocol定义发布服务用到的dubbo和rest协议
      4. bean注册spring bean给容器管理
      5. Dubbo:service以dubbo或者rest协议发布服务去注册中心
    2. 向注册中心注册自己提供的服务:userRestSertvice,userService,hsuse,houseManager,userManager,utilData这几个服务
  3. Consumer向注册中心订阅自己所需的服务。

    1. 读取consumer模块中的”META-INF/spring/consumer.xml”
      1. dubbo:application给应用配置基本信息
      2. dubbo:registry给dubbo配置注册中心zookeeper
      3. Dubbo:refernce生成远程服务代理,声明消费者订阅了哪些被提供者发布的服务,允许消费者像使用本地bean一样使用远程服务
      4. 读取到userRestSertvice,userService,hsuse,houseManager,userManager,utilData这几个服务
  4. Consumer启动,注册中心返回Provider地址列表给Consumer,如果有变更,注册中心将基于长连接推送变更数据给Consumer。

    1. TestDubboRequest启动,通过ClassPathXmlApplicationContext ctx=newClassPathXmlApplicationContext(“META-INF/spring/provider.xml”);ctx.start();启动了spring的IOC容器,读取provider.xml的应用程序上下文
  5. Consumer,从Provider地址列表中,基于软负载均衡算法,选一台Provider进行调用,如果调用失败,再选另一台调用。

    1. TestDubboRequest利用ctx对注册中心中被provider发布的服务进行订阅调用,可以直接ctx.getBean(UserService.class)来获取到userService的bean实例

关键点:

如果在provider中注释掉某个dubbo:service标签比如UserService,然后启动消费者TestDubboRequest会提示对应的服务没有提供者

图5.1

如果只启动提供者的BootStrap而不启动消费者的TestDubboRequest,会提示所有服务都没有消费者

图5.2

如果在provider中注释掉某个dubbo:service标签比如UserService,然后不启动消费者TestDubboRequest会在dubbo中,刚才注释的服务不会出现

图5.3

如果启动provider的BootStrap,然后仅注释掉消费者中的consumer.xml中的dubbo:reference标签比如userService,启动消费者TestDubboRequest

会提示找不到注释掉的UserService找不到对应的bean

图5.4

如果启动provider的BootStrap,然后仅注释掉消费者中的TestDubboRequest

中的ctx.getBean()标签比如UtilData,启动消费者TestDubboRequest

dubbo会提示没有消费者


《面向服务的软件系统》实验二:Dubbo环境搭建与服务部署
http://yoursite.com/2023/04/21/面向服务实验二-120L021011-石卓凡/
作者
Fars
发布于
2023年4月21日
许可协议