作者:不洗碗工作室 - Marklux
版权归作者所有,转载请注明出处
在了解什么是分布式框架之后,我们需要上手实践一下,来了解整个系统是如何运作起来的。
本文抱着学习的目的来尝试使用dubbo搭建一个简单的分布式服务,并且使用dubbokeeper来进行服务的监控。
参考自:聊聊dubbo和最简单的dubbo教程
准备工作
在正式使用dubbo之前,需要准备两样东西:
1. 服务注册中心(ZooKeeper)
dubbo的消费方和服务方都需要在一个统一的注册中心进行注册才能使用,搭建一个zookeeper即可,当然你也可以使用其他的注册中心并集成进去。
zookeeper的搭建流程很简单,参考此文即可(仅仅是最简单的单机版,并不复杂)。
2. 服务监控中心(dubbokeeper)
为了监控整个分布式服务的运行情况,最好能够有一个可视化的管理和监控应用,这里选用由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
看到如下界面,即为安装成功。
创建API
现在正式开始编程。我们将使用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中同样可以查看到其相关状态:
小结
至此,一个最简单的使用dubbo协议进行服务-调用的demo就完成了。可以看到最显著的特点是,在消费者中调用服务方提供的服务无需添加额外代码,整个调用过程完全透明。
另外借助dubbokeeper
这样的监控端,也更能够直观的理解整个应用服务的分布和运行情况。