在Spring技术栈-整合dubbo、zookeeper一文中我们已经讲述了如何整合Spring、dubbo、zookeeper来开发一个分布式的应用。本文在上文的基础上来描述如何打包部署dubbo微服务,实现一个高可用的微服务集群,如果不知道如何整合Spring、dubbo、zookeeper,请读者先阅读上文,然后再阅读此文进行微服务的打包和部署操作。
准备工作
我们假设读者已经在自己的环境中安装了maven,java jdk等必须的基础软件,本文不会讲述如何安装这些基础构件,只描述部署dubbo微服务的打包、部署、运行测试方案。
安装虚拟机3台,笔者安装虚拟机使用的是VirtualBox,读者可根据自己的环境具体分析,安装完成虚拟机之后,要确保虚拟机和宿主机之间能够进行网络通讯。
IP | 备注 | 开放端口 |
---|---|---|
192.168.199.177(宿主机) | MySQL是安装在宿主机 | 3306(需要添加入站规则,将3306端口开放,否则虚拟机无法链接MySQL) |
192.168.199.161(虚拟机) | zookeeper注册中心 | 2181 |
192.168.199.249(虚拟机) | 服务主机 | 20882 |
192.168.199.126(虚拟机) | 服务主机 | 20882 |
以上是笔者机器上所安装的虚拟机信息,仅供参考,读者可根据自己的具体环境具体安装。
实例介绍
我们以开发一个博客服务为例,用户在访问博客列表时,我们一开始启动两个服务实例注册到Zookeeper,然后让其中一个服务宕机,然后测试博客列表是否能够正常访问。
服务接口
public interface BlogFacade {
/**
* @Comment 获取博客列表
* @Author Ron
* @Date 2017年10月25日 下午2:53:39
* @return
*/
List<BlogContent> findBlogList(BlogContent blogContent);
/**
* @Comment 获取博客内容
* @Author Ron
* @Date 2017年10月25日 下午3:04:57
* @return
*/
BlogContent getBlog(String bid);
}
服务实现
新建一个blog_service项目,新建BlogService实现以上接口
@Component("blogService")
public class BlogService implements BlogFacade{
private Logger logger = LogManager.getLogger(this.getClass());
@Autowired
private BlogContentMapper blogContentMapper;
@Autowired
RedisUtils redisUtils;
/**
* @Comment 获得博客列表
* @Author Ron
* @Date 2017年10月25日 下午3:04:01
* @return
*/
@Override
public List<BlogContent> findBlogList(BlogContent blogContent) {
logger.info("进入博客查询列表");
try {
return blogContentMapper.selectList(blogContent);
} catch (Exception e) {
logger.error("访问博客列表失败"+e);
return null;
}
}
/**
* @Comment 获取博客内容
* @Author Ron
* @Date 2017年10月25日 下午3:05:27
* @return
*/
@Override
public BlogContent getBlog(String bid) {
if(redisUtils.exists(bid)){
logger.info("缓存命中博客"+bid);
return (BlogContent) redisUtils.get(bid);
}else{
logger.info("缓存尚未命中博客"+bid);
BlogContent blogContent = blogContentMapper.selectByPrimaryKey(bid);
redisUtils.set(bid, blogContent);
return blogContent;
}
}
}
在服务实例中我们用到了Redis做缓存,读者可参考12、Spring技术栈-Redis Sentinel实战一文了解如何使用Redis实现缓存集群。
其中blogContentMapper是通过整合Mybatis访问MySQL的映射类,关于如何整合Mybatis,读者可参考2、Spring技术栈-整合Mybatis
Dubbo 服务提供方配置
在resources目录增加dubbo目录,新建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="ron-service-blog" logger="log4j"/>
<dubbo:registry protocol="zookeeper" address="${registry.address}"/>
<dubbo:monitor protocol="registry"/>
<dubbo:protocol name="dubbo" port="${service.port}" serialization="java" />
<dubbo:provider timeout="30000" loadbalance="random" >
<dubbo:parameter key="shutdown.timeout" value="60000" />
<dubbo:parameter key="shutdown.hook" value="true" />
<dubbo:parameter key="retries" value="0" />
</dubbo:provider>
<!-- 声明需要暴露的服务 -->
<dubbo:service interface="ron.blog.blog_facade.blog.BlogFacade" ref="blogService" />
</beans>
config.properties配置
在配置文件中,增加zookeeper地址和端口以及服务端口的配置。
#zookeeper配置
registry.address=192.168.199.161:2181
service.port=20882
微服务项目pom.xml配置
在服务的pom.xml文件中除了添加dubbo和zookeeper客户端的依赖之外,我们还需要添加一些maven插件,帮助我们在使用maven打包项目时能够拷贝依赖的jar包和相关的资源文件到指定的目录。同时因为我们开发的微服务一般情况家都是一个jar包,所以我们需要这个jar包能够单据运行,所以我们也需要在pom文件中指定main函数(程序入口)的位置。具体的配置如下:
dubbo_version:2.8.4a
zkclient_version:0.10
<!-- dubbo -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
<version>${dubbo_version}</version>
</dependency>
<!-- zookeeper -->
<dependency>
<groupId>com.101tec</groupId>
<artifactId>zkclient</artifactId>
<version>${zkclient_version}</version>
</dependency>
<build>
<finalName>ron-service-blog</finalName>
<resources>
<!-- 资源文件 -->
<resource>
<targetPath>${project.build.directory}/classes</targetPath>
<directory>src/main/java</directory>
<filtering>true</filtering>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
<resource>
<!--配置文件拷贝的对象目录 -->
<targetPath>${project.build.directory}/classes</targetPath>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<includes>
<include>**/*.xml</include>
<include>**/*.properties</include>
</includes>
</resource>
<resource>
<!--配置文件必须放在spring文件夹下,否则dubbo即使显示启动成功,实际上也没有启动成功 -->
<targetPath>${project.build.directory}/classes/META-INF/spring</targetPath>
<directory>src/main/resources/</directory>
<filtering>true</filtering>
<includes>
<include>spring-context.xml</include>
</includes>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<classesDirectory>target/classes/</classesDirectory>
<archive>
<manifest>
<mainClass>com.alibaba.dubbo.container.Main</mainClass>
<useUniqueVersions>false</useUniqueVersions>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
</manifest>
<manifestEntries>
<Class-Path>.</Class-Path>
</manifestEntries>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<type>jar</type>
<includeTypes>jar</includeTypes>
<outputDirectory>
${project.build.directory}/lib
</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
Dubbo消费者配置
在web端的resources目录下新建dubbo目录,添加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:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:context="http://www.springframework.org/schema/context" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xsi:schemaLocation="
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-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/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-4.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://code.alibabatech.com/schema/dubbo
http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
<!-- 消费方应用名,用于计算依赖关系,不是匹配条件,不要与提供方一样 -->
<dubbo:application name="blog-service" />
<context:property-placeholder ignore-unresolvable="true" location="classpath:config.properties" />
<!-- 使用zookeeper注册中心暴露服务地址 -->
<dubbo:registry protocol="zookeeper" address="${registry.address}" />
<dubbo:consumer check="false" />
<!-- 服务应用 -->
<dubbo:reference id="blogService" interface="ron.blog.blog_facade.blog.BlogFacade" />
</beans>
其中配置参数都添加到config.properties中,内容如下
#zookeeper配置
registry.address=192.168.199.161:2181
打包blog_service微服务
在命令行工具中,进入项目pom.xml文件目录,执行以下命令进行打包
mvn clean
mvn package -Dmaven.test.skip=true
等待打包完成之后,我们在项目的target目录先会看到一个*.jar包和一个lib文件夹,部署时只需要上传jar包和lib文件夹即可。
安装和配置zookeeper
安装zookeeper作为服务的注册中心,本文将zookeeper安装在192.168.199.161这台虚拟机上,zookeeper安装参见Zookeeper精要-standalone模式,本文主要描述的是服务的高可用,注册中心我们采用单点即可。
注意:服务所指定的注册中心的地址和端口必须是您所安装的zookeeper所在的虚拟机地址和端口。
#zookeeper配置
registry.address=192.168.199.161:2181
#服务端口
service.port=20882
部署服务
我们假设读者已经在自己的虚拟机上安装了java环境,所以这里就不说明如何安装java环境。
在服务主机(笔者的服务主机是192.168.199.126、192.168.199.249)新建一个目录,用于存放服务相关文件。
mkdir /data/blogSrv
通过ftp工具将打包好的内容上传到该目录,笔者使用的是filezilla.exe。文件上传完成之后,编写启动脚本。
新建start.sh,文件,写入启动脚本。
cd /data/blogSrv
vi start.sh
在start.sh中写入如下内容
#!/bin/bash
nohup java -jar ron-service-blog.jar > nohup.log 2>&1 &
解释一下启动脚本命令的含义:在后台运行服务并将服务的错误流信息作为标准输出流输出到nohup.log文件中。
赋予start.sh脚本读写权限
chmod 777 start.sh
启动服务
在服务主机上使用如下命令分别执行启动脚本启动服务。
cd /data/blogSrv
./start.sh
服务启动成功后,可通过如下命令查看是否启动成功
ps -ef|grep ron-service-blog(这里是jar包的名称)
如果启动成功,您会看到如下内容
[root@localhost blogSrv]# ps -ef|grep ron-service-blog
root 4193 1 0 14:09 pts/0 00:00:29 java -jar ron-service-blog.jar
root 4348 2316 0 15:25 pts/0 00:00:00 grep --color=auto ron-service-blog
如果启动失败,在服务jar包存放的目录会生成一个nohup.log文件,读者可查看该日志文件中的内容查看错误信息并修复。
服务可用性测试
如果两台机器上的服务都成功启动,我们就可以打开我们的服务消费端,亲测博客页面能访问。
接下来我们去到任意一台部署服务的虚拟机,使用kill命令杀掉服务进程,再次刷新页面,博客列表页面依然可用。
重新刷新页面