10

Micro 架构与设计

翻译自 Micro architecture & design patterns for microservices

注: 原文作者即 Micro 框架的开发者。

过去几个月中,我们收到了很多关于 micro 的微服务架构和设计模式的问题。所以今天我们试着解释一下这两方面的问题。

关于 Micro

Micro 是一个微服务工具集。它被用来实现它的特性和接口,同时提供强大的可插拔的架构来保证基础组件可以被替换掉。

Micro 专注于解决构建微服务系统的基础需求。它采用了深思熟虑地富有预见性的方式来实现它的设计。

如果你想深入研究 Micro 工具集请点这里查看上一篇博客,或者如果你想学习微服务的基本概念请查看这里

在我们开始讨论 Micro 的架构之前,我们将快速的介绍一下 Micro 的特性.

工具集

Go Micro

Go Micro是一个用 GO 来写微服务的、可插拔的 RPC 框架。它提供了服务发现,客户端负载均衡,编码,同步异步通讯等功能的库。

Micro API

Micro API 是为访问微服务提供了 HTTP 服务和路由功能的 API 网管。在 Micro 中,它提供一个单一的入口,它可以被用作反向代理,或者将 HTTP 请求转换成 RPC.

Micro Web

Micro Web 是微型网络应用(micro web application)的仪表盘和反向代理。我们相信 web 应用应该被构建成微服务因此应被看做微服务世界的一等公民。它像一个 API 的反向代理但它同时提供对 web socket 的支持。

Micro Sidecar

Micro Sidecar 提供将 go-micro 用作 HTTP 服务的所有功能。Sidecar 提供使用其他语言写微服务应用的途径。

Micro CLI

Micro CLI 是和你的微服务们交互的命令行接口。它还可以让你在不想直接连接服务的时候使用 Sidecar 作为一个代理。

下面让我们更深入的了解。

RPC, REST, Proto...

你的第一个疑问可能就是,为什么是 RPC 而不是 REST? 我们认为 RPC 更适合内部服务通信的场景。或者更具体的, 使用 protobuf 编码并且用 protobuf IDL 定义 API 的 RPC。联合使用这些技术能够很方便的创建强定义的 API 接口和有效的消息编码。RPC 是非常直观的通信协议。

我们并不是这一信条的独立拥护者。

Google 是 protobuf 的创造者,在内部使用 RPC 并且最近开源的 RPC 框架 gRPC. Hailo 同样也是 RPC/Protobuf 的强烈倡导者,并从中受益匪浅,更有趣的是在跨团队协助方面获得的收益比系统性能上的收益更多。Uber 正则开发资金的 PRC 框架协议 TChannel

我个人认为未来的 API 应该是使用 RPC 构建的,因为它有诸如 protobuf 这类的有良好的结构化的格式,有易用高效的编码方法的协议,从而能构建强定义的 API 和高效的通讯。

HTTP 到 RPC, API...

然而在现实中,在 web 上使用 RPC 还有很长的路要走。尽管在数据中心内部使用 RPC 很完美,但是支撑高并发的网站和移动 API 又是另一回事。好吧,完全从 HTTP 切换到 RPC 来由很长的路要走。这也是为什么 micro 提供了 API 网关组件,来支撑和转换 HTTP 请求。

API gateway 是微服务架构中使用的一种模式。它是微服务和外界沟通的唯一入口,它根据 HTTP 请求调用对应的服务。API gateway 使一个 HTTP API 能够组合调用多个不同的微服务。

这是一个很强大的模式。因 API 一部分的更改导致整个单一部署的服务挂掉的日子将一去不复返。

微服务 API 使用 路径-服务 的解决方案,因此每个请求路径能够调用不同的微服务 API,例如 /user => user api, /order => order api

举个例子,到 /customer/orders 的请求将被带着方法名 Customer.Orders 转发到 API go.micro.api.customer

image

你可能好奇, API 服务到底是什么。现在我们来讨论不同类型的服务。

微服务的类型

微服务的概念主要是按关注点分离 -- 从著名的 unix 哲学 doing one thing and doing it well 中借鉴了很多。出于这个原因,我们认为有必要从逻辑上和架构上将拥有不同任务的服务分离。

这些概念并不是什么新的概念,最近变得很引人注目是因为它被一些非常成功的技术公司证明是可行的。我们的目标是推广这些开发哲学并通过构建工具链来指导设计决策。

以下是我们定义的服务的类型。

API - 基于 micro api,API 服务在设施的最顶端,一般直接支撑你的移动或 web 应用。你可以使用 HTTP handler 建造它然后使用反向代理模式启动 micro api,或者,默认情况下处理这种专门格式的 RPC API 请求和响应。

