一、架构发展过程

首先,我们先来看看上面的架构发展的线路图:单一应用架构 --> 垂直应用架构 --> 分布式服务架构 --> 流动计算架构 。

单一应用架构

  在一些中小型的传统软件公司中,一个 产品/项目 的所有的代码都在一个工程里,工程下面有多个不同的模块。在部署的时候,将整个工程打包然后放到服务器 Tomcat 下来运行。然后,为了所谓的“高可用”,会使用一台负载均衡服务器(比如Nginx),然后将应用部署到两到三台服务器上。至于系统的依赖可能只有一个,就是类似于 MySQL、Oracle 这类的关系型数据库,会单独部署在一台服务器上,让系统来使用。就如下面这个图:

对于这种单一应用的架构,随着业务量的增长,虽然也可以进行扩展,但是扩展的每台服务器上都部署了所有的功能,假如只需要扩展交易能力而其他模块的功能不需要扩展呢?这种单一架构的系统就没办法解决,所以后面就出现了垂直应用架构。

从研发团队人数的发展来看,这种架构模式也是越来越不靠谱的。如果研发团队有几十人甚至上百人一起研发这个系统,业务逻辑复杂,功能模块多达几十上百个,大家都在一个工程内写代码,大量的冲突以及代码的合并都会让人崩溃。而且测试也会非常痛苦,比如某个功能模块要上线了,就必须得把整个单块系统所有的功能都回归测试一遍才敢上线。因为大家的代码都在一个工程里,都是耦合在一起的,你修改了代码,必须全部测试一遍才能保证系统正常。

垂直应用架构

  随着业务量的增加,单一应用的架构就越来越不适合了,这时候就诞生了垂直应用架构,将整个系统拆成好几个单独的应用,提升了效率,扩容的时候也能够对对应的业务进行精准的扩容。

这种垂直应用架构的模式虽然将每个模块都拆分开了,但是每个模块内部还是有非常多的功能,比如说用户中心当中可能会有:注册、登录、密码校验等等功能,密码校验可能会比注册和登录使用频繁得多,这个时候我们是否要考虑将每一个模块的单体功能再进行拆分,然后就变成了下面这个样子:

当拆分得越来越多,达到几十上百甚至上千个的时候,这种垂直应用架构就不能很好的支撑系统的运行,所以就出现了分布式服务架构。

分布式服务架构


当垂直应用越来越多,应用之间交互不可避免,将核心业务抽取出来,作为独立的服务,逐渐形成稳定的服务中心,使前端应用能更快速的响应多变的市场需求。用于提高业务复用及整合的分布式调用是关键。

