1、架构发展过程前端
首先,咱们先来看看上面的架构发展的线路图:单一应用架构 --> 垂直应用架构 --> 分布式服务架构 --> 流动计算架构 。web
单一应用架构算法
在一些中小型的传统软件公司中,一个 产品/项目 的全部的代码都在一个工程里,工程下面有多个不一样的模块。在部署的时候,将整个工程打包而后放到服务器 Tomcat 下来运行。而后,为了所谓的“高可用”,会使用一台负载均衡服务器(好比Nginx),而后将应用部署到两到三台服务器上。至于系统的依赖可能只有一个,就是相似于 MySQL、Oracle 这类的关系型数据库,会单独部署在一台服务器上,让系统来使用。就以下面这个图:spring
对于这种单一应用的架构,随着业务量的增加,虽然也能够进行扩展,可是扩展的每台服务器上都部署了全部的功能,假如只须要扩展交易能力而其余模块的功能不须要扩展呢?这种单一架构的系统就没办法解决,因此后面就出现了垂直应用架构。 数据库
从研发团队人数的发展来看,这种架构模式也是愈来愈不靠谱的。若是研发团队有几十人甚至上百人一块儿研发这个系统,业务逻辑复杂,功能模块多达几十上百个,你们都在一个工程内写代码,大量的冲突以及代码的合并都会让人崩溃。并且测试也会很是痛苦,好比某个功能模块要上线了,就必须得把整个单块系统全部的功能都回归测试一遍才敢上线。由于你们的代码都在一个工程里,都是耦合在一块儿的,你修改了代码,必须所有测试一遍才能保证系统正常。apache
垂直应用架构编程
随着业务量的增长,单一应用的架构就愈来愈不适合了,这时候就诞生了垂直应用架构,将整个系统拆成好几个单独的应用,提高了效率,扩容的时候也可以对对应的业务进行精准的扩容。缓存
这种垂直应用架构的模式虽然将每一个模块都拆分开了,可是每一个模块内部仍是有很是多的功能,好比说用户中心当中可能会有:注册、登陆、密码校验等等功能,密码校验可能会比注册和登陆使用频繁得多,这个时候咱们是否要考虑将每个模块的单体功能再进行拆分,而后就变成了下面这个样子:tomcat
当拆分得愈来愈多,达到几十上百甚至上千个的时候,这种垂直应用架构就不能很好的支撑系统的运行,因此就出现了分布式服务架构。springboot
分布式服务架构
当垂直应用愈来愈多,应用之间交互不可避免,将核心业务抽取出来,做为独立的服务,逐渐造成稳定的服务中心,使前端应用能更快速的响应多变的市场需求。用于提升业务复用及整合的分布式调用是关键。
2、分布式&集群&RPC
分布式:一个电商系统,用户模块部署在 Server1, 订单模块部署在 Server2, 促销模块部署在 Server3, 商品模块部署在 Server4,他们之间经过远程rpc实现服务调用,这就叫分布式。强调的是不一样功能模块,单独部署在不一样的 Server 上,全部 Server 加起来是一个完整的系统。
集群:更多强调的是灾备,一个电商系统,完整的部署在Server1上一个,完整的部署在Server2上一个,Server1宕机后,Server2仍然能够正常提供请求服务,这叫集群。一样对于某一功能模块,好比用户模块部署在 Server1上,一样部署在 Server2上,也叫作集群。分布式系统的每一个功能模块节点,均可以用多机作成集群。
RPC:Remote Procedure Call,远程过程调用,它是一种经过网络从远程计算机程序上请求服务,而不须要了解底层网络技术的协议。举个例子说明:两台服务器 A、B,分别部署不一样的应用 a 和 b。当A服务器上的应用 a 想要调用B服务器上的应用 b 提供的方法的时候,因为不在一个内存空间,不能直接调用,须要经过网络来表达调用的语义传达调用的数据,这个时候就出现了一个远程服务调用的概念。
常见RPC框架:
3、Dubbo架构
Dubbo是一款高性能、轻量级的开源Java RPC框架,它提供了三大核心能力:面向接口的远程方法调用,智能容错和负载均衡,以及服务自动注册和发现。
节点角色说明
节点 | 角色说明 |
---|---|
Provider |
暴露服务的服务提供方 |
Consumer |
调用远程服务的服务消费方 |
Registry |
服务注册与发现的注册中心 |
Monitor |
统计服务的调用次数和调用时间的监控中心 |
Container |
服务运行容器 |
调用关系说明
Dubbo的特色:
连通性
健壮性
伸缩性
升级性
当服务集群规模进一步扩大,带动IT治理结构进一步升级,须要实现动态部署,进行流动计算,现有分布式服务架构不会带来阻力。下图是将来可能的一种架构:
节点角色说明
节点 | 角色说明 |
---|---|
Deployer |
自动部署服务的本地代理 |
Repository |
仓库用于存储服务应用发布包 |
Scheduler |
调度中心基于访问压力自动增减服务提供者 |
Admin |
统一管理控制台 |
Registry |
服务注册与发现的注册中心 |
Monitor |
统计服务的调用次数和调用时间的监控中心 |
4、Zookeeper
Dubbo 将注册中心进行抽象,使得它能够外接不一样的存储媒介给注册中心提供服务,有ZooKeeper,Memcached,Redis等。
Dubbo的注册、订阅、通知等功能不是由 Dubbo自己来实现的,而是借助于这些存储媒介来实现的。
ZooKeeper的特性
5、Dubbo环境搭建
一、Zookeeper
下载
https://mirrors.tuna.tsinghua.edu.cn/apache/zookeeper/
安装
解压安装包,而后将 conf 目录下的 zoo_sample.cfg 改成 zoo.cfg 便可。
启动
进入 Zookeeper 安装目录下的 bin 目录,执行如下命令
./zkServer.sh start
链接
./zkCli.sh -server IP:端口
二、引入依赖
compile('com.alibaba:dubbo:2.6.6') compile('io.netty:netty-all:4.1.34.Final') compile('org.apache.zookeeper:zookeeper:3.4.14') compile('org.apache.curator:curator-framework:2.13.0') compile('org.apache.curator:curator-recipes:2.13.0')
三、建立三个工程
dubbo-order-iface
建立两个实体类 Order 和 RegMsg,以及一个对外提供的接口 IOrderService
@Getter @Setter @ToString public class Order implements Serializable { private String orderId; private Integer amount; private String orderInfo; }
@Getter @Setter @ToString public class RegMsg implements Serializable { private String errorNo; private String errorMsg; public RegMsg(String errorNo, String errorMsg) { this.errorNo = errorNo; this.errorMsg = errorMsg; } }
这两个实体类必须实现 Serializable,由于它要在不一样的进程之间传输,须要进行序列化和反序列化
public interface IOrderService { RegMsg creatOrder(Order order); }
注意:该工程需单独打包,发到中央仓库,供服务提供方和消费方使用(以 jar 包的方式引入)
dubbo-order-provider(服务提供者)
服务提供者实现 IOrderService 接口
public class OrderServiceImpl implements IOrderService { @Override public RegMsg creatOrder(Order order) { System.out.println("OrderServiceImpl -> create order: " + order); return new RegMsg("200","create order success!!"); } }
用 Spring 配置声明暴露服务
<?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://dubbo.apache.org/schema/dubbo" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd"> <!-- 提供方应用信息,用于计算依赖关系 --> <dubbo:application name="dubbo-order-provider" /> <!-- 使用zookeeper注册中心暴露服务地址 --> <dubbo:registry address="zookeeper://192.168.182.128:2181" /> <!-- 用dubbo协议在20880端口暴露服务 --> <dubbo:protocol name="dubbo" port="20880" /> <!-- 和本地bean同样实现服务 --> <bean id="orderService" class="com.dubbo.order.provider.service.OrderServiceImpl" /> <!-- 声明须要暴露的服务接口 --> <dubbo:service interface="com.dubbo.order.iface.service.IOrderService" ref="orderService" /> </beans>
加载 Spring 配置
public class ProviderApp { public static void main(String[] args) { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("provider.xml"); context.start(); try { // 按任意键退出 System.in.read(); } catch (IOException e) { e.printStackTrace(); } } }
dubbo-order-consumer(服务消费者)
经过 Spring 配置引用远程服务
<?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://dubbo.apache.org/schema/dubbo" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd"> <!-- 消费方应用名,用于计算依赖关系,不是匹配条件,不要与提供方同样 --> <dubbo:application name="dubbo-order-consumer" /> <!-- 使用zookeeper注册中心暴露发现服务地址 --> <dubbo:registry address="zookeeper://192.168.182.128:2181" /> <!-- 生成远程服务代理,能够和本地bean同样使用demoService --> <dubbo:reference id="orderService" interface="com.dubbo.order.iface.service.IOrderService" /> </beans>
加载Spring配置,并调用远程服务
public class ConsumerApp { public static void main(String[] args) throws Exception { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("consumer.xml"); context.start(); // 获取远程服务代理 IOrderService orderService = context.getBean("orderService", IOrderService.class); Order order = new Order(); order.setOrderId("1"); order.setAmount(1024); order.setOrderInfo("dubbo create order"); // 执行远程方法 RegMsg regMsg = orderService.creatOrder(order); // 显示调用结果 System.out.println("regMsg = " + regMsg); } }
6、Dubbo配置
一、启动时检查
check="true"
。check="false"
关闭检查,好比,测试时,有些服务不关心,或者出现了循环依赖,必须有一方先启动。check="false"
,老是会返回引用,当服务恢复时,能自动连上。示例:经过Spring 配置文件
关闭某个服务的启动时检查:
<dubbo:reference id="orderService" check="false" interface="com.dubbo.order.iface.service.IOrderService" />
关闭全部服务的启动时检查:
<dubbo:consumer check="false" />
关闭注册中心启动时检查:
<dubbo:registry check="false" />
二、超时重试
<dubbo:reference id="orderService" timeout="3000" retries="3" interface="com.dubbo.order.iface.service.IOrderService" />
上面配置了超时时间为3秒,重试3次,若是一直超时,会请求四次。
咱们配置超时和重试前,下面这些状况是要充分考虑的
超时:
对外提供的服务,超时时间设的比较长,实际状况倒是:服务时间出现抖动,外部链接比较多,可能会把该服务给拖垮(瞬间有大量的链接进来,可是服务又消化不掉)。因此超时时间的设置应该充分考虑整个链路的时间。
重试:
对外提供的服务,是否应该支持重试,是否有必要重试。好比说:订单业务,重试也不能形成重复下单,要作好内部惟一性校验,要作到彻底相同的请求在数据库的落地只有一单。
7、SpringBoot整合Dubbo
一样是下面建立三个工程
dubbo-order-iface
这个工程和上面的同样,没有变化
dubbo-springboot-provider
引入依赖
dependencies { compile project(':dubbo-order-iface') // dubbo须要的starter compile('com.alibaba.spring.boot:dubbo-spring-boot-starter:2.0.0') implementation('org.springframework.boot:spring-boot-starter-web') implementation('org.springframework.boot:spring-boot-starter-aop') testImplementation('org.springframework.boot:spring-boot-starter-test') }
服务提供者实现 IOrderService 接口
@org.springframework.stereotype.Service @com.alibaba.dubbo.config.annotation.Service public class OrderServiceImpl implements IOrderService { @Override public RegMsg creatOrder(Order order) { System.out.println("springboot OrderServiceImpl->createOrder, order=" + order); return new RegMsg("3000", "create success!!!"); } }
用 yml文件配置声明暴露服务
server: port: 8001 servlet: context-path: /provider tomcat: accesslog: enabled: true dubbo: application: name: dubbo-springboot-provider registry: address: 192.168.182.128:2181 protocol: zookeeper protocol: name: dubbo port: 20880
加载 Springboot 配置
@SpringBootApplication @EnableDubbo public class ProviderApplication { public static void main(String[] args) { SpringApplication.run(ProviderApplication.class, args); } }
dubbo-springboot-consumer
引入依赖
dependencies { compile project(':dubbo-order-iface') // dubbo须要的starter compile('com.alibaba.spring.boot:dubbo-spring-boot-starter:2.0.0') implementation('org.springframework.boot:spring-boot-starter-web') implementation('org.springframework.boot:spring-boot-starter-aop') testImplementation('org.springframework.boot:spring-boot-starter-test') }
实现一个 Controller 调用方法
@Slf4j @RestController @RequestMapping("/order") public class OrderController { @Reference private IOrderService orderService; @RequestMapping("/createOrder") public RegMsg createOrder(Integer amount) { log.info("createOrder start. amount={}", amount); Order order = new Order(); order.setAmount(amount); order.setOrderInfo("time:" + LocalDateTime.now()); order.setOrderId(System.currentTimeMillis() + ""); return orderService.creatOrder(order); } }
经过 yml文件配置引用远程服务
server: port: 8002 servlet: context-path: /consumer tomcat: accesslog: enabled: true dubbo: application: name: dubbo-springboot-consumer registry: address: 192.168.182.128:2181 protocol: zookeeper
注意:consumer的端口要和provider不同
加载Springboot配置,并调用远程服务
@SpringBootApplication @EnableDubbo public class ConsumerApplication { public static void main(String[] args) { SpringApplication.run(ConsumerApplication.class, args); } }