读《Chris Richardson 微服务系列》

阅读文章来自DaoCloud:http://blog.daocloud.io/microservices-1/

微服务架构概念解析

单体应用释义:

应用的核心是商业逻辑,它由定义服务、域对象和事件各模块来完成。各种适配器围绕核心与外部交互。适配器包括数据库访问组件、生成和 consume 信息的消息组件,以及提供 API 或者 UI 访问支持的 web 模块。

优点:

  • 易于构建、部署
  • 容易测试
  • 横向拓展,负载均衡方便

缺点:

  • 系统复杂:内部多模块紧密耦合,关联依赖复杂
  • 运维困难:代码量巨大,没有人能理解整个应用,bug修复困难。任何修改都必须重启整个应用。
  • 无法拓展:不能拆分部署,出现性能瓶颈往往只能增加服务器或集群节点。但是DB问题无法解决。

微服务释义:

一个微服务一般==完成某个特定的功能== ,比如订单管理、客户管理等。每个微服务都是一个微型应用,==有着自己六边形架构==,包括商业逻辑和各种接口。有的微服务通过暴露 API 被别的微服务或者应用客户端所用;有的微服务则通过网页 UI 实现。

与SOA区别:

  • 不包含网络服务说明(WS-*)
  • 不包含Enterprise Service Bus(ESB)

优点:

  1. scale cube的3D模型
  • Y轴:应用分解,即将传统的单体应用分解为多个微服务应用
  • X轴:负载均衡实现水平弹性拓展,但DB问题无法解决,引入3
  • Z轴:DB弹性拓展,引入数据库拆分和Daas
  1. 引用分解后,单应用复杂度降低。每个服务都有一个RPC 或者消息驱动API,边界清晰。
  2. 单应用可以自由选择开发技术,不必受某些早起技术影响。甚至重构代码也相对简单。
  3. 服务单独部署,不需要协调其他服务部署。加快部署速度。
  4. 单服务对于性能消耗更明确,利于优化硬件资源配置。

缺点:

  1. 微服务应用是分布式系统,由此带来固有复杂性
    1. 通讯机制:RPC或消息传递
      1. 通讯速度慢
      2. 服务不可用
      3. 通讯超时
  2. CAP原则:分布式事务一致性,业务实现复杂度提高
  3. 集成复杂:任何吃滴的分解都将带来集成的复杂度
  4. 部署:部署节点多,还涉及部署后的配置、拓展、监控问题

使用API网关构建微服务

客户端与微服务交互方式。

单体应用只需要发起一次请求,就能拿到所有需要的信息;

微服务需要发起多次请求,调用不同微服务提供的API。

发现问题:

  • 客户端需求和每个微服务暴露的细粒度API不匹配
  • 部分服务使用的协议对web并不友好
  • 重构困难:系统拆分、合并,涉及外部改造。困难重重

使用API网关的架构:

API网关职责:请求路由、组合、协议转换

  • 外部调用API,网关调用多个微服务并合并结果
  • 处理内部服务,与外部调用协议不匹配问题
  • 根据外部不同设备,设计不同API

优点:

  • 封装了应用程序内部,简化外部调用

缺点:

  • 增加了一个必须开发、部署、维护的高可用组件
  • API网关变成了开发瓶颈

实现API网关

  1. 性能和可拓展性
    1. 构建在一个支持异步、I/O非阻塞的平台
      1. JVM上的NIO框架,例如:netty、vertx、spring reactor等
      2. node.js
    2. 另一种方法,使用nginx plus提供的成熟的、可拓展的、高性能web服务器和一个易于部署的、可配置、可编程的反向代理
      1. 身份验证
      2. 访问控制
      3. 负载均衡
      4. 缓存响应
      5. 提供程序可感知的健康检查、监控
  2. 使用响应式编程模型
    1. 独立请求
    2. 组合请求:代码复杂
    3. 响应式抽象概念的例子有 Scala 中的 Future、Java 8 中的 CompletableFuture 和 JavaScript 中的Promise,还有最初微软为 .NET 平台开发的 Reactive Extensions(RX)。
  3. 服务调用:多协议支持
    1. 异步,基于消息传递的机制==响应可能非即时==
      1. jms
      2. amqp
    2. 同步通信==由于等待而阻塞==
      1. http
      2. thrift
  4. 服务发现:应用程序服务的位置是动态分配的,而且,单个服务的一组实例也会随着自动扩展或升级而动态变化。
    1. 服务端发现
    2. 客户端发现
  5. 服务版本问题:
    1. 特别是RestAPI调用,由于json本身无Schema返回,更容易忽视对服务的版本控制
      1. 小版本变更,直接覆盖。升级受影响消费端
      2. 大版本升级,则视为增加一个服务;逐步迁移和替代旧版本服务
  6. 处理局部失败:Netfilix的服务解决方案
    1. 超时设置
    2. 断路器机制
    3. 流量控制
    4. 缓存数据或默认返回值
    5. 最终目的:减少对最终用户影响