二、分布式&集群&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框架:

  • dubbo:Alibaba开发的一个RPC框架,远程接口基于Java Interface, 依托于Spring框架。
  • gPRC:是由Google公司开源的高性能RPC框架。是一个高性能、开源和通用的 RPC 框架,面向移动和 HTTP/2 设计。目前提供 C、Java 和 Go 语言版本
  • thrift:Apache的一个项目(http://thrift.apache.org),前身是Facebook开发的一个RPC框架,采用thrift作为IDL (Interface description language)。
  • brpc:一个基于protobuf接口的RPC框架,在百度内部称为“baidu-rpc”,它囊括了百度内部所有RPC协议,并支持多种第三方协议,从目前的性能测试数据来看,brpc的性能领跑于其他同类RPC产品。

三、Dubbo架构

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

节点角色说明

节点 角色说明
Provider 暴露服务的服务提供方
Consumer 调用远程服务的服务消费方
Registry 服务注册与发现的注册中心
Monitor 统计服务的调用次数和调用时间的监控中心
Container 服务运行容器

调用关系说明

  1. 服务容器负责启动,加载,运行服务提供者。
  2. 服务提供者在启动时,向注册中心注册自己提供的服务。
  3. 服务消费者在启动时,向注册中心订阅自己所需的服务。
  4. 注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。
  5. 服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
  6. 服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。

Dubbo的特点:

连通性

  • 注册中心负责服务地址的注册与查找,相当于目录服务,服务提供者和消费者只在启动时与注册中心交互,注册中心不转发请求,压力较小
  • 监控中心负责统计各服务调用次数,调用时间等,统计先在内存汇总后每分钟一次发送到监控中心服务器,并以报表展示
  • 服务提供者向注册中心注册其提供的服务,并汇报调用时间到监控中心,此时间不包含网络开销
  • 服务消费者向注册中心获取服务提供者地址列表,并根据负载算法直接调用提供者,同时汇报调用时间到监控中心,此时间包含网络开销
  • 注册中心,服务提供者,服务消费者三者之间均为长连接,监控中心除外
  • 注册中心通过长连接感知服务提供者的存在,服务提供者宕机,注册中心将立即推送事件通知消费者
  • 注册中心和监控中心全部宕机,不影响已运行的提供者和消费者,消费者在本地缓存了提供者列表
  • 注册中心和监控中心都是可选的,服务消费者可以直连服务提供者

健壮性

  • 监控中心宕掉不影响使用,只是丢失部分采样数据
  • 数据库宕掉后,注册中心仍能通过缓存提供服务列表查询,但不能注册新服务
  • 注册中心对等集群,任意一台宕掉后,将自动切换到另一台
  • 注册中心全部宕掉后,服务提供者和服务消费者仍能通过本地缓存通讯
  • 服务提供者无状态,任意一台宕掉后,不影响使用
  • 服务提供者全部宕掉后,服务消费者应用将无法使用,并无限次重连等待服务提供者恢复

伸缩性

  • 注册中心为对等集群,可动态增加机器部署实例,所有客户端将自动发现新的注册中心
  • 服务提供者无状态,可动态增加机器部署实例,注册中心将推送新的服务提供者信息给消费者

升级性

当服务集群规模进一步扩大,带动IT治理结构进一步升级,需要实现动态部署,进行流动计算,现有分布式服务架构不会带来阻力。下图是未来可能的一种架构:

节点角色说明

节点 角色说明
Deployer 自动部署服务的本地代理
Repository 仓库用于存储服务应用发布包
Scheduler 调度中心基于访问压力自动增减服务提供者
Admin 统一管理控制台
Registry 服务注册与发现的注册中心
Monitor 统计服务的调用次数和调用时间的监控中心

四、Zookeeper

Dubbo 将注册中心进行抽象,使得它可以外接不同的存储媒介给注册中心提供服务,有ZooKeeper,Memcached,Redis等。

Dubbo的注册、订阅、通知等功能不是由 Dubbo本身来实现的,而是借助于这些存储媒介来实现的。

ZooKeeper的特性

  • 是负载均衡:单注册中心的承载能力是有限的,在流量达到一定程度的时 候就需要分流,负载均衡就是为了分流而存在的,一个 ZooKeeper 群配合相应的Web应用就可以很容易达到负载均衡;
  • 资源同步:单单有负载均衡还不 够,节点之间的数据和资源需要同步,ZooKeeper 集群就天然具备有这样的功能。ZooKeeper 通过心跳机制可以检测挂掉的机器并将挂掉机器的 IP 和服务对应关系从列表中删除;
  • 命名服务:将树状结构用于维护全局的服务地址列表,服务提供者在启动 的时候,向 ZooKeeper 上的指定节点 /dubbo/${serviceName}/providers 目录下写入自己的 URL地址,这个操作就完成了服务的发布。 其他特性还有 Mast 选举,分布式锁等;

五、Dubbo环境搭建

1、Zookeeper

下载

https://mirrors.tuna.tsinghua.edu.cn/apache/zookeeper/

安装

解压安装包,然后将 conf 目录下的 zoo_sample.cfg 改为 zoo.cfg 即可。

启动

进入 Zookeeper 安装目录下的 bin 目录,执行以下命令

./zkServer.sh start

连接

./zkCli.sh -server IP:端口

2、引入依赖

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')

3、创建三个工程

dubbo-order-iface

创建两个实体类 Order 和 RegMsg,以及一个对外提供的接口 IOrderService

@Getter
@Setter
@ToString
public class Order implements Serializable {
private String orderId;
private Integer amount;
private String orderInfo;
}

Order

@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;
}
}

