《分布式系统原理与范型》定义:
“分布式系统是若干独立计算机的集合,这些计算机对于用户来讲就像单个相关系统”
分布式系统(distributed system)是创建在网络之上的软件系统。java
架构的发展是由最初的单一应用架构构建的,通常就是ORM框架方便数据库操做。linux
不过随着系统愈来愈复杂,单一应用架构会变得难以维护,因此架构逐渐演变出了垂直应用架构,所谓垂直应用架构其实就是安装业务模板进行拆分,好比能够安装业务将一个电商系统分为订单模块,用户信息管理模块,商品管理模块等等,这时候MVC框架就派上用场,MVC框架能够协助系统更好的按业务拆分,不过业务拆分后虽然是比单一应用架构更好维护了。git
不过随着系统越来约复杂,发现不少共用的模块很难复用起来,这时候分布式服务架构登场了,分布式架构是将一些核心业务抽取出来,做为独立的服务,逐渐造成稳定的服务中心,当应用须要时,就去服务中心调服务就能够,而实现这种服务注册的确定是RPC框架了。程序员
当服务愈来愈多,容量的评估,小服务资源的浪费等问题逐渐显现,此时需增长一个调度中心基于访问压力实时管理集群容量,提升集群利用率,这时候就须要流动计算架构(SOA)[ Service Oriented Architecture],用于提升机器利用率的资源调度,SOA是一个治理中心,综上所述,到目前,软件系统架构演变经历了:单一应用架构->垂直应用架构->分布式应用架构->流动计算架构,下面Dubbo官网的图片能够很好的描述
github
RPC概念
RPC【Remote Procedure Call】是指远程过程调用,是一种进程间通讯方式,他是一种技术的思想,而不是规范。它容许程序调用另外一个地址空间(一般是共享网络的另外一台机器上)的过程或函数,而不用程序员显式编码这个远程调用的细节。web
RPC核心模块
RPC有两个核心模块:通讯和序列化算法
Apache Dubbo (incubating) |ˈdʌbəʊ| 是一款高性能、轻量级的开源Java RPC框架,它提供了三大核心能力:面向接口的远程方法调用,智能容错和负载均衡,以及服务自动注册和发现。spring
官网:
http://dubbo.apache.org/数据库
Dubbo的服务治理:
apache
Dubbo原理图片,图片来自Dubbo官网:
Dubbo角色:
Provider:暴露服务的服务提供者
Container:服务运行的容器
Consumer:调用远程服务的消费者
Registry:服务注册和发现的注册中心
Minitor:统计服务调用次数和时间的监控中心
调用过程:
下面根据个人理解说明一下
0:服务器容器负责启动、加载、运行服务提供者
1:服务提供者在启动后就能够向注册中心暴露服务
2:服务消费者在启动后就能够向注册中心订阅想要的服务
3:注册中心向服务消费者返回服务调用列表
4:服务消费者基于软负载均衡算法调用服务提供者的服务,这个服务提供者有多是一个服务提供者列表,调用那个服务提供者就是根据负载均衡来调用了
5:服务提供者和服务消费者定时将保存在内存中的服务调用次数和服务调用时间推送给监控中心
搭建Zookeeper,首先是搭建分布式架构的注册中心Zookeeper,固然也能够用Redis等等来作服务注册中心,不过本博客只介绍Zookeeper的,由于没有linux服务器,因此只介绍window版的搭建
一、下载Zookeeper:
网址 https://archive.apache.org/dist/zookeeper/zookeeper-3.4.13/
三、配置Zookeeper
由于Zookeeper的conf文件夹下面只提供zoo_sample.cfg文件,须要本身修改命名为zoo.cfg
对于配置文件须要注意:
dataDir=./ 临时数据存储的目录(可写相对路径)
clientPort=2181 zookeeper的端口号
ok,简单在zkCli.cmd敲几个命令测试一下:
ls /:列出zookeeper根下保存的全部节点
create –e /testNode 12345678:建立一个testNode节点,值为12345678
get /testNode:获取/testNode节点的值
搭建了服务注册中心后,就须要搭建Dubbo-admin了,最近看了一下,dubbo的Github项目已经进行了更新,管理平台已经作了比较大的改动,而我学习的时候,平台是比较简单的,因此本dubbo-admin搭建是以旧版master的为准,不过以学习为目的的,只须要知道具体原理和操做技巧就能够
由于我搭建时候(ps:不是博客写做时间),dubbo还没作比较大改动,因此我以比较旧的版本为例子,如今新的具体参考dubbo官方的教程,本博客只是作记录
修改 src\main\resources\application.properties 指定zookeeper地址
mvn clean package -Dmaven.test.skip=true
maven打包以后,就去target里找到jar,而后cmd运行
java -jar dubbo-admin-0.0.1-SNAPSHOT.jar
运行成功以后,访问: http://127.0.0.1:7001,输入默认的帐号密码root/root,登陆成功
经典例子(引用尚硅谷教程例子进行改写):
某个电商系统,订单服务须要调用用户服务获取某个用户的全部地址;
咱们如今 须要建立两个服务模块进行测试
模块 | 功能 |
---|---|
订单服务模块 | 建立订单等 |
用户服务模块 | 查询用户地址等 |
建立工程:
建议将服务接口,服务模型,服务异常等均放在 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工程
要实现服务提供,配置文件主要须要配置以下:
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类,而后在监控平台是能够看到服务注册成功的
查看服务接口的详细信息:
而后服务已经注册了,如今建立一个消费者工程order-service-comsumer
<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) { //一、查询用户的收货地址 List<UserAddress> addressList = userService.getUserAddressList(userId); return addressList; } }
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下载连接