Web - 基于 micro web, 专门用来提供 html 内容和管理面板访问的 Web 服务。micro web 为 HTTP 和 WebSockets 提供反向代理。目前,仅支持这两周格式,未来可能会支持更多的格式。就像之前提到过的那样,我们相信 “web 应用即微服务”。

SRV - 基于 RPC 的后端服务。它们主要关注于为你的系统提供核心功能并且大多数情况下不会对外开放。如果你愿意,你仍可以使用 micro api 或 micro web 使用 /rpc 路径来访问它,但一般使用 go-micro 客户端来直接调用它们。

image

基于以往的经验,我们发现这种架构模式及其强大并且见到过使用它支撑数百个微服务的系统。

Namespacing(命名空间)
你可能会好奇,如何隔断 micro api 和 micro web 之间的通信?我们使用逻辑命名空间里做分离。通过给服务名加前缀(prefix)我们清晰的确定它的意图以及它在系统中的位置。这个简单但有效的模式让我们受益良多。
micro api 和 micro web 将组成由命名空间和请求路径的第一个路径组成的服务名称。例如,访问 api/customer 的请求变为 go.micro.api.customer。

默认的命名空间为:

  • API - go.micro.api

  • Web - go.micro.web

  • SRV - go.micro.srv
    你应该为你自己的域名设定这些命名空间: com.example.{api, web, srv}。micro api 和 micro web 能够配置成在运行时路由到你的命名空间。

同步和异步

我们经常听到微服务和响应式模式一同出现。对于大多数来说,微服务是创建事件驱动的架构,并且主要通过异步通信的服务。

Micro 将异步通信作为一等公民对待并且将其构建成为微服务的基础组成部分之一。通过与事件异步通信的方式允许任何人消费这些事件,并针对这些事件执行自己的任务。可以在此基础上新的单独部署的服务而不需要需改他们的其他任何方面。这是一个强大的设计模式并且正由于此我们在 go-micro 中实现了一个异步的 broker 接口。

image

在 Micro 中,同步和异步通信被放到隔离的需求中。Transport 接口用来创建服务间点对点的连接。构建在 transport 基础上的 go-micro 客户端和服务器能够提供请求-响应模式的 RPC 调用,也可以提供双向流模式下的调用。

image

在构建系统时两种通信模型都应该被使用,但关键是要理解什么时候,在哪儿用哪种方式更合适。很多情况下,没有对错,但是我们还是要权衡两种的利弊。
举个例子,在制作用来保存跟踪用户操作历史的审计系统时,broker 和异步通信可能更合适。

image

在这个例子中,每个 AI 或者说服务,当一些动作发生(客户登录,更新简介或下订单)时都会肺部一个事件。审计服务将会订阅这些事件并将它们存储到按时间序列存储的数据库中。管理员或其他任何用户都能看到任何用户产生的任何事件发生的历史。

如果这个系统被设计成同步的,当流量高或服务数量增加时,审计系统很容易被压垮。如果审计系统宕机或者请求失败我们可能会丢失这条历史记录。通过将这些事件发布给 broker 我们能保持他们异步。这是事件驱动型架构构建的微服务的一种通用模式。

咳咳,暂停一下,微服务的定义是什么呢?

我们讲了很多 Micro toolkit 提供的功能,也定义了很多类型的服务(API, WEB, SRV)但是并没怎么讲微服务到底是什么。

关于微服务的定义和解释有很多,但这组是最合适的。

基于有限上下文的架构的低耦合的服务
--Adrian Cockcroft

将单个应用开发为一组跑在独立进程上并且互相之间使用轻量级方法进行通信的微小的服务
--Martin Fowler

就像 unix 哲学说的那样 Do one thing and do it well
--Doug McIlroy

我们认为一个微服务就是一个专注于一个实体(或领域)的应用 -- 并且通过强定义的 API 访问它。
让我们拿社交网络来举个现实中的例子。

image

有一个软件架构模式随着 Ruby On Rails 的崛起而变得流行 -- 那就是 MVC(模型 -- 视图 -- 控制)。
在 MVC 的世界里,每个实体,或者说,域,都被表示为一个从数据库中抽象而来的模型。模型可能和其他模型之间有相互关系,比如说一对多,多对多。控制层处理收到的请求,从 model 中查询数据,然后把它传递给用户,从而展现给用户。

