一、分布式基本理论

1.1、分布式基本定义

《分布式系统原理与范型》定义:

“分布式系统是若干独立计算机的集合,这些计算机对于用户来说就像单个相关系统”

分布式系统(distributed system)是建立在网络之上的软件系统。

1.2 架构发展演变

架构的发展是由最初的单一应用架构构建的,一般就是ORM框架方便数据库操作。

不过随着系统越来越复杂,单一应用架构会变得难以维护,所以架构逐渐演变出了垂直应用架构,所谓垂直应用架构其实就是安装业务模板进行拆分,比如可以安装业务将一个电商系统分为订单模块,用户信息管理模块,商品管理模块等等,这时候MVC框架就派上用场,MVC框架可以协助系统更好的按业务拆分,不过业务拆分后虽然是比单一应用架构更好维护了。

不过随着系统越来约复杂,发现很多共用的模块很难复用起来,这时候分布式服务架构登场了,分布式架构是将一些核心业务抽取出来,作为独立的服务,逐渐形成稳定的服务中心,当应用需要时,就去服务中心调服务就可以,而实现这种服务注册的肯定是RPC框架了。

当服务越来越多,容量的评估,小服务资源的浪费等问题逐渐显现,此时需增加一个调度中心基于访问压力实时管理集群容量,提高集群利用率,这时候就需要流动计算架构(SOA)[ Service Oriented Architecture],用于提高机器利用率的资源调度,SOA是一个治理中心,综上所述,到目前,软件系统架构演变经历了:单一应用架构->垂直应用架构->分布式应用架构->流动计算架构,下面Dubbo官网的图片可以很好的描述

1.3、RPC简介

RPC概念

RPC【Remote Procedure Call】是指远程过程调用,是一种进程间通信方式,他是一种技术的思想,而不是规范。它允许程序调用另一个地址空间(通常是共享网络的另一台机器上)的过程或函数,而不用程序员显式编码这个远程调用的细节。

RPC核心模块

RPC有两个核心模块:通信和序列化

二、Dubbo理论简介

Apache Dubbo (incubating) |ˈdʌbəʊ| 是一款高性能、轻量级的开源Java RPC框架,它提供了三大核心能力:面向接口的远程方法调用,智能容错和负载均衡,以及服务自动注册和发现。

官网:

http://dubbo.apache.org/



Dubbo的服务治理:

Dubbo原理图片,图片来自Dubbo官网:

Dubbo角色:

  • Provider:暴露服务的服务提供者

  • Container:服务运行的容器

  • Consumer:调用远程服务的消费者

  • Registry:服务注册和发现的注册中心

  • Minitor:统计服务调用次数和时间的监控中心

调用过程:

下面根据我的理解说明一下

  • 0:服务器容器负责启动、加载、运行服务提供者

  • 1:服务提供者在启动后就可以向注册中心暴露服务

  • 2:服务消费者在启动后就可以向注册中心订阅想要的服务

  • 3:注册中心向服务消费者返回服务调用列表

  • 4:服务消费者基于软负载均衡算法调用服务提供者的服务,这个服务提供者有可能是一个服务提供者列表,调用那个服务提供者就是根据负载均衡来调用了

  • 5:服务提供者和服务消费者定时将保存在内存中的服务调用次数和服务调用时间推送给监控中心

三、Dubbo环境搭建

3.1 Zookeeper搭建

搭建Zookeeper,首先是搭建分布式架构的注册中心Zookeeper,当然也可以用Redis等等来做服务注册中心,不过本博客只介绍Zookeeper的,因为没有linux服务器,所以只介绍window版的搭建

  • 1、下载Zookeeper:

    网址 https://archive.apache.org/dist/zookeeper/zookeeper-3.4.13/

  • 2、解压Zookeeper

    解压Zookeeper之后,运行bin目录里的zkServer.cmd,发现报错了,提示找不到配置文件,所以需要继续步骤3

  • 3、配置Zookeeper

    因为Zookeeper的conf文件夹下面只提供zoo_sample.cfg文件,需要自己修改命名为zoo.cfg