进程间通信

一对一 一对多
同步 请求/响应
异步 通知(客户端不期望服务端响应) 发布/订阅(通知消息)
异步 请求/异步响应(客户端不阻塞,默认响应不会立即到达) 发布/异步响应(请求消息,等待从感兴趣的服务发回响应)

REST包含以下四个层次:

  • Level 0:本层级的 Web 服务只是使用 HTTP 作为传输方式,实际上只是远程方法调用(RPC)的一种具体形式。SOAP 和 XML-RPC 都属于此类。
  • Level 1:Level 1 层级的 API 引入了资源的概念。要执行对资源的操作,客户端发出指定要执行的操作和任何参数的 POST 请求。
  • Level 2:Level 2 层级的 API 使用 HTTP 语法来执行操作,譬如 GET 表示获取、POST 表示创建、PUT 表示更新。如有必要,请求参数和主体指定操作的参数。这能够让服务影响 web 基础设施服务,如缓存 GET 请求。
  • Level 3:Level 3 层级的 API 基于 HATEOAS(Hypertext As The Engine Of Application State)原则设计,基本思想是在由 GET请求返回的资源信息中包含链接,这些链接能够执行该资源允许的操作。例如,客户端通过订单资源中包含的链接取消某一订单,GET 请求被发送去获取该订单。HATEOAS 的优点包括无需在客户端代码中写入硬链接的 URL。此外,由于资源信息中包含可允许操作的链接,客户端无需猜测在资源的当前状态下执行何种操作。

优点:

  • HTTP 非常简单并且大家都很熟悉。
  • 可以使用浏览器扩展(比如 Postman)或者 curl 之类的命令行来测试 API。
  • 内置支持请求/响应模式的通信。
  • HTTP 对防火墙友好。
  • 不需要中间代理,简化了系统架构。

缺点:

  • 只支持请求/响应模式交互。尽管可以使用 HTTP 通知,但是服务端必须一直发送 HTTP 响应。
  • 由于客户端和服务端直接通信(没有代理或者缓冲机制),在交互期间必须都保持在线。
  • 客户端必须知道每个服务实例的 URL。如前篇文章“API 网关”所述,这也是个烦人的问题。客户端必须使用服务实例发现机制。

Thrift

服务发现的可行方案以及实践案例

客户端发现模式:

Netflix OSS 是客户端发现模式的绝佳范例。Netflix Eureka 是一个服务注册表,为服务实例注册管理和查询可用实例提供了 REST API 接口。Netflix Ribbon 是 IPC 客户端,与 Eureka 一起实现对请求的负载均衡。我们会在后面深入讨论 Eureka。

优点:

  • 除了服务注册,其他部分无需变动
  • 能针对特定应用实现负载均衡

缺点:

  • 客服端与服务注册绑定,要针对服务端用到的每个编程语言和框架,实现发现服务逻辑

服务端发现模式

  • HTTP 服务器与类似 NGINX PLUS 和 NGINX 这样的负载均衡起也能用作服务端的发现均衡器。Graham Jenson 的 Scalable Architecture DR CoN: Docker, Registrator, Consul, Consul Template and Nginx一文就描述如何使用 Consul Template 来动态配置 NGINX 反向代理。Consul Template 定期从 Consul Template 注册表中的配置数据中生成配置文件;文件发生更改即运行任意命令。在这篇文章中,Consul Template 生成 nginx.conf 文件,用于配置反向代理,然后运行命令,告诉 NGINX 重新加载配置文件。在更复杂的实现中,需要使用 HTTP API 或DNS 来动态配置 NGINX Plus。

———————–未完待续————————-