RegMsg

这两个实体类必须实现 Serializable,因为它要在不同的进程之间传输,需要进行序列化和反序列化

public interface IOrderService {

  RegMsg creatOrder(Order order);
}

IOrderService

注意:该工程需单独打包,发到中央仓库,供服务提供方和消费方使用(以 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!!");
}
}

OrderServiceImpl

用 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>

provider.xml

加载 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();
}
}
}

ProviderApp

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>

consumer.xml

加载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);
}
}

ConsumerApp

六、Dubbo配置

1、启动时检查

  • Dubbo 缺省会在启动时检查依赖的服务是否可用,不可用时会抛出异常,阻止 Spring 初始化完成,以便上线时,能及早发现问题,默认 check="true"
  • 可以通过 check="false" 关闭检查,比如,测试时,有些服务不关心,或者出现了循环依赖,必须有一方先启动。
  • 另外,如果你的 Spring 容器是懒加载的,或者通过 API 编程延迟引用服务,请关闭 check,否则服务临时不可用时,会抛出异常,拿到 null 引用,如果 check="false",总是会返回引用,当服务恢复时,能自动连上。

示例:通过Spring 配置文件

关闭某个服务的启动时检查:

<dubbo:reference id="orderService" check="false" interface="com.dubbo.order.iface.service.IOrderService" />

关闭所有服务的启动时检查:

<dubbo:consumer check="false" />

关闭注册中心启动时检查:

<dubbo:registry check="false" />

2、超时重试

<dubbo:reference id="orderService" timeout="" retries="" interface="com.dubbo.order.iface.service.IOrderService" />

上面配置了超时时间为3秒,重试3次,如果一直超时,会请求四次。

我们配置超时和重试前,下面这些情况是要充分考虑的

超时:

对外提供的服务,超时时间设的比较长,实际情况却是:服务时间出现抖动,外部连接比较多,可能会把该服务给拖垮(瞬间有大量的连接进来,但是服务又消化不掉)。所以超时时间的设置应该充分考虑整个链路的时间。

重试:

对外提供的服务,是否应该支持重试,是否有必要重试。比如说:订单业务,重试也不能造成重复下单,要做好内部唯一性校验,要做到完全相同的请求在数据库的落地只有一单。

七、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!!!");
}
}

OrderServiceImpl

用 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

application.yml

加载 Springboot 配置

@SpringBootApplication
@EnableDubbo
public class ProviderApplication { public static void main(String[] args) {
SpringApplication.run(ProviderApplication.class, args);
}
}

ProviderApplication

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);
}
}

OrderController

通过 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

application.yml

注意:consumer的端口要和provider不一样

加载Springboot配置,并调用远程服务

@SpringBootApplication
@EnableDubbo
public class ConsumerApplication { public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class, args);
}
}

ConsumerApplication