对于配置文件需要注意:

dataDir=./ 临时数据存储的目录(可写相对路径)

clientPort=2181 zookeeper的端口号

  • 4、使用zkCli.cmd测试

    修改配置文件后,重新启动zkServer.cmd,启动bin目录下面的zkCli.cmd,很显然这是个客户端程序,注意zkServer.cmd是服务端程序,必须启动

ok,简单在zkCli.cmd敲几个命令测试一下:

ls /:列出zookeeper根下保存的所有节点

create –e /testNode 12345678:创建一个testNode节点,值为12345678

get /testNode:获取/testNode节点的值

3.2 Dubbo管理页面搭建

搭建了服务注册中心后,就需要搭建Dubbo-admin了,最近看了一下,dubbo的Github项目已经进行了更新,管理平台已经做了比较大的改动,而我学习的时候,平台是比较简单的,所以本dubbo-admin搭建是以旧版master的为准,不过以学习为目的的,只需要知道具体原理和操作技巧就可以

因为我搭建时候(ps:不是博客写作时间),dubbo还没做比较大改动,所以我以比较旧的版本为例子,现在新的具体参考dubbo官方的教程,本博客只是做记录

  • 修改dubbo-admin

修改 src\main\resources\application.properties 指定zookeeper地址

  • Maven package dubbo-admin
mvn clean package -Dmaven.test.skip=true
  • 运行dubbo-admin的jar

maven打包之后,就去target里找到jar,然后cmd运行

java -jar dubbo-admin-0.0.1-SNAPSHOT.jar

运行成功之后,访问: http://127.0.0.1:7001,输入默认的账号密码root/root,登录成功

四、Dubbo服务注册发现例子

经典例子(引用尚硅谷教程例子进行改写):

4.1、业务场景

某个电商系统,订单服务需要调用用户服务获取某个用户的所有地址;

我们现在 需要创建两个服务模块进行测试

模块 功能
订单服务模块 创建订单等
用户服务模块 查询用户地址等
  • 测试预期结果:

    订单服务web模块在A服务器,用户服务模块在B服务器,A可以远程调用B的功能

4.2、api工程创建

创建工程:

建议将服务接口,服务模型,服务异常等均放在 API 包中,因为服务模型及异常也是 API 的一部分,同时,这样做也符合分包原则:重用发布等价原则(REP),共同重用原则(CRP)。

创建一个API工程,将实体类和接口都放在api工程

maven新建一个shop-api-common工程:

用户地址DTO类:

package com.test.dubbo.bean;
import java.io.Serializable;
public class UserAddress implements Serializable { private Integer id;
private String userAddress; //用户地址
private String userId; //用户id
private String consignee; //收货人
private String phoneNum; //电话号码
private String isDefault; //是否为默认地址 Y-是 N-否 public UserAddress() {
super();
} public UserAddress(Integer id, String userAddress, String userId, String consignee, String phoneNum,
String isDefault) {
super();
this.id = id;
this.userAddress = userAddress;
this.userId = userId;
this.consignee = consignee;
this.phoneNum = phoneNum;
this.isDefault = isDefault;
} public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUserAddress() {
return userAddress;
}
public void setUserAddress(String userAddress) {
this.userAddress = userAddress;
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getConsignee() {
return consignee;
}
public void setConsignee(String consignee) {
this.consignee = consignee;
}
public String getPhoneNum() {
return phoneNum;
}
public void setPhoneNum(String phoneNum) {
this.phoneNum = phoneNum;
}
public String getIsDefault() {
return isDefault;
}
public void setIsDefault(String isDefault) {
this.isDefault = isDefault;
}
}

用户信息服务接口:

package com.test.dubbo.service;

import java.util.List;

import com.test.dubbo.bean.UserAddress;

