前言:
大二的寒假简单学习了 SpringBoot 的 分布式开发,并使用 dubbo + zookeeper 搭建简单的分布式项目,现在回来再温故一遍。
一、什么是分布式系统?
要理解分布式系统,主要需要明白一下2个方面:
-
1.分布式系统一定是由多个节点组成的系统。其中,节点指的是计算机服务器,而且这些节点一般不是孤立的,而是互通的。
-
2.这些连通的节点上部署了我们的节点,并且相互的操作会有协同。
分布式系统对于用户而言,他们面对的就是一个服务器,提供用户需要的服务而已,而实际上这些服务是通过背后的众多服务器组成的一个分布式系统,因此分布式系统看起来像是一个超级计算机一样。
二、Spring Boot 整合 Dubbo&Zookeeper
Dubbo是一款由阿里巴巴开发的远程服务调用框架(RPC),其可以透明化的调用远程服务,就像调用本地服务一样简单。截至目前,Dubbo发布了基于Spring Boot构建的版本,版本号为0.2.0,这使得其与Spring Boot项目整合变得更为简单方便。而Zookeeper在这里充当的是服务注册中心的角色,我们将各个微服务提供的服务通过Dubbo注册到Zookeeper中,然后服务消费者通过Dubbo从Zookeeper中获取相应服务并消费。
2.1、 启动 zookeeper 注册中心:
在搭建项目之前需要启动 Zookeeper 服务,Zookeeper下载地址:http://zookeeper.apache.org/releases.html#download,我下载的 zookeeper-3.4.5 版本。
下载后解压,将config目录下的zoo_sample.cfg 重命名为 zoo.cfg (Zookeeper配置文件,默认端口为2181,可根据实际进行修改)。然后双击bin目录下的zkServer.cmd启动即可。
个人感觉每次运行项目都要启动 zookeeper,麻烦,看这篇文章设置开机自启:Windows下把ZooKeeper注册成为Windows服务,实现开机自启动
2.2、 构建项目:
2.3、 代码编写:
privider-server 接口提供者
<!--导入依赖-->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>2.7.3</version>
</dependency>
<!--zkclient-->
<dependency>
<groupId>com.github.sgroschupf</groupId>
<artifactId>zkclient</artifactId>
<version>0.1</version>
</dependency>
<!--解决日志冲突-->
<!--引入zookeeper-->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>2.12.0</version>
</dependency>
<!--解决 java.lang.NoClassDefFoundError: org/apache/curator/framework/recipes/cache/TreeCacheListener-->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>2.8.0</version>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.14</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
# 服务端口
server.port=8001
# 注册服务应用名字
dubbo.application.name=provider-server
# 注册中心地址
dubbo.registry.address=zookeeper://127.0.0.1:2181
# 哪些服务需要被注册
dubbo.scan.base-packages=com.xiao.service
package com.xiao.service;
public interface TicketService {
String getTicket();
}
package com.xiao.service;
import org.apache.dubbo.config.annotation.Service;
import org.springframework.stereotype.Component;
// zookeeper: 服务注册和发现
@Service // dubbo的注解,可以被扫描到,在项目一启动就自动注册到注册中心
@Component
public class TicketServiceImpl implements TicketService {
@Override
public String getTicket() {
return "一张电影票";
}
}
注意: TicketServiceImpl 实现种最好不要写 @Service注解,因为Dubbo也有一个 @Service 注解,改用 @Component。
完成以上代码编写后,启动项目出现如下问题:
原因是 dubbo 默认使用的是 log4j 日志管理组件,就是少个log4j.properties配置文件,所有我们需要创建一个 log4j.properties 文件,配置如下即可!
log4j.rootCategory=INFO, stdout, file
log4j.logger.org.apache=ERROR
# 控制台输出
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.target=System.out
log4j.appender.stdout.Threshold=INFO
log4j.appender.stdout.encoding=GBK
log4j.appender.stdout.layout.ConversionPattern=%5p %c{2} - %m%n
# 文件输出
log4j.appender.file=org.apache.log4j.RollingFileAppender
log4j.appender.file.file=dubbo-governance.log
log4j.appender.file.Threshold=INFO
log4j.appender.file.append=true
log4j.appender.file.maxFileSize=10MB
log4j.appender.file.maxBackupIndex=100
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d [%t] %-5p %C{6} (%F:%L) - %m%n
consumer-server 接口消费者
<!--导入依赖-->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>2.7.3</version>
</dependency>
<!--zkclient-->
<dependency>
<groupId>com.github.sgroschupf</groupId>
<artifactId>zkclient</artifactId>
<version>0.1</version>
</dependency>
<!--解决日志冲突-->
<!--引入zookeeper-->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>2.12.0</version>
</dependency>
<!--解决 java.lang.NoClassDefFoundError: org/apache/curator/framework/recipes/cache/TreeCacheListener-->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>2.8.0</version>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.14</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
# 服务端口
server.port=8002
# 消费者取哪里拿服务需要暴露自己的名字
dubbo.application.name=consumer-server
# 注册中心地址
dubbo.registry.address=zookeeper://127.0.0.1:2181
提供者相同,这里就不再写一遍了
package com.xiao.service;
public interface TicketService {
String getTicket();
}
import com.xiao.service.TicketService;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class UserController {
// 想拿到 provide-server 的提供的类, 就要去注册中心拿到服务
// 动态接口实现
@Reference
TicketService ticketService;
@GetMapping("/getTicket")
public String buyTicket() {
String ticket = ticketService.getTicket();
return "在注册中心拿到 =>" + ticket;
}
}
@Reference 的行为跟 @Autowired 类似均实现了自动注入的过程 。
@Reference修饰的域是通过动态代理实现的, 也就是生成了一个动态的接口实现类
2.4、 dubbo-admin 管理控制台部署
由于我们不能直观的看到dubbo和zookeeper上到底有什么服务(提供者),所以我们需要一个可视化工具来方便我们管理每一个服务和每一个节点。
官方地址:https://github.com/apache/incubator-dubbo/tree/2.5.x
dubbo-admin 配置
修改 dubbo.properties文件 如下:
dubbo-admin 启动:
把 dubbo-admin 打包成 jar 包然后 java -jar 运行 jar包 即可:
访问 http://localhost:7001/
进入管理界面:
2.5、 启动运行 privider-server 和 consumer-server
先启动 privider-server
查看 dubbo-admin 可以看到 privider-server 已把业务层接口发布到注册中心
测试消费者是否远程调用到了接口:
远程服务调用成功!