7.微服务架构简介

微服务架构是 Cloud Native 的重要组成部分,通过拆分服务让每个团队独立负责一个服务,使用固定的 API 接口可以缩小沟通范围,提升团队协作的效率。

微服务架构起源
在软件开发的过程中,通常有如下的需要:

  • 敏捷开发:减少浪费、快速反馈,提升用户体验。
  • 持续交付:更快、更可靠、更频繁的修改软件。
  • 基础设施即代码(Infrastructure As Code):简化环境管理。

正是在这些需求下共同推动了微服务的诞生。

2014 年,Martin Fowler 和 James Lewis 共同提出了微服务的概念,定义:
微服务架构是以开发一组小型服务的方式来开发一个独立的应用系统,每个服务都以一个独立进程的方式运行,每个服务与其他服务使用轻量级(通常是 HTTP API)通信机制。这些服务是围绕业务功能构建的,可以通过全自动部署机制独立部署,同时服务会使用最小规模的集中管理能力(比如 Docker),也可以采用不同的编程语言和数据库。

** 微服务架构起源**
在 Web 应用程序发展早期,大部分的 Web 项目将所有的功能模块打包到一块儿并放到一个容器中运行,这种将所有功能都部署在一个容器中运行的方式就叫做单体架构,如下所示:

单体架构的好处在于一致性实现成本较低,时延性低,在本地测试较为简单,同时对于开发人员的要求、工具的依赖程度以及运维复杂度也会低一些。

相应的单体架构的缺点也很明显:

  • 复杂度高:整个项目耦合度高,修改代码可能随时带来隐藏的 BUG。
  • 技术债务:随着时间的推移,代码会越加难以修改。
  • 拓展能力受限:单体架构只能是应用整体进行拓展,无法结合业务模块实现弹性伸缩。
    语言限制:通常单体架构中的代码都是使用同一语言进行开发,难以引入新的框架或是语言。

正是由于前面提到的这些缺点,对于公司业务发展早期使用单体架构可以快速上线进行验证,随着业务的拓展以及用户量的增加,这个时候往往就会考虑把单体架构拆分为微服务架构,以便实现更好的性能优化。

将前面的单体架构拆分为微服务架构,如下图所示:

采用微服务架构的优势在于:

  • 易于开发和维护:一个微服务只需要关注特定的业务功能,因此业务清晰、代码量较少。开发维护单个的微服务相对而言比较简单,而整个应用都是由多个微服务构建而成,那么整个应用相对来说也比较可控。
  • 业务模块弹性伸缩:可以根据系统负载对具体的业务模块实现弹性伸缩,保证了系统的高可用性。
  • 技术栈不受限:可以结合具体的业务项目和团队特点,自由的选择技术栈。

** 微服务要遵循的设计原则**

  • 垂直划分优先原则:根据业务领域对服务进行垂直划分。
  • 持续演进原则:将单体架构拆分为微服务架构时,可以先将不太重要的功能拆分为一个服务进行实验测试,同时要准备持续交付的工具、微服务框架等,并加强监控。
  • 服务自治、接口隔离原则:设置 API 接口的时候要尽量消除对于其他服务的强依赖,使服务通过标准的 API 接口隔离,隐藏内部实现细节,避免直接访问其他服务的数据库造成强耦合。
  • 自动化驱动原则:构建自动化的工具和环境来解决由于微服务数量增多带来的开发、管理复杂度急剧上升的问题。

微服务 API 设计
API 是服务之间通信的契约,在微服务架构中通过 API 可以忽略服务内部的实现细节,设计合理的 API 接口会降低团队之间的耦合度,加快开发速度。