/**
* 用户服务
*/
public interface UserService { /**
* 按照用户id返回所有的收货地址
* @param userId
* @return
*/
public List<UserAddress> getUserAddressList(String userId); }

订单信息服务接口:


package com.test.dubbo.service; import java.util.List; import com.test.dubbo.bean.UserAddress; public interface OrderService { /**
* 初始化订单
* @param userId
*/
public List<UserAddress> initOrder(String userId); }

ok,创建好api工程

4.3、服务提供者工程

要实现服务提供,配置文件主要需要配置如下:

Dubbo提供者加载过程(Dubbo容器的启动):



Spring加载xml配置之后暴露服务的过程:



Exporter方法主要是打开socket的监听,接收客户的请求

ok,理解了上面的理论知识后,继续创建一个user-service-provider工程:

参考Dubbo官方例子

<properties>
<spring-boot.version>2.2.1.RELEASE</spring-boot.version>
<dubbo.version>2.7.5</dubbo.version>
<curator.version>2.12.0</curator.version>
</properties> <dependencies>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>${dubbo.version}</version>
</dependency> <!-- Zookeeper dependencies -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-dependencies-zookeeper</artifactId>
<version>${dubbo.version}</version>
<type>pom</type>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>

我用的Springboot版本是2.2.1,dubbo starter版本是2.7.5,启动之后,发现报错

Caused by: java.lang.: org.apache.curClassNotFoundExceptionator.framework.CuratorFrame

找不到对应的类,看起来是缺少jar了?通过网上资料搜索再加上如下配置即可:

<!-- https://mvnrepository.com/artifact/org.apache.curator/curator-framework -->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>${curator.version}</version>
</dependency> <!-- https://mvnrepository.com/artifact/org.apache.curator/curator-recipes -->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>${curator.version}</version>
</dependency>

curator是Zookeeper配置需要的

maven配置好之后,就可以进行dubbo配置:

#server.port=7010

dubbo.application.name=user-service-provider
dubbo.registry.address=127.0.0.1:2181
dubbo.registry.protocol=zookeeper dubbo.protocol.name=dubbo
dubbo.protocol.port=20882 dubbo.monitor.protocol=registry
#dubbo.scan.base-packages=com.example.springboot.dubbo

用户服务类:

package com.example.springboot.dubbo.service.impl;

import com.example.spring.dubbo.bean.UserAddress;
import com.example.spring.dubbo.service.UserService;
import org.apache.dubbo.config.annotation.Service;
import org.springframework.stereotype.Component; import java.util.Arrays;
import java.util.List; @Service//暴露服务
@Component
public class UserServiceImpl implements UserService { @Override
public List<UserAddress> getUserAddressList(String userId) { UserAddress address1 = new UserAddress(1, "北京市昌平区", "1", "李老师", "010-56253825", "Y");
UserAddress address2 = new UserAddress(2, "深圳市宝安区", "1", "王老师", "010-56253825", "N"); return Arrays.asList(address1,address2);
} }

Springboot的启动类要加上@EnableDubbo注解:

package com.example.springboot.dubbo;

import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; /**
* <pre>
* Springboot启动类
* </pre>
*
* @author nicky
* <pre>
* 修改记录
* 修改后版本: 修改人: 修改日期: 2020年01月05日 修改内容:
* </pre>
*/
@EnableDubbo(scanBasePackages="com.example.springboot.dubbo.service.impl")
@SpringBootApplication
public class UserServiceProviderApplication { public static void main(String[] args) {
SpringApplication.run(UserServiceProviderApplication.class, args);
}
}

启动Springboot类,然后在监控平台是可以看到服务注册成功的



查看服务接口的详细信息:

4.4、服务消费者工程

然后服务已经注册了,现在创建一个消费者工程order-service-comsumer

  • maven加上配置
 <properties>
