Skip to content

Latest commit

 

History

History
117 lines (75 loc) · 7.14 KB

01.微服务架构.md

File metadata and controls

117 lines (75 loc) · 7.14 KB

01.微服务架构

  • 什么是微服务
  • 面向微服务的架构
  • 关键的好处
  • SOA与微服务的比较
  • 为什么选择Node.js

单块软件

大多数公司都只有两个大的软件组件:面向用户的网站和内部的管理系统。我们通常将这种架构方式称为单块软件架构。

将庞大的单块系统拆分成微服务可以让工程团队创造出互相隔离且独立自治的工作单元。这些工作单元从功能上来说都是高度专职化的,例如可以专职处理电子邮件的发送、支付卡交易等特定任务。

专职化通常是提升效率的关键。做一件事并将它做对是软件开发的准则之一。

如今,数以百计的系统都采用了面向微服务的架构来构建,我们来看看:

  • Netflix是时下最流行的流媒体服务商之一,它构建了囊括自身所有应用的整个生态系统,这些应用互相协作,从而构建出能为全球范围提供可靠和可伸缩服务的流媒体系统。
  • Spotify是世界领先的音乐流媒体服务商,它采用了微服务来构建应用。它的应用(该应用是一个采用Chromium Embedded Framework实现的以桌面方式呈现的网站)中的每个单独的小部件都是一个可以独立升级的微服务。

不足之处

事无绝对,周遭也存在着一些针对面向微服务架构的诟病。大家都提到了一些需要处理的问题,例如:延迟、可追踪性以及在单块软件中并不存在的配置管理的问题。其中一些问题描述如下。

  • 网络延迟: 微服务具有分布式的特性,从而无可避免地会存在网络延迟。
  • 运维负担: 更多的服务器也意味着需要更多的维护工作。
  • 最终一致性: 在一个对事务性要求较高的系统中,考虑到实现的局限性,各个节点在某一段时间内可能会出现数据不一致。

关键设计原则

  • 微服务是一系列参考公司流程模型而分拆出来的业务单元。
  • 它们是一系列包含了业务逻辑并能采用简单信道和协议与之进行通信的智能端点。
  • 根据定义,面向微服务的架构是去中心化的,从而可以构建出健壮和具有弹性的软件。

从组件到业务单元

保持较低的耦合度得以让我们毫不费力地将软件组件转换成微服务。

让我们来看一个实际的例子:公司的应用目前急需处理支付的功能。

通常我们会为此创建一个新的模块,该模块可以处理与所选支付厂商(例如信用卡、PayPal等)之间的相关事务,然后会将所有与支付相关的业务逻辑封装在该模块中。定义的接口代码如下:

public interface PaymentService {
  PaymentResponse processPayment(PaymentRequest request) throws MyBusinessException;
}

这是一个大家都能理解的简单接口,而它却是通往微服务世界的关键。我们已经将所有的业务知识封装在该接口背后,所以理论上可以任意切换支付厂商而不会影响应用的其他部分。对外面的世界来说,接口内部的实现细节是不可见的。

到目前为止我们掌握了如下信息:

  • 我们知道方法名,因此也知道如何调用服务。
  • 该方法会抛出MyBusinessException类型的异常,这强制了调用代码要处理该异常。
  • 还了解到输入的参数是一个PaymentRequest类型的实例。
  • 响应也是一个已知的对象。

我们已经创建了一个高内聚、低耦合的业务单元。下面来对该论断进行证明。

  • 高内聚: 所有支付模块内的代码只做了一件事,就是处理支付以及调用第三方服务(比如信用卡处理器)相关的事项(连接处理、响应代码等)。
  • 低耦合: 如果出于某些原因,需要切换到一个新的支付处理器会怎么样?接口本身是否会泄露出任何实现细节的信息?如果接口的契约发生了变化,是否需要更改调用服务的代码?这些问题的答案当然是否定的。支付服务接口的实现将永远是一个模块化的工作单元。

去中心化

微服务的目标是去中心化。相比于构建超大的数据库,它选择根据前文提到的业务单元来对数据进行拆分。

一些读者会将事务性作为主要的理由从而拒绝使用微服务。先来看看下面的场景:

  1. 一个客户在面向微服务的网店中购买了一件商品。
  2. 当进入支付环节时,系统发出了如下调用:
    1. 向公司的财务系统发起请求,创建了一个支付的事务。
    2. 向仓储系统发起请求,通知对客户购买的书籍进行发货操作。
    3. 向邮件系统发起请求,为客户订阅新闻邮件。

在一个单块软件中,所有的调用都被包装在一个事务中。因此,如果有某些原因导致任何一个调用失败,其他调用涉及的所有数据都不会持久化到数据库中。

当你开始学习数据库设计时,首先接触到的一个重要原则便是ACID,它是以下四个属性的缩写。

  • 原子性: 每一个事务要么全部生效,要么全部回滚。只要有一部分失败,不会有任何变更持久化到数据库中。
  • 一致性: 事务中产生的数据变更会得到一致性保证。
  • 隔离性: 事务并发执行产生的系统状态将与事务串行执行产生的状态保持一致。
  • 持久性: 一旦事务被提交,数据将被持久化。

常规而言,微服务应该小到足够在一个sprint之内完成开发。

易于部署

微服务应当易于部署。原因如下:

  • 少量的业务逻辑(从经验上来说是只需两周即可完成从无到有的编写)导致更易于部署。
  • 微服务是自治的工作单元,所以升级一个服务对于复杂系统来说是一个局部可控的问题。无须重新部署整个系统。
  • 微服务架构中的基础设施和配置应该尽可能自动化。

SOA与微服务的比较

微服务是细粒度的SOA组件。换句话说,某单个SOA组件可以被拆成多个微服务,而这些微服务通过分工协作,可以提供与原SOA组件相同级别的功能。

微服务是细粒度的SOA组件,它们是关注点更窄的轻量级服务。

除了技术栈与服务规模之外,在SOA与微服务之间还有一个更大的区别:领域模型。在本章前面的内容中,我们曾讨论过去中心化。有管理的去中心化,也有数据的去中心化。在一个基于微服务的软件中,每个微服务应该在本地存储自身管理的数据,并将领域模型分别隔离到单个服务中。而在面向SOA的软件中,数据往往存储在单个大型的数据库中,服务之间会共享领域模型。

为什么选择Node.js

Node.js是用来构建面向微服务的架构的绝佳选择,原因如下:

  • 学习门槛低(但是如果想要精通还是有一定门槛的)
  • 易于扩展
  • 对测试友好
  • 易于部署
  • 可以通过npm进行依赖管理
  • 有着大量与主流标准协议相集成的库

API聚合

Seneca的一个最吸引人的特性就是API聚合。API聚合是一项用于将不同功能(插件、方法等)组合成一个接口的高级技术。

展望Node.js