现在举一个微服务架构中同样的例子。模型被服务取而代之,它通过 API 传递数据。用户请求,数据收集和数据呈现由多个 web service 处理。
每个服务都有一个单一的关注点。当我们想添加一个新功能或新的实体时,我们可以简单的修改关注于那个功能的服务或者直接写一个新的服务。这种分离的方式提供了能够很好 scale 的软件开发方式。

接下来我们回归正题。

版本管理

image

版本管理是现实软件开发中重要的一部分。在微服务的世界中很重要的一点是 API 和业务逻辑是被分成很多不同的服务的。正由于此,服务的版本控制很重要,被放到核心工具库中,提供更好的细粒度的控制和升级过程中的流量迁移。

在 go-micro 中服务有一个名字和版本号定义。仓库(Registry)返回一个 list 表示一个服务 -- 通过节点
注册时的版本号来区分这些节点。
这是我们用于构建基于版本的路由功能的构建模块的一段代码

type Service struct {
    Name      string
    Version   string
    Metadata  map[string]string
    Endpoints []*Endpoint
    Nodes     []*Node
}

它和 Selector -- 一个客户端的负载均衡 -- 结合起来使用,从而在 go-micro 内部保证请求分发到不同的版本上去。

Selector 是一个强大的接口。我们在它之上提供不同类型的路由算法:随机(默认),round robin(环形队列?),基于标签,基于延迟,等等。
通过默认的基于随机哈希的负载均衡算法,并逐步将新版本的服务实例加入,你可以执行蓝绿发布(link)并实行金丝雀测试。

未来我们会实现一个内嵌 selector 的面向全球服务的负载均衡服务来提供为既存的系统做路由决策。它还能胜任在运行时为不同版本的服务分配不同的负载的职能,并且能动态地为服务添加原信息或标签,从而在此之上可以做动态的路由决策。

伸缩

上文关于版本控制的说明经已提及了伸缩一个服务使用的基础模型。仓库(registry)用来存储服务的相关信息,selector 用来控制路由和负载均衡。

我们再一次实践了关注点分离(separation of concoerns)和做一件事并把它做好(dooing one thing well)的哲学。伸缩基础设施、代码很依赖于简化、强定义的 API 以及分层的架构。通过编写上面那些构建模块,我们能够开发伸缩性更强的软件系统,并专注于更高层面的东西。

这是 Micro 的基础,也是在微服务世界里我们希望引领的软件开发的方式。

在之前的文章 Micro on NATS 中我们简要讨论了关于云端架构模型的问题。现在我们简单回顾下其中的一些观点。
当在生产环境部署服务时,你希望你的系统是可伸缩的、能容错的、以及性能优异的。云计算使我们能构建有很强伸缩性能的服务,但很难不受错误影响。事实上容错性是构建分布式系统时最关键的考察点之一。所以在构建基础设施时,我们应该充分考虑容错性。
在云的世界里,我们希望能容忍可用区的错误,甚至是整个区域中断。过去,我们尝试通过热备份,冷备份或者灾难恢复计划来应对。现在,技术最先进的公司们有一个国际惯例,那就是把每个应用制作多个副本跑在世界各地的多个数据中心上。

我们需要向 Google, Facebook, Netflix 和 Twitter 学习。我们必须保证我们构建的系统能在可用区失败时不影响用户而且在大多数情况下在数分钟内解决可用区失败。

通过提供可插拔的接口, Micro 可以构建这样的架构。我们能为 micro toolkit 中的每个需求选用最合适的分布式系统。

服务发现和仓库(registry)是 Micro 的构建模块。他能用来在可用区,区域或其他配置范围内隔离和发现服务。
然后 Micro API 能够在这个拓补结构中路由以及负责均衡一系列的服务。

image

Microservices is first and foremost about software design patterns. We can enable certain foundational patterns through tooling while providing flexibility for other patterns to emerge or be used.

Because Micro is a pluggable architecture it’s a powerful enabler of a variety of design patterns and can be appropriately used in many scenarios. For example if you’re building video streaming infrastructure you may opt for the HTTP transport for point to point communication. If you are not latency sensitive then you may choose a transport plugin such as NATS or RabbitMQ instead.

The future of software development with a tool such as Micro is very exciting.

If you want to learn more about the services we offer or microservices, check out the blog, the website micro.mu or the github repo.

总结

希望这篇文章讲清了 Micro 的架构和它如何使用可伸缩的设计模式来开发微服务应用。
微服务首先是一种软件设计模式。
.... 感觉后面没啥用,就略了...


FingerLiu
562 声望28 粉丝

先广后精。Explore the whole world,and then do one thing but do it best.