<spring-boot.version>2.2.1.RELEASE</spring-boot.version>
<dubbo.version>2.7.5</dubbo.version>
<curator.version>2.12.0</curator.version>
</properties> <dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency> <dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>${dubbo.version}</version>
</dependency> <!-- Zookeeper dependencies -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-dependencies-zookeeper</artifactId>
<version>${dubbo.version}</version>
<type>pom</type>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
</exclusions>
</dependency> <!-- https://mvnrepository.com/artifact/org.apache.curator/curator-framework -->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>${curator.version}</version>
</dependency> <!-- https://mvnrepository.com/artifact/org.apache.curator/curator-recipes -->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>${curator.version}</version>
</dependency> <dependency>
<groupId>com.example.springboot</groupId>
<artifactId>shop-api-common</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency> </dependencies>
  • 消费者配置文件:
server.port=8081

dubbo.application.name=order-service-consumer
dubbo.registry.address=zookeeper://127.0.0.1:2181
dubbo.monitor.protocol=registry
  • 订单服务类:
package com.example.springboot.dubbo.service.impl;

import com.example.spring.dubbo.bean.UserAddress;
import com.example.spring.dubbo.service.OrderService;
import com.example.spring.dubbo.service.UserService;
import org.apache.dubbo.config.annotation.Reference;
import org.apache.dubbo.config.annotation.Service; import java.util.List; /**
* <pre>
* 订单服务
* </pre>
*
* @author nicky
* <pre>
* 修改记录
* 修改后版本: 修改人: 修改日期: 2020年01月05日 修改内容:
* </pre>
*/
@Service
public class OrderServiceImpl implements OrderService{
@Reference(loadbalance="random",timeout=1000) //dubbo直连
UserService userService; @Override
public List<UserAddress> initOrder(String userId) {
//1、查询用户的收货地址
List<UserAddress> addressList = userService.getUserAddressList(userId);
return addressList;
}
}
  • Springboot启动
package com.example.springboot.dubbo;

import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; /**
* <pre>
* Springboot启动类
* </pre>
*
* @author nicky
* <pre>
* 修改记录
* 修改后版本: 修改人: 修改日期: 2020年01月05日 修改内容:
* </pre>
*/
@EnableDubbo(scanBasePackages="com.example.springboot.dubbo.service.impl")
@SpringBootApplication
public class OrderServiceProviderApplication { public static void main(String[] args) {
SpringApplication.run(OrderServiceProviderApplication.class, args);
}
}

写一个Controller类进行测试:

package com.example.springboot.dubbo.controller;

import com.example.spring.dubbo.bean.UserAddress;
import com.example.spring.dubbo.service.OrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody; import java.util.List; @Controller
public class OrderController { @Autowired
OrderService orderService; @ResponseBody
@RequestMapping("/initOrder")
public List<UserAddress> initOrder(@RequestParam("uid")String userId) {
return orderService.initOrder(userId);
} }

在监控平台看,消费者启动也是可以的

代码例子下载:github下载链接