Dubbo ==> 简介的更多相关文章

  1. dubbo入门学习 三 dubbo简介

    http://dubbo.apache.org/zh-cn/docs/user/references/protocol/dubbo.html Dubbo简介 1. Dubbo:一个分布式.高性能.透明 ...

  2. Dubbo简介与基本概念

    场景 分布式系统的发展演变以及RPC简介: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/103555049 Dubbo简介 Ap ...

  3. Dubbo简介---搭建一个最简单的Demo框架

    Dubbo背景和简介 Dubbo开始于电商系统,因此在这里先从电商系统的演变讲起. 单一应用框架(ORM) 当网站流量很小时,只需一个应用,将所有功能如下单支付等都部署在一起,以减少部署节点和成本.  ...

  4. (一)Dubbo简介

    Dubbo是阿里巴巴公司开源的一个高性能优秀的服务框架,使得应用可通过高性能的 RPC 实现服务的输出和输入功能,可以和Spring框架无缝集成.具体可以看 百度百科 https://baike.ba ...

  5. Dubbo简介2

    Dubbo是阿里巴巴公司开源的一个高性能优秀的服务框架,使得应用可通过高性能的 RPC 实现服务的输出和输入功能,可以和Spring框架无缝集成.具体可以看 百度百科 https://baike.ba ...

  6. 2、Spring Cloud和dubbo简介

    1.Spring Cloud简介 (1).Spring Cloud简介 SpringCloud,基于SpringBoot提供了一套微服务解决方案,包括服务注册与发现,配置中心,全链路监控,服务网关,负 ...

  7. dubbo源码—dubbo简介

    dubbo是一个RPC框架,应用方像使用本地service一样使用dubbo service.dubbo体系架构 上图中的角色: 最重要的是consumer.registry和provider con ...

  8. Dubbo简介

    1. Dubbo是什么? Dubbo是一个分布式服务框架,致力于提供高性能和透明化的RPC远程服务调用方案,以及SOA服务治理方案.简单的说,dubbo就是个服务框架,如果没有分布式的需求,其实是不需 ...

  9. Dubbo简介及实例

    节点角色说明: Ø  Provider: 暴露服务的服务提供方. Ø  Consumer: 调用远程服务的服务消费方. Ø  Registry: 服务注册与发现的注册中心. Ø  Monitor: 统 ...

  10. Dubbo简介与使用

    1:Dubbo是什么 阿里生产的一种rpc 实现框架  Dubbo 是一个分布式服务框架,是阿里巴巴开源项目 ,被国内电商及互联网项目中使用. Dubbo 致力于提供高性能和透明化的RPC远程服务调用 ...

随机推荐

  1. JS继承的原理、方式和应用

    概要: 一.继承的原理 二.继承的几种方式 三.继承的应用场景 什么是继承? 继承:子类可以使用父类的所有功能,并且对这些功能进行扩展.继承的过程,就是从一般到特殊的过程.要了解JS继承必须首先要了解 ...

  2. vue-cli3项目中使用CDN

    1.html 中引入 echarts         html中添加script标签如下:         <script src="//cdn.bootcss.com/echarts ...

  3. 模块化开发之Amd规范和Cmd规范

    CMD规范:是SeaJS 在推广过程中对模块定义的规范化产出的. AMD规范:是 RequireJS 在推广过程中对模块定义的规范化产出的 // CMD define(function(require ...

  4. 嵌入式系统FreeRTOS — 互斥信号量

    互斥信号量可以在资源保护的时候很有帮助.用于控制在两个或多个任务间访问共享资源.任务1里面用互斥,那么任务2只能等任务1访问完再访问同一个变量. 比如全局变量double gADC_value[CH_ ...

  5. smarty模板使用

    安装配置 下载smarty模板核心类库,把libs文件夹复制到项目文件夹下,修改为smarty在php文件中调用 require '../smarty/Smarty.class.php';$tpl = ...

  6. vue cli 3.x 配置使用 sourceMap

    项目使用vue cli 3.x搭建,没有了配置文件,如何更方便的查找到对应的scss文件,配置项目支持sourceMap方式? 分二步走: 1.项目根目录(不是src目录,不要搞错了)添加vue.co ...

  7. [Luogu] 维护序列

    https://www.luogu.org/problemnew/show/P2023 线段树双懒标记下放 #include <bits/stdc++.h> using namespace ...

  8. CoreText学习(二)之Hello world

    最后更新:2017-08-10 部分内容丢失,后续补上 相关配置: Xcode 8.3.3 Swift 3.0 macOS Sierra 一.CoreText 简介 CoreText 是用于处理文字和 ...

  9. HDU 3689 Infinite monkey theorem ——(自动机+DP)

    这题由于是一个单词,其实直接kmp+dp也无妨.建立自动机当然也是可以的.设dp[i][j]表示匹配到第i个字母的时候,在单词中处于第j个位置的概率,因此最终的答案是dp[0~m][len],m是输入 ...

  10. [51nod1789] 跑得比谁都快

    题面 题解 设\(f[i]\)为根节点到\(i\)的最小耗时 设\(S\)为\(i\)的祖先集合, 可以得到 \[ f[i] = min(f[j] + (i - j)^p),j \in S \] 对于 ...