文章来自微信公众号:DevOps研究院
前言:
前段时间公司事情多,这篇长文写了放、放了写…耽搁了一些进度。各个自媒体的更新也慢了很多,这里给大家说句抱歉了。
现如今“微服务”遍地开花,已经成软件架构领域最受欢迎的热门话题之一。网上和书籍中都有很多关于微服务基础和优势的学习材料,但是我们可能会发现这东西在现实世界企业场景中似乎好像没那么普及,真正能跑的微服务资源其实也不是很多,大多是停留在概念和摸索阶段。
在这篇文章里,我打算讲讲微服务架构(MSA)的关键架构概念,以及如何在实践中将这些架构原理应用起来。
企业应用,因为服务于众多业务需求,因此会有些特定的软件应用提供许多功能,而一般惯例是把这些功能都堆在单个单片应用中。例如,ERP,CRM和其他各种软件系统被规划构建为具有数百个功能的整体。这种带坑应用一经部署,在往后的故障排除、扩展和升级场景中就是一场接一场的恶梦了。
面向服务架构(SOA)旨在通过引入“服务”的概念来克服以上的限制,“服务”是从应用程序提供的类似功能中提取出来的聚合和分组。因此,使用SOA,软件应用程序就会被设计为“粗粒度”服务的组合。然而,SOA中服务的范围非常广泛,这又引出了复杂而庞大的服务与一大堆操作(功能)以及复杂无比的消息格式和标准(如WS *标准)。
多数情况下,SOA中的服务彼此独立,只不过它们与所有其他服务一起部署在相同的运行时间里(只需考虑将部署到同一个Tomcat实例中的多个Web应用)。和单片软件应用类似,这些服务通过积累各种功而具有随时间推移的习惯。图1是一个非常好的一个单片架构的例子,显示了包括多个服务的零售软件应用,所有这些服务都能部署到同一应用程序。
说了那么多,大家是不是有点不明所以?我总结了一些重点,以下就是基于单片架构的应用程序的一些特性归纳:
单片架构的天然特性,直接给微服务架构的异军突起带来了绝佳的机会。
微服务架构(MSA)的基础是将单片应用作为一套小型和独立服务来开发,这些服务都在自己的空间独立开发、部署和运行。在微服务体系结构的大多数定义中,它普遍被解释为将巨大的可用服务隔离成一套独立服务的过程。不过我对这些有自己的理解,微服务的逻辑不仅是将整个大容量服务分为独立服务,关键在于通过查看从整体提供的功能,我们就可以确定所需的业务能力。而这些业务能力可以具体实现为各自独立的细粒度和自包含(微)服务。它们可能在一个技术堆栈上实现,每个服务都处理一个非常具体和有限的业务范围。
因此,上面解释的在线零售系统场景可以通过如图2的微服务架构实现。通过微服务架构,零售软件应用程序被规整为一套微服务。而且从图2最底下一层可以看出,根据业务需求,还多了一个从原始服务组合中额外创建的一个微服务。换句话说,想跟进微服务,要有超大容量服务可能会分裂的准备,不过我相信相比于进步,这点麻烦值得付出。
所以,铺垫了那么多,现在我们深入了解微服务的关键架构原理,这里重要的是最好带着实践的思路来思考问题。
通过Microservices Architecture可以从头开始构建软件应用或改造现有应用程序/服务…无论是哪种方法,正确判定Microservices的大小,范围和功能,都至关重要。我感觉,这可能是在Microservices Architecture实践最初(对的,“最初”这个词用的没错)最难的事了。
现在聊聊关于微服务的规模、范围和功能的关键实践问题和对一些坊间误解的辟谣。
那么那么我们应该如何在微服务架构中正确设计服务?
在我们的零售用例中,整体功能分为四个不同的微服务,即“库存”,“会计”,“运输”和“存储”。他们正在解决一个有限但重点突出的业务范围,使每个服务彼此完全脱钩,并确保开发和部署中的敏捷性。
在单片应用中,使用函数调用或语言级方法调用不同处理器/组件的业务功能。在SOA中,这种转移趋向于更为松散耦合的Web服务级别消息传递,主要基于不同协议(如HTTP,JMS)之上的SOAP。而具有数十种操作和复杂消息模式的Web服务是Web服务普及的关键阻力。对于Microservices架构,它需要简单而轻量的消息传递机制就行。
对于同步消息传递(客户端期望从服务及时得到响应并等待到达),在微服务体系结构中,REST是主流标配,因为它提供了基于资源API风格的HTTP请求响应实现的简单消息传递方式。因此,大多数微服务实现都使用HTTP以及基于资源API的风格(每个功能都以资源和在这些资源之上执行的操作来表示)。
另外,Thrift (可以在其中为微服务定义接口定义)可以作为REST / HTTP同步消息传递的替代方法。
对于某些需要使用异步消息传递技术(客户端不期望立即响应或根本不接受响应)的微服务场景。多看看诸如AMQP, STOMP或MQTT之类的异步消息协议就好了。
决定微服务最适合的消息格式是另一个关键因素。传统单片应用使用二进制格式(习惯了,表示还好不算复杂);基于SOA / Web服务的应用使用基于复杂消息格式(SOAP)和模式(xsd)的文本消息。而在大多数基于微服务器的应用中,简单基于文本的消息格式即可,如JSON和XML,反正就是基于HTTP资源API风格跑起来。在我们需要二进制消息格式的情况下(文本消息在某些用例中可能会变冗长),微服务可以利用二进制消息格式,如Thrift,ProtoBuf或Avro…
若你把业务能力实现为服务,就需要定义和发布服务合同。传统单片应用几乎找不到这样的功能来定义应用的业务功能。在SOA/Web服务的世界里,WSDL用于定义服务合同。不过众所周知,WSDL不是用于定义微服务合同的理想解决方案,因为WSDL非常复杂且与SOAP紧密耦合。
由于我们在REST架构风格之上构建微服务器,所以我们可以使用相同的REST API定义技术来定义微服务器的合同。因此,微服务更多情况下用标准的REST API定义语言(如Swagger和RAML) 来定义服务契约。
对于不基于HTTP/REST(如Thrift)的其他微服务实现,可以用协议级别的“接口定义语言(IDL)”(如Thrift IDL)。
在微服务架构中,软件应用程序被构建为一套独立的服务。因此,为了实现业务用例,需要在不同的微服务/流程之间建立通信结构。这就是为什么微服务之间的服务间/过程通信至关重要的原因。
在SOA实现中,服务之间的服务间通信通过企业服务总线(ESB)来实现,大部分业务逻辑都位于中间层(消息路由,转换和业务流程)中。然而,微服务架构促进消除中间消息总线/ESB,并将“智能”或业务逻辑移至服务和客户端(称为“智能端点”)。
由于微服务使用诸如HTTP,JSON等标准协议,因此在微服务之间的通信中,与不同协议集成的要求是最小的。Microservice通信中的另一种替代方法是使用轻量级的消息总线或网关,它们有最小的路由功能,并且仅用作在网关上实现业务逻辑的“dumb pipe”。基于这些风格,在微服务架构中不可避免的出现了几种通信模式。
以点对点的形式,消息路由逻辑的整体跑在每个端点之上,服务可以直接通信。这里每个微服务器都暴露一个REST API,一个给定的微服务器或外部客户端可以通过对应的REST API调用另一个微服务器。
显然,这个模型适用于相对简单的基于微服务的应用。随着服务数量增加,复杂就会压倒一切的源头。传统SOA实现中使用ESB也是相同的原因,不过是为了摆脱混乱的点对点集成链接。总结微服务通信中点对点风格的缺点:
特征说完,总结:对于复杂的微服务用例,可以考虑轻量级的中间消息总线,而不是点对点连接或中心ESB,思路是为微服务提供一个抽象层,并可用于实现各种非功能的能力,这种风格被称为API网关风格,往下看。
API网关风格背后的关键思想是使用轻量级消息网关作为所有客户端/消费者的主要入口点,并在Gateway级别实现常见的非功能需求。通常,API网关允许通过REST/HTTP使用受管API。
因此,在这里,我们可以将通过API-GW实现作为微服务的业务功能公开为管理API。Microservices架构和API管理的组合,这个算是最佳选择了。
在我们的零售业务场景中,如图5,所有的微服务都通过API-GW公开,这是所有客户端的单个入口点。总结下API-GW风格优势:
比较推荐API-GW,我没具体了解过,但这个应该也是应用最广泛的模式。
微服务还可以和异步消息的场景集成,比如队列或主题的单向请求以及订阅。给定的微服务可以做消息生成,并且它可以异步地将消息发送到队列或主题。那么消费的微服务器可以消耗来自队列或主题的消息。这种风格将消息生成与消息消费分离,中间消息代理缓冲直到消费处理。
消费/生产之间的通信基于异步消息标准(例如AMQP,MQTT等)的消息代理来实现。
单片架构中,应用将数据存储在单个和集中的数据库中,以实现应用的各种功能/功能。
在微服务体系结构中,功能分散在多个微服务器中,如果我们使用相同的集中式数据库,那么微服务器将不再彼此独立(例如,如果数据库模式已经从给定的微服务器发生变化)。因此,每个微服务器都必须拥有自己的数据库。
以下是在微服务架构中实施分散数据管理的关键方面:
非集中式数据管理提供完全解耦的微服务器,以及选择不同数据管理技术(SQL或NoSQL等,按需分配,可能不同数据库管理系统)的***。再者对于涉及多个微服务的复杂事务用例,事务行为必须使用从每个服务提供的API来实现,并且逻辑位于客户端或中间(GW)级别。
微服务架构倾向于分散治理。一般来说,SOA治理指导了可重用服务的开发,建立如何设计和开发服务以及这些服务随时间的变化。它确定了服务提供商和这些服务的消费者之间的协议,告诉消费者他们期望什么以及提供者有义务提供什么。在SOA治理中,共有两种类型的治理:
那么,微服务环境中的治理究竟怎么理解?在微服务架构中,微服务通过各种技术和平台构建为完全独立和解耦服务。因此,不需要为服务设计和开发定义一个共同的标准。总结下微服务的权力下放治理能力:
在微服务架构中,需要处理的微服务器数量相当高。而且,由于微服务的快速和敏捷的开发/部署性质,他们的位置一般来说也会动态变化。因此,你需要在运行时间内找到微服务器的位置。解决此问题的方法是使用Service Registry。
服务注册表保存微服务实例及其位置。Microservice实例在启动时注册到服务注册表,并在关机时注销。消费者可以通过服务注册表找到可用的微服务及其位置。
要找到可用的微服务及其位置,我们要一个服务发现机制。有两种类型的服务发现机制,客户端发现和服务器端发现,来看看这些服务发现机制各原理如何。
客户端发现:
在这种方法中,客户端或API-GW通过查询服务注册表来获取服务实例的位置。
这里客户端/API-GW必须通过调用Service-Registry组件来实现服务发现逻辑。
服务器端发现:
通过这种方法,客户机/API-GW将请求发送到在众所周知的位置运行的组件(如负载平衡器)。该组件调用服务注册表并确定微服务器的绝对位置。
Kubernetes等微服务部署解决方案提供了服务端发现机制,自媒体里链接不能发就算了。
在微服务架构方面,微服务的部署同样起着至关重要的作用,关键要求如下:
Docker提供了一种很好的方式来部署满足上述要求的微服务器,所涉及的关键步骤如下:
Kubernetes通过允许将一组Linux容器作为单个系统进行管理,在多个主机上管理和运行Docker容器,提供容器的共同位置,服务发现和复制控制,从而扩展Docker功能。其实大多数这些功能在微服务环境中也很重要,因此使用Kubernetes(在Docker上面)用于微服务部署已经成为一种非常强大的方法,特别是对于大规模微服务部署。
图11,显示了零售应用的微服务部署概述。每个微服务实例被部署为容器,每个主机有两个容器。同时可随意更改在给定主机上运行的容器数。
现实很骨感,无论是不是微服务都应当得到安全方面的保护。在进入微服务安全性篇章之前,我们先快速过一下如何在单片应用层面实现安全。
那么,我们可以直接将这种模式转化为微服务架构吗?是的,但是这需要在每个微服务级别实现安全组件,该级别正在与集中式/共享用户存储库进行通信,并检索所需的信息。这是解决Microservices安全问题的一种非常乏味的方法。
还有,划重点,我们可以利用广泛使用的API-Security标准(如OAuth2和OpenID Connect)来找到我们的Microservices安全问题的更好的解决方案。在深入了解之前,我来总结下这些标准。
现在,让我们看看我们如何使用这些标准来保护我们零售业的微观服务。
如图12,这些是实现微服务安全性的关键步骤:
微服务中的交易支持如何?其实,支持跨多个微服务的分布式事务是一个非常复杂的任务。
微服务架构本身鼓励服务之间的无事务协调。这个想法是给定的服务是完全独立,基于单一的责任原则。跨多个微服务器分布式事务的需要通常是微服务体系结构设计缺陷的症状,通常可以通过重构微服务器的范围进行整理。
然而,如果强制性要求跨多个服务进行分布式交易,则可以通过在每个微服务级别引入“补偿操作”来实现这种情况。关键思想是,给定的微服务是基于单一责任原则,如果给定的微服务器未能执行给定的操作,那么我们可以认为这是整个微服务的失败。
Microservice架构引入了一系列分散的服务,与单片设计相比,增加了在每个服务级别发生故障的可能性。由于网络问题,基础资源不可用,给定的微服务可能会失败。不可用或无响应的微服务器不应玩砸了整个基于微服务器的应用。因此,微服务应该有容错余地,能够在可能的情况下恢复,客户端也必须妥善处理。
此外,由于服务可能随时失败,因此能够快速检测(实时监控)故障,并尽可能自动恢复服务(故障自愈)很重要。
在微服务玩家的眼里,处理错误有几种常用模式。
当你对微服务器进行外部呼叫,就可以在每次调用时配置故障监视器组件,并且当故障达到某个阈值时该组件将停止对服务的任何进一步调用(跳闸电路)。在打开状态(可以配置)的一定数量的请求后,将电路更换回关闭状态。
这种模式对于避免不必要的资源消耗,由于超时引起的请求延迟是非常有用,也让我们有机会更积极的监控系统(基于活动的开路状态)。
基于微服务器的应用的一部分的故障不应影响其他应用,隔板模式是关于隔离应用的不同部分,以便应用的某个部分的服务失败不会影响任何其他服务。
超时是一种主观加入的合理机制,当你认为结果无法返回,则允许停止响应。
模式这里叨叨完。那么,我们在哪里和如何使用这些模式与微服务?大多数情况下这些模式都适用于Gateway级别,这意味着当微服务不可用或没有响应时,在网关级别,我们可以决定是否使用断路器或超时模式将请求发送到微服务。此外,在Gateway级别实现诸如隔板之类模式也很重要,因为它是所有客户端请求的单个入口点,也因此发送服务中的故障不应影响其他微服务器的调用。
另外,Gateway可以作为中心点,我们可以通过Gateway调用每个微服务来获取每个微服务器的状态和监视。
们专门研究过微服务架构的各种特点,以及如何在现代企业IT环境中实现它们。但是,我们应该记住,微服务不是灵丹妙药。流行语概念的盲目适应不会解决“真实”企业IT问题。
它微服务是有很多优势,我们也应该充分利用。但是我们还必须记住,解决所有企业IT问题与微服务之间联系不一定就是强相关。例如,Microservices架构促进消除ESB作为中间总线,但是当涉及到现实世界的IT时,现在有很多不是基于Microservices的应用程序/服务。所以,整合是避不开的解决思路,要做集成。
所以,理想情况下,Microservices和其他企业架构概念(如Integration)的混合方法将更为现实。以后再聊了,这个能写的太多。 希望这能让你更清楚地了解如何在企业中使用Microservices。