** 优秀 API 的设计原则**

  • 简单
  • 易懂:可读性好,尽量看到 API 名称就可以读懂代表的含义,如果是提供给第三方开发者的接口要详细的描述参数的取值范围、错误码等。
  • 一致:对于同一个公司、站点提供的 API 风格要统一。
  • 稳定:对于已经在使用中的 API 接口不要轻易的修改,如果必须要修改可以考虑通过增加 API 接口的方式或是明确版本号加以区分。
  • 安全:要考虑超出预期的情况如何处理。
  • 权限:如果提供给第三方需要考虑证书鉴权、租户隔离,并尽量使用 HTTPS 协议进行通信。

服务间通信 RESTful

RESTful(Representational State Transfer 的缩写),可以翻译为“表现层状态转化”,如果一个架构符合 REST 原则,就称它为 RESTful 架构。

符合 RESTful 风格的 API 在设计的时候需要满足哪些要求呢?

协议
API 是基于 HTTP 的协议。

域名
API 需要有一个域名,比如:http://api.xxx.com

版本
API 需要有版本信息。当已发布的服务变更时,可以通过版本号来控制兼容性,比如:http://api.xxx.com/v1/

路径
REST 开发又被称作面向资源的开发,API 要用资源来表示,URL 中不能出现动词。资源(Resource)是服务端可命名的一个抽象概念,主要是为了方便客户端的理解。在这里可以将资源看作是一个实体,比如:用户、邮件、图片等,用 URI(统一资源定位符)指向它。在设计中通常会把资源和数据库表名设计为对应关系,定义资源的时候,推荐使用复数,比如:http://api.xxx.com/v1/users

方法
一般可以使用的方法有如下几种:

  • GET:读取资源,一个或多个(常用)。
  • POST:创建资源(常用)。
  • PUT:修改资源,客户端提供修改后的完整资源(常用)。
  • PATCH:对已知资源进行局部更新,客户端只需要提供改变的属性。
  • DELETE:删除、回收资源(常用)。
  • HEAD:读取资源的元数据(不常用)。
  • OPTIONS:读取对资源的访问权限(不常用)。

通常情况下,使用较多的是:GET、POST、PUT 和 DELETE 方法,其中最最常使用的是 GET 和 POST 方法,比如:GET /users/1 表示获取用户 ID 为 1 的用户信息;GET /users/1/orders 表示获取用户 ID 为 1 的用户的所有订单信息。

参数
参数可以放到 API 路径中,也可以放到 ? 的后面,比如:GET /users/1/orders 和 GET /orders?user_id=1。

编码
RESTful 并没有限制资源的表达格式,但是通常服务端和客户端通过 JSON 传递数据。

状态码
使用 HTTP 状态码传递服务端的状态信息,常用的有:

  • 100:Continue
  • 200:OK,GET
  • 201:Created,POST/PUT/PATCH
  • 202:Accepted
  • 204:No Content,DELETE
  • 400:Bad Request,POST/PUT/PATCH
  • 401:Unauthorized
  • 403:Forbidden
  • 404:Not Found
  • 405:Method Not Allowed
  • 406:Not Acceptable
  • 409:Conflict
  • 410:Gone
  • 412:Precondition Failed
  • 429:Too many requests
  • 500:Internal Server Error
  • 501:Not Implemented
  • 503:Service Unavailable

在设计 API 的时候也要尽量符合以下的约束条件:

单一职责:尽量保持接口职责单一,留给客户端足够的操作空间,来满足不同的业务需求。
幂等性:一次和多次请求某个资源应该具有同样的作用,即使客户端重复发起请求也不会担心因此会造成副作用。
无状态:多次请求之间应该没有状态的耦合,不需要关联过去、现在和将来的请求或响应。
客户端发起:通常通信方式都是由客户端发起,服务端被调用。
原子性:所有操作是一个不可分割的单元,要么全部成功。要么全部失败。
易用:要提供详尽的文档、参数说明、示例,API 定义的 URL、变量名要通俗易懂。

由于 RESTful 通常采用 HTTP+JSON 的方式实现,使得它更加轻量、简单,支持跨语言、容易调试,所以现在 RESTful 已经成为了业界的主流。

原文地址:https://www.cnblogs.com/jasonwu/p/13886909.html