SpringBoot系列之集成Dubbo示例教程的更多相关文章

  1. SpringBoot系列之集成Dubbo的方式

    SpringBoot系列之集成Dubbo的方式 本博客介绍Springboot框架集成Dubbo实现微服务的3种常用方式,对于Dubbo知识不是很熟悉的,请先学习我上一篇博客:SpringBoot系列 ...

  2. SpringBoot系列之集成Mybatis教程

    SpringBoot系列之集成Mybatis教程 环境准备:IDEA + maven 本博客通过例子的方式,介绍Springboot集成Mybatis的两种方法,一种是通过注解实现,一种是通过xml的 ...

  3. SpringBoot系列之集成logback实现日志打印(篇二)

    SpringBoot系列之集成logback实现日志打印(篇二) 基于上篇博客SpringBoot系列之集成logback实现日志打印(篇一)之后,再写一篇博客进行补充 logback是一款开源的日志 ...

  4. SpringBoot系列之RabbitMQ使用实用教程

    SpringBoot系列之RabbitMQ使用实用教程 @ 目录 1. 消息队列概述 1.1 MQ的概述 1.2 MQ目的地形式 2. 消息队列实现方式 2.1 常见MQ框架 2.2 MQ实现方式 3 ...

  5. SpringBoot系列之集成jsp模板引擎

    目录 1.模板引擎简介 2.环境准备 4.源码原理简介 SpringBoot系列之集成jsp模板引擎 @ 1.模板引擎简介 引用百度百科的模板引擎解释: 模板引擎(这里特指用于Web开发的模板引擎)是 ...

  6. SpringBoot系列之集成Druid配置数据源监控

    SpringBoot系列之集成Druid配置数据源监控 继上一篇博客SpringBoot系列之JDBC数据访问之后,本博客再介绍数据库连接池框架Druid的使用 实验环境准备: Maven Intel ...

  7. SpringBoot系列之自定义starter实践教程

    SpringBoot系列之自定义starter实践教程 Springboot是有提供了很多starter的,starter翻译过来可以理解为场景启动器,所谓场景启动器配置了自动配置等等对应业务模块的一 ...

  8. SpringBoot系列之集成Thymeleaf用法手册

    目录 1.模板引擎 2.Thymeleaf简介 2.1).Thymeleaf定义 2.2).适用模板 3.重要知识点 3.1).th:text和th:utext 3.2).标准表达式 3.3).Thy ...

  9. SpringBoot系列之日志框架使用教程

    目录 1.SpringBoot日志级别 1).日志级别简介 2).默认日志级别 3).配置日志级别 4).日志分组设置 2.SpringBoot日志格式设置 1).默认格式原理简介 2).默认日志格式 ...

随机推荐

  1. LA 4676 Geometry Problem (几何)

    ACM-ICPC Live Archive 又是搞了一个晚上啊!!! 总算是得到一个教训,误差总是会有的,不过需要用方法排除误差.想这题才几分钟,敲这题才半个钟,debug就用了一个晚上了!TAT 有 ...

  2. part11.2-LED驱动设计

  3. APICloud原生APP中ajax需要用api.ajax

    报错截屏: APICloud原生APP中ajax请求需要用api.ajax(api对象的ajax方法来替代),否则会将引起请求失败. APICloud api.ajax

  4. Android Studio(五):修改Android Studio项目包名

    Android Studio相关博客: Android Studio(一):介绍.安装.配置 Android Studio(二):快捷键设置.插件安装 Android Studio(三):设置Andr ...

  5. LRJ-Example-06-17-Uva10562

    main() 函数中的这两行 fgets(buf[0], maxn, stdin); sscanf(buf[0], "%d", &T); 不能简单替换为 scanf(&qu ...

  6. jq on绑定事件off移除事件

    https://www.cnblogs.com/sandraryan/ 以前用的是bind(); 后来更新后用的on (on() 方法是 bind().live() 和 delegate() 方法的新 ...

  7. java反斜杠替换

    java replaceAll() 方法要用 4 个反斜杠,表示一个反斜杠 例如 str1="aa\bbb"; str2="aa'bbb"; 要想替换成 str ...

  8. html(三)注册页面与重定向

    注册和登陆的建立是通过界面post提交表单然后在测试界面获取提交的值,进行判断. 1.测试传来的值,是否为空,将值传回到测试界面: ("Reg.jsp?errorCode=" + ...

  9. python基础十五之递归函数

    递归函数,在函数中调用自身函数,就会形成一个递归函数.例如: def recursion(n): n += 1 print(n) recursion(n) 由于递归函数的结构,在函数调用时,它会一直调 ...

  10. C# “不支持给定路径的格式”异常处理

    问题背景 无聊研究了一下怎么发送邮件(包含附件),但发现附带的文件路径除了报错就是报错,不知道为什么. 用了不下好几种方式,比如 var x = "E:\\Git\\cmd\\git.exe ...