分布式入门教程记录。由于dubbo依赖zookeeper,前置条件需掌握zookeeper相关知识,可跳转至zookeeper指南提前进行了解。
一. 什么是dubbo
官网解释如下:Apache Dubbo 是一款微服务框架,为大规模微服务实践提供高性能 RPC 通信、流量治理、可观测性等解决方案,
涵盖 Java、Golang 等多种语言 SDK 实现。
主要为了实现生产环境中单体服务无法满足日趋增长的访问量所做的横向扩展,使用以下粗略的草图来表示使用dubbo前和使用dubbo后的区别:
(简单表示单点服务)
(引入dubbo/zookeeper后)
我们可以横向扩展多个服务,有多种场景可以适用,例如在一个系统中我们将用户中心作为单独一个服务A,订单系统作为单独一个服务B,并且服务A和服务B都可以作为多个副本部署在不同的服务器并注册到dubbo上。
当用户访问的时候就会经过dubbo来分配请求,其中在dubbo这一层还有zookeeper的参与。本文重点突出dubbo的使用,故假设读者已经具备zookeeper的使用能力,若有疑问可以转至笔者的另一篇文章进行了解:zookeeper指南
二. dubbo实战
talk is cheap,show me the code,我们直接上手玩一把。
网上也有较多的例子,这里以保姆教学的心态将每个细节都呈现给读者。
我们首先需要建立一个多模块聚合工程,包含以下三个模块:
- api:接口定义,实体类定义
- consumer:消费者
- provider:生产者
pom依赖
其中,consumer和provider都依赖api模块,这里将关键的pom文件展示出来:
root父工程的pom依赖:
<modelVersion>4.0.0</modelVersion>
<packaging>pom</packaging>
<name>mydubbo</name>
<groupId>org.vainycos</groupId>
<artifactId>mydubbo</artifactId>
<version>1.0</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.2</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<modules>
<module>api</module>
<module>consumer</module>
<module>provider</module>
</modules>
<properties>
<java.version>1.8</java.version>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
api模块:
<parent>
<groupId>org.vainycos</groupId>
<artifactId>mydubbo</artifactId>
<version>1.0</version>
</parent>
<groupId>com.vainycos</groupId>
<artifactId>api</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>api</name>
<description>api</description>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
provider模块:
<parent>
<groupId>org.vainycos</groupId>
<artifactId>mydubbo</artifactId>
<version>1.0</version>
</parent>
<dependencies>
<dependency>
<groupId>com.vainycos</groupId>
<artifactId>api</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- dubbo的依赖 -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>2.7.6</version>
</dependency>
<!-- zk的依赖 -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-dependencies-zookeeper</artifactId>
<version>2.7.6</version>
<type>pom</type>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
<build>
<!-- 包名称 -->
<finalName>dubbo-provider</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<!--添加自己的启动类路径!-->
<configuration>
<mainClass>com.vainycos.provider.ProviderApplication</mainClass>
</configuration>
<executions>
<execution>
<goals>
<!--可以把依赖的包都打包到生成的Jar包中-->
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.21.0</version>
<configuration>
<!-- 跳过测试 -->
<skipTests>true</skipTests>
</configuration>
</plugin>
</plugins>
</build>
consumer模块:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.2</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependencies>
<dependency>
<groupId>com.vainycos</groupId>
<artifactId>api</artifactId>
<version>0.0.1-SNAPSHOT</version>
</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>
<!-- dubbo的依赖 -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>2.7.6</version>
</dependency>
<!-- zk的依赖 -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-dependencies-zookeeper</artifactId>
<version>2.7.6</version>
<type>pom</type>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<!-- 包名称 -->
<finalName>dubbo-consumer</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<!--添加自己的启动类路径!-->
<configuration>
<mainClass>com.vainycos.consumer.ConsumerApplication</mainClass>
</configuration>
<executions>
<execution>
<goals>
<!--可以把依赖的包都打包到生成的Jar包中-->
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.21.0</version>
<configuration>
<!-- 跳过测试 -->
<skipTests>true</skipTests>
</configuration>
</plugin>
</plugins>
</build>
配置文件
- provider
spring:
application:
name: provider
server:
port: 60001
dubbo:
registry:
# zookeeper的注册地址
address: zookeeper://x.x.x.x:2181
timeout: 10000
protocol:
name: dubbo
# 线上环境可使用-1,由dubbo分配端口
port: 20880
scan:
base-packages: com.vainycos.provider.service
- consumer
spring:
application:
name: consumer
server:
port: 50001
dubbo:
registry:
address: zookeeper://x.x.x.x:2181
timeout: 10000
关键代码
- api
定义接口
public interface OrderService {
List<Order> findOrdersByUserId(Integer userId);
}
定义model
@Data
public class Order implements Serializable {
private Long id;
private Date createTime;
private Integer userId;
private List<OrderItem> orderItemList;
}
@Data
public class Order implements Serializable {
private Long id;
private Date createTime;
private Integer userId;
private List<OrderItem> orderItemList;
}
- provider
服务实现类
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.Service;
import java.util.ArrayList;
import java.util.List;
/**
* @author: Vainycos
* @description
* @date: 2022/8/4 15:29
*/
// 需注意这里引入@Service注解是dubbo包下的
@Slf4j
@Service
public class OrderServiceImpl implements OrderService {
@Override
public List<Order> findOrdersByUserId(Integer userId) {
// do something
log.info("获取订单消息...");
Order order = new Order();
order.setId(1L);
order.setUserId(userId);
List<Order> list = new ArrayList<>();
list.add(order);
return list;
}
}
- consumer
service:
public interface UserService {
List<Order> findOrdersByUserId(Integer id);
}
import com.vainycos.consumer.service.UserService;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* @author: Vainycos
* @description
* @date: 2022/8/4 15:57
*/
// Spring的Service注解
@Service
public class UserServiceImpl implements UserService {
@Reference
private OrderService orderService;
@Override
public List<Order> findOrdersByUserId(Integer id) {
return orderService.findOrdersByUserId(id);
}
}
controller:
@RequestMapping("/test")
@RestController
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/getUser")
public List<Order> getUser(Integer userId){
List<Order> ordersByUserId = userService.findOrdersByUserId(userId);
return ordersByUserId;
}
}
此时,我们分别启动provider以及consumer,并访问consumer的接口:localhost:50001/test/getUser,观察provider的日志正确输出:获取订单消息…即表示成功了。
三. dubbo-admin
前期准备
dubbo-admin是一个官方的可视化服务,这里我们通过Github的源代码仓库进行构建。
-
访问Github地址:https://github.com/apache/dubbo-admin,并clone至本地
-
目录结构如下
重点关注dubbo-admin-server以及dubbo-admin-ui模块,前者是springboot后端项目,后者是vue前端项目。
- 调整dubbo-admin-server配置文件中的zookeeper指向,启动端口,访问账号密码调整(可选)
server.port=10080
admin.registry.address=zookeeper://10.8.3.173:2181
admin.config-center=zookeeper://10.8.3.173:2181
admin.metadata-report.address=zookeeper://10.8.3.173:2181
# 可选调整
admin.root.user.name=root
admin.root.user.password=root
启动
本地调试模式启动:前后端分开启动;或者在根目录下打包后直接用根目录的jar包启动,两种启动结果是一致的。
-
启动后端,以下两种方式
- org.apache.dubbo.admin.DubboAdminApplication,直接启动main主入口
- 在项目根目录下执行打包命令:mvn clean install ‘-Dmaven.test.skip=true’,打包完成后进入到dubbo-admin-distribution\target目录下找到dubbo-admin-0.4.0.jar并进行启动即可
-
启动前端
-
首先需要准备node环境
-
切换到dubbo-admin-ui目录下,运行命令npm install
-
修改dubbo-admin-ui/vue.config.js的代理后端地址,需要与dubbo-admin-server配置文件中的启动端口保持一致
proxy: { '/': { // 实际后端访问地址 target: 'http://localhost:10080/', changeOrigin: true, pathRewrite: { '^/': '/' } } }
-
执行启动命令,默认启动端口为8082
npm run dev
-
启动完成之后访问localhost:8082,默认账号密码是root/root。
四. 总结
作为dubbo的使用,仅仅作为开始,后续将会不断地丰富该项目,将以上代码在gitee上进行开源:https://gitee.com/dearvainycos/mydubbo.git。
参考资料: