作者:不洗碗工作室 - Marklux
出处: Dubbo入门(2) - 简单实践
版权归作者所有,转载请注明出处
在了解什么是分布式框架之后,我们需要上手实践一下,来了解整个系统是如何运作起来的。
本文抱着学习的目的来尝试使用dubbo搭建一个简单的分布式服务,并且使用dubbokeeper来进行服务的监控。
参考自:聊聊dubbo和 最简单的dubbo教程
在正式使用dubbo之前,需要准备两样东西:
dubbo的消费方和服务方都需要在一个统一的注册中心进行注册才能使用,搭建一个zookeeper即可,当然你也可以使用其他的注册中心并集成进去。
zookeeper的搭建流程很简单,参考此文即可(仅仅是最简单的单机版,并不复杂)。
为了监控整个分布式服务的运行情况,最好能够有一个可视化的管理和监控应用,这里选用由dubboclub团队开发的 dubbokeeper ,当然也可以使用dubbo官方的 dubboadmin
项目。
由于dubbokeeper的部署有些复杂,在这里还是简要的描述一下,注意监控软件并不是必要的,但是为了能够看到服务运行的效果,建议还是部署一个。
部署流程参考此文
首先需要获取dubbokeeper的源码,可以从github上获取,git地址:
https://github.com/dubboclub/dubbokeeper
下面我们假设将dubbokeeper克隆到了 ~/dubbokeeper
这个目录下。
在此之前,首先需要确定你要使用何种数据库,dubbokeeper目前支持MySQL,MongoDB和Lucene三种数据储存方案,我们以MySQL为例进行部署。
首先要填写 ~/dubbokeeper/conf/dubbo-mysql.properties
配置文件,下面给出比较重要的配置项说明:
dubbo.registry.address=zookeeper://localhost:2181 #注册中心地址 dubbo.protocol.name=dubbo dubbo.protocol.port=20884 #dubbo服务端口 dubbo.monitor.mysql.url=jdbc:mysql://localhost:3306/dubbo-monitor #mysql服务地址 dubbo.monitor.mysql.username=root dubbo.monitor.mysql.password=secret #用户名及密码
接下来要填写 ~/dubbokeeper/dubbokeeper-ui/src/main/resources/dubbo.properties
配置文件中的注册中心和网络服务器类型等参数。
创建一个mysql数据库,并运行 ~/dubbokeeper/doc/storage/mysql/sql/application.sql
创建表结构。
执行 ~/dubbokeeper/install-mysql.sh
进行打包,最终会生成 target
输出目录。
这一步要启动几个服务后才能去部署应用,注意顺序
首先需要启动zookeeper服务,注意端口的配置要和配置文件一致。
接下来执行 target
目录下的 mysql-dubbokeeper-server/bin/start-mysql.sh
启动储存服务。
最后将 target
目录下的 mysql-dubbokeeper-ui
中的war包复制到 tomcat(自己部署)
的webapps目录下,启动tomcat便会自动进行解压和安装,之后访问 http://localhost:8080/dubbokeeper-ui-1.0.1
看到如下界面,即为安装成功。
现在正式开始编程。我们将使用dubbo创建一个非常简单的、只有一个消费者和一个服务提供方的例子。
首先第一步是创建双方都需要依赖的数据交换定义,通过一个interface来实现。
创建maven项目 msa-demo-api
, pom.xml
文件内容如下:
<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.marklux</groupId> <artifactId>msa-demo-api</artifactId> <version>1.0-SNAPSHOT</version> <packaging>pom</packaging> <properties> <motan.version>0.3.0</motan.version> <!-- 在阿里巴巴内部广泛使用的GA版本为:2.4.9,强烈推荐此版本 --> <dubbo.version>2.5.3</dubbo.version> <dubbox.version>2.8.4</dubbox.version> <spring.version>4.3.6.RELEASE</spring.version> <java.version>1.7</java.version> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <dependencies> <dependency> <groupId>com.alibaba</groupId> <artifactId>dubbo</artifactId> <version>2.5.3</version> <exclusions> <exclusion> <groupId>org.springframework</groupId> <artifactId>spring</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>com.github.sgroschupf</groupId> <artifactId>zkclient</artifactId> <version>0.1</version> </dependency> <!-- spring相关 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-orm</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jms</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjrt</artifactId> <version>1.6.11</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.6.11</version> </dependency> </dependencies> </project>
然后在 com.marklux.dubbo.demo
包中添加 DemoService
接口,代码如下:
package com.marklux.dubbo.demo; /** * Created by lumin on 18/5/15. */ public interface DemoService { String sayHello(String name); }
之后的服务提供方根据这个接口实现服务,消费者根据接口调用服务。(有点类似Thrift里的IDL文件)
创建一个新的maven模块 msa-demo-provider
,用于实现 DemoService
服务。模块结构如下:
项目的 pom.xml
中需要添加对 msa-demo-api
模块的依赖:
<?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.marklux</groupId> <artifactId>msa-demo-provider</artifactId> <version>1.0-SNAPSHOT</version> <dependencies> <dependency> <groupId>com.marklux</groupId> <artifactId>msa-demo-api</artifactId> <version>1.0-SNAPSHOT</version> </dependency> </dependencies> </project>
首先编写 DemoServiceImpl
实现服务内容,代码如下:
package com.marklux.dubbo.demo.impl; import com.marklux.dubbo.demo.DemoService; import org.springframework.stereotype.Service; /** * Created by lumin on 18/5/15. */ @Service("demoService") public class DemoServiceImpl implements DemoService { public String sayHello(String name) { return "Hello, " + name; } }
接下来填写 msa-demo-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="dubbo_provider" /> <!-- 使用zookeeper注册中心暴露服务地址 --> <dubbo:registry address="zookeeper://127.0.0.1:2181" /> <!-- 用dubbo协议在20880端口暴露服务 --> <dubbo:protocol name="dubbo" port="20880" /> <!-- 声明需要暴露的服务接口 --> <dubbo:service interface="com.marklux.dubbo.demo.DemoService" ref="demoService" /> </beans>
然后填写 springmvc.xml
,用于给入口类提供 Spring
服务容器的配置:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xmlns:util="http://www.springframework.org/schema/util" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd" default-autowire="byName"> <aop:aspectj-autoproxy /> <context:component-scan base-package="com.marklux.dubbo.demo" /> <import resource="classpath:msa-demo-provider.xml" /> </beans>
最后在 com.marklux.dubbo.demo.test
包中添加测试启动类,用于启动服务:
package com.marklux.dubbo.demo.test; import org.springframework.context.support.ClassPathXmlApplicationContext; import java.io.IOException; /** * Created by lumin on 18/5/15. */ public class DemoServiceImplTest { public static void main(String[] args) { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:spring-mvc.xml"); context.start(); System.out.println("Dubbo Service started...."); try { System.in.read(); // 按任意键退出 } catch (IOException e) { e.printStackTrace(); } } }
启动 DemoServiceImplTest
类后服务就会注册并启动,这时候可以在 dubbokeeper
中看到服务的状态:
最后来创建一个调用服务的消费者,添加一个maven模块 msa-demo-client
, pom.xml
同上,添加对 msa-demo-api
模块的依赖,注意并不需要 msa-demo-provider
的依赖。
模块的结构如下:
只有一个测试的启动类,代码如下:
package com.marklux.dubbo.demo.test; import com.marklux.dubbo.demo.DemoService; import org.springframework.context.support.ClassPathXmlApplicationContext; import java.io.IOException; /** * Created by lumin on 18/5/15. */ public class DemoServiceConsumerTest { public static void main(String[] args) { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"classpath:springmvc.xml"}); context.start(); DemoService demoService = (DemoService) context.getBean("demoService"); System.out.println(demoService.sayHello("哈哈哈")); try { System.in.read(); } catch (IOException e) { e.printStackTrace(); } } }
记得补充dubbo的配置文件 msa-demo-client.xml
和spring的配置文件 springmvc.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="dubbo_consumer" /> <!-- 使用multicast广播注册中心暴露发现服务地址 --> <dubbo:registry protocol="zookeeper" address="zookeeper://127.0.0.1:2181" /> <!-- 生成远程服务代理,可以和本地bean一样使用demoService --> <dubbo:reference id="demoService" interface="com.marklux.dubbo.demo.DemoService" /> </beans>
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xmlns:util="http://www.springframework.org/schema/util" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd" default-autowire="byName"> <aop:aspectj-autoproxy /> <context:component-scan base-package="com.marklux.dubbo.demo" /> <import resource="classpath:msa-demo-consumer.xml" /> </beans>
万事俱备,现在启动 DemoServiceConsumerTest
,可以看到成功调用了 DemoService
:
在dubbokeeper中同样可以查看到其相关状态: