微服务 (Microservices) 是一种软件架构风格,它是以专注于单一责任与功能的小型功能区块 (Small Building Blocks) 为基础,利用模块化的方式组合出复杂的大型应用程序,各功能区块使用与语言无关 (Language-Independent/Language agnostic) 的 API 集相互通信。
微服务的起源是由 Peter Rodgers 博士于 2005 年度云计算博览会提出的微 Web 服务 (Micro-Web-Service) 开始,Juval Löwy 则是与他有类似的前导想法,将类别变成细粒服务 (granular services),以作为 Microsoft 下一阶段的软件架构,其核心想法是让服务是由类似 Unix 管道的访问方式使用,而且复杂的服务背后是使用简单 URI 来开放接口,任何服务,任何细粒都能被开放 (exposed)。这个设计在 HP 的实验室被实现,具有改变复杂软件系统的强大力量。
2014年,Martin Fowler 与 James Lewis 共同提出了微服务的概念,定义了微服务是由以单一应用程序构成的小服务,自己拥有自己的行程与轻量化处理,服务依业务功能设计,以全自动的方式部署,与其他服务使用 HTTP API 通信。同时服务会使用最小的规模的集中管理 (例如 Docker) 能力,服务可以用不同的编程语言与数据库等组件实现。
微服务是一种以业务功能为主的服务设计概念,每一个服务都具有自主运行的业务功能,对外开放不受语言限制的 API (最常用的是 HTTP),应用程序则是由一个或多个微服务组成。
微服务的另一个对比是单体式应用程序。单体式应用表示一个应用程序内包含了所有需要的业务功能,并且使用像主从式架构 (Client/Server) 或是多层次架构(英语:Multitier architecture) (N-tier) 实现,虽然它也是能以分布式应用程序来实现,但是在单体式应用内,每一个业务功能是不可分割的。若要对单体式应用进行扩展则必须将整个应用程序都放到新的运算资源(如:虚拟机) 内,但事实上应用程序中最吃资源、需要运算资源的仅有某个业务部分(例如跑分析报表或是数学算法分析),但因为单体式应用无法分割该部分,因此无形中会有大量的资源浪费的现象。
微服务运用了以业务功能的设计概念,应用程序在设计时就能先以业务功能或流程设计先行分割,将各个业务功能都独立实现成一个能自主运行的个体服务,然后再利用相同的协议将所有应用程序需要的服务都组合起来,形成一个应用程序。若需要针对特定业务功能进行扩展时,只要对该业务功能的服务进行扩展就好,不需要整个应用程序都扩展,同时,由于微服务是以业务功能导向的实现,因此不会受到应用程序的干扰,微服务的管理员可以视运算资源的需要来配置微服务到不同的运算资源内,或是布建新的运算资源并将它配置进去。
虽然使用一般的服务器虚拟化技术就能应用于微服务的管理,但容器技术 (Container Technology) 如 Docker 会更加地适合发展微服务的运算资源管理技术。
微服务的规划与单体式应用程序十分不同,微服务中每个服务都需要避免与其他服务有所牵连,且都要能够自主,并在其他服务发生错误时不受干扰。
微服务理念中有数个数据库的规划方式。
数据库并不会只存放该服务的数据,而是“该服务所会用到的所有数据”。更深层一点的举例:假设有个文章服务,而这个服务可能会需要判断用户的账号⋯⋯等。那么文章服务的数据库就可以放入用户的部分数据。此举是为了避免服务之间的相依性,避免文章服务调用用户服务。
实践微服务有许多的做法,但其中一种做法是将数据库作为短期的存储空间而不是存储长期的数据。这意味着数据库可以在离线时被清空。因为它们可以在上线时从事件存储中心恢复,因此也能以存储器缓存(如:Redis) 作为数据库服务器。但这种做法需要将每个请求当作事件来进行广播。如此一来就可以从事件存储中心重播所有的事件来找回所有的数据。
微服务中最重要的就是每个服务的独立与自主,因此服务与服务之间也不应该有所沟通。倘若真有沟通,也应采用异步沟通的方式来避免紧密的相依性问题。要达到此目的,则可用下列两种方式:
这可以让你在服务集群中广播事件,并且在每个服务中监听这些事件并作处理,这令服务之间没有紧密的相依性,而这些发生的事件都会被保存在事件存储中心里。这意味着当微服务重新上线、部署时可以重播(Replay)所有的事件。这也造就了微服务的数据库随时都可以被删除、摧毁,且不需要从其他服务中获取数据。
这令你能够在服务集群中广播消息,并传递到每个服务中。具有这个功能的像是 NSQ 或是 RabbitMQ。你能够在 A 服务上广播一个“创建新用户”的事件,这个事件可以顺便带有新用户的数据。而 B 服务可以监听这个事件并在接收到之后有所处理。这些过程都是异步处理的,这意味着 A 服务并不需要等到 B 服务处理完该事件后才能继续,而这也代表 A 服务无法获取 B 服务的处理结果。与事件存储中心近乎相似,但有所不同的是:消息队列并不会保存事件。一旦事件被消化(接收)后就会从队列中消失,这很适合用在像发送欢迎信件的时机。
单个微服务在上线的时候,会向服务探索中心(如:Consul)注册自己的 IP 位置、服务内容,如此一来就不需要向每个微服务表明自己的 IP 位置,也就不用替每个微服务单独设置。当服务需要调用另一个服务的时候,会去询问服务探索中心该服务的 IP 位置为何,得到位置后即可直接向目标服务调用。
这么做的用意是可以统一集中所有服务的位置,就不会分散于每个微服务中,且服务探索中心可以每隔一段时间就向微服务进行健康检查(如透过:TCP 调用、HTTP 调用、Ping),倘若该服务在时间内没有回应,则将其从服务中心移除,避免其他微服务对一个无回应的服务进行调用。
一个微服务框架的应用程序有下列特性:
一个微服务框架:
微服务可以用不同的编程语言实现,也可以使用不同的基础设施。因此,最重要的技术选择是微服务之间的通信方式(同步、异步、UI集成)以及用于通信的协议(RESTful HTTP、消息、GraphQL……)。在传统系统中,大多数技术选择,如编程语言,都会影响整个系统。因此,选择技术的方法是完全不同的。
Eclipse基金会已经发布了开发微服务的规范——Eclipse MicroProfile。
在服务网格中,每个服务实例都与一个反向代理服务器实例(称为服务代理、 sidecar代理或sidecar)配对。服务实例和 sidecar 代理共享一个容器,容器由一个容器编排工具(如Kubernetes、Nomad、Docker Swarm、DC/OS)管理。服务代理负责与其他服务实例的通信,并支持服务(实例)发现、负载平衡、身份验证和授权、安全通信等功能。
在服务网格中,服务实例及其sidecar代理被称为构成数据平面,其中不仅包括数据管理,还包括请求处理和响应。服务网格还包括一个用于管理服务之间交互的控制平面,这些交互由它们的sidecar代理协调。服务网格架构有几个选项: Istio、Linkerd、Consul和其他许多服务网格景观。服务网格管理平面Meshery提供跨服务网格部署的生命周期、配置和性能管理。
实现微服务体系结构非常困难。任何微服务体系结构都需要解决许多问题(见下表)。Netflix开发了一个微服务框架来支持他们的内部应用程序,然后开放了该框架的许多部分。其中许多任务具已经通过Spring框架得到推广——它们已经在Spring Cloud项目的保护伞下重新实现为基于Spring的工具。 下表显示了Kubernetes生态系统中的实现功能与Spring Cloud世界中的等效功能的比较。 Spring Cloud生态系统值得注意的一点是,它们都是基于Java的技术,而Kubernetes是一个多语言运行时平台。