武汉PHP培训
达内武汉民大中心

15271940953

热门课程

微服务与SOA架构

  • 时间:2018-02-28 13:59
  • 发布:武汉PHP培训
  • 来源:互联网

    本文是Mark Richards写的微服务与面向服务架构完整报告.
    基于服务架构的世界
    微服务和SOA都被认为是基于服务的架构,这意味着这两种架构模式都非常强调将"服务"作为其架构中的首要组件,用于实现各种功能(包括业务层面和非业务层面).微服务和SOA是两种差异很大的架构模式,但是他们仍有一些相同的特征.
    所有基于服务的架构的一个共性是他们一般都是分布式架构,也就是服务组件都是通过远程访问协议来实现的,例如REST、SOAP、AMQP、JMS、MSMQ、RMI或者.NET Remoting.相对于单体式架构和分层式架构,分布式架构有很多优势,包括可伸缩性、解耦能力以及对开发、测试和部署的可控性等.分布式架构中的组件更趋向于自包含,因此其变更管理和维护也更容易,从而使得相应的应用也更稳定,响应也更快.分布式架构也非常适用于各模块之间耦合度较低、更加模块化的应用.
    在基于服务的架构语境中,"模块化"指的是将应用的各个部分分别封装为自包含的服务的做法.拆分后的每个服务都可以单独设计、开发、测试和部署,与其他组件或服务之间的依赖性很低甚至没有.模块化的架构还支持用重写的方式来维护组件的做法.随着业务增长,架构可以逐渐地、以很小的部件为单位进行重构或者替换,而不是大张旗鼓地对整个应用进行重构或者替换.
    不幸的是,凡事都有代价,享受分布式系统的优点也一样.与优点相伴的缺点则是复杂性的增加和投入的增长.维护服务合约、选择正确的远程访问协议、处理不响应的或不可用的服务、加密远程服务和管理分布式事务,这些还只是构造基于服务的架构时许多复杂问题中的一部分.本章中,我会描述这些与基于服务的架构有关的复杂问题.
    服务合约
    服务合约是服务提供者(通常是远程的)和使用者(客户)之间使用合约语言(XML、JSON、Java Object等)约定数据输入和数据输出的一份协议.创建和维护服务合约是一项困难的工作,不应该被轻视或者当作补充条款.因此,服务合约的议题在基于服务的架构设计中值得特殊关注.
    在基于服务的架构中,存在两种服务合约模型可供使用:基于服务的合约和客户驱动的合约.两者之间的真正差别在于合作程度.在基于服务的合约中,服务是合约的唯一拥有者,一般可以在不考虑服务客户需求情况下演化或修改合约.这种模式强迫服务的所有客户都要接受新的服务合约变更,而不管客户是否需要这些新功能.
    与之相反,客户驱动的合约所基于的是服务和与服务客户之间更为密切地合作的一种关系.在这种模型下,服务拥有者和客户有很强的合作(关系),因此任何服务合约变更会充分考虑客户的需求.采用这种模型时,服务(拥有者)一般需要了解客户是谁以及每个客户都是如何使用这些服务的.客户可以对服务合约随意提出变更建议,服务方则可以根据是否影响其他客户而自行决定是否采纳.理想情况下,服务的客户向服务拥有者发起修改建议和测试用例,测试被执行时可以监测该修改是否影响其他客户.开源工具如Pact和Pacto可以帮助维护和测试这类客户驱动的合约.
    服务合约的上下文中另一个重要议题是合约的版本.我们必须接受这一现实--在服务和服务客户间实现绑定的合约终究是要变化的.改变程度和范围取决于这些变更如何影响每个客户,以及合约改变后服务的向后兼容性.
    合约的版本化使得启用新的、包含合约变更的服务功能时能够为仍旧使用老版本合约的客户提供向后兼容性.从开始开发之前就要为合约的版本化做出规划,即使开始你觉得不需要,到了最后一定需要,这也许是本章最重要的一条建议.有很多开源和商业版本的框架可以用来帮助管理和实施合约版本化策略,不过你也可以选择使用两项基本技术来实现自己的合约版本化策略:同质版本化和异质版本化.
    同质版本化是指在同一个服务合约中使用合约版本号.图1-1中,被客户A和B同时使用的合约都用圆形(代表同一服务合约)来表现,但是其中各自包含着不同版本号.举一个简单例子,假定合约是基于XML的,用来表示某些商品的订单,采用合约版本号1.0.现在新版本1.1发布了,其中包含了额外字段用于提供当订单派送而接收人不在家的时候的交货规则.这种情况下,可以通过让新的delivery-instructions字段成为可选字段来保持向后兼容版本1.0的合约.
    异质版本化则涉及对不同类型合约的支持.这个技术跟本节之前描述的客户驱动的合约很相似.服务引入新的功能特性时,就引入新合约用来支持这一(些)功能特性.注意,图1-1与1-2之间不同在于表示服务合约的形状.1-2中,客户A使用圆圈所代表的合约,而客户B则使用三角形所代表的合约.在这种情况下,向后兼容性是由不同合约而不是同一合约的不同版本所支持的.许多基于JMS的消息系统都是采用这种方式,尤其是使用ObjectMessage消息类型的系统.例如,基于Java的接收端可以使用instanceof关键字来检查通过消息发送的对象类型,然后根据对象类型来采取响应的步骤.或者,XML负载可以通过JMS的 TextMessage来发送(每个不同合约包含完全不同的XML schema),由一个消息属性来指明XML schema和XML类型负载之间的对应关系.
    合约版本化的主要目的就是提供向后兼容性.谨记,服务必须支持多个版本的合约(或者多个合约),这样才能使得开发团队能够更快地部署新的功能特性或者其它变更,而不必担心破坏与其它服务客户之间的现有合约.需要注意的是,这两种技术也可以组合起来,支持不同合约类型的多个版本.
    最后一个关于服务合约中变更合约需要注意的是:一定要从开始就制定一个明确的服务客户沟通策略,以便客户能够及时获知合约变更的信息,或者特定合约类型不再被支持的信息.很多情况下,因为内部/外部客户很多,这类沟通并不可行.这时候,一个集成中心(integration hub),或者说消息中间件,可以在服务的客户与服务之间建立抽象层,实行服务合约的转译.我将在后续"合约解耦"一节种谈到这种可能性.
    服务可用性
    服务可用性(Availability)和服务响应能力(Responsiveness)是基于服务的架构通常需要考虑的另外两个问题.这两者都涉及服务客户与远程服务之间通信的能力,但他们还是有着轻微不同的内涵,因此客户也会采用不同方式来解决这两个问题.
    服务可用性是指远程服务及时地接受请求的能力,例如,与此远程服务建立连接.服务响应能力是指客户及时地从服务接收响应的能力.
    尽管这两种错误条件造成的结果是一样的(服务请求无法被处理),但是处理方式是不同的.因为服务可用性跟服务的可连接性有关,因此客户能够做的并不多,只能要么多试几次,要么在可能的情况下把请求放入队列,以后再处理.
    处理服务响应能力问题就更困难一些.请求成功地发送给服务之后,客户需要等待多久?是否服务仅仅是很慢,又或者服务端发生了什么事情导致无法发送响应?解决超时条件问题对于远程服务的可连接性来说是相当具有挑战性的.一种常见的做法是在有负载的情况下获得最长响应时间作为基准,然后在此基础上添加额外的时延以处理负载的波动.例如,假设运行某个基准测试时,某个特定服务请求的最大响应时间为2000毫秒.那么你可能需要将这个值乘以二,用以处理负载较高的状况,因此预期的超时时长应该是4000毫秒.
    尽管看起来这是一个合理的估算服务响应超时时长的解决方案,但有时也会有各种问题.首先,如果服务真的停止了或者未启动,每个请求都要等待四秒才能判定服务无响应.这实在是效率太低,而且会引起最终客户的不满意.另外一个问题在于,你所使用的基准测试可能并不精确,在高负载情况下,服务响应时间可能会是五秒而不是我们所算出来的四秒.这种情况下,服务端实际上能够做出响应,但是客户端会因为超时时长设得太低而拒绝了所有响应.
    比较常见的一种解决方案是使用断路器模式(circuit breaker pattern).如果服务不能及时做出响应或者干脆不响应,软件断路器将会起作用,提醒客户不必浪费时间等待超时事件发生.与物理断路器相比,软件断路器很不错的一点是在实现这种设计模式时,可以在服务端开始发送响应或者变得可用时对自己进行重置.软件断路器有不少开源实现,包括Netfix的Ribbon等.你可以在Michael Nygard的书Release It!中读到更多的关于断路器模式的内容.
    在处理超时时长值的问题时,应该尽量避免使用全局的超时值来处理每个请求.恰恰相反,建议你基于上下文来定义超时时长,同时确保这些数值可以从外部通过配置来设置,这样你就可以在负载条件变化的情况下快速做出响应,而不用重建或者重新部署应用.另一种方案是在代码中使用"智能超时值(smart timeout values)",以便在负载变化情况下自行调整超时值.例如,应用可以在高负载或者网络有问题的情况下自动增加超时时长值.当负载降低,响应时间变短后,应用可以重新计算平均响应时间,并对应地降低超时时长值.
    安全性
    在基于服务架构下,服务都是远程访问的,很重要的一点是需要确认给定的客户是否被授权访问某个特定服务.根据实际情况,服务的客户可能既需要被认证(authentication)也需要被授权(authorization).认证是指服务客户是否可以连接到某个服务,一般是通过用户名和密码来建立登录凭证来进行认证.某些情况下,仅仅执行认证还不够:客户可以连接到某个服务并不意味着他可以访问服务所提供的所有功能.授权指的是某个服务客户是否被允许访问服务内部特定的业务功能项.
    安全在早期SOA实现中是个大问题.原本被严格隔离的某个应用的功能突然被公开,从企业的全球各处都能访问到.这一变化所引发的问题促使我们换个角度思考,重新认识服务以及如何保护服务不会被不该访问的客户访问到.
    对微服务而言,安全问题成为挑战主要是因为没有一个专门处理安全问题的中间件组件.相反地,每个服务必须各自处理安全性问题,或者在某些情况下需要增强API层以使之更加智能地处理应用的安全性问题.我看到的微服务中所实现的一个比较好的设计是将认证工作委托给一个独立的服务,而保留授权工作在微服务内部.尽管这一设计可以修改为将认证和授权都交由单独的服务来完成,我还是倾向于将授权包含在微服务自身当中.这样做可以避免与远程安全性服务之间的太多的不必要交互,还可以使得服务的上下文边界更加稳定,减少对外界的依赖.
    事务
    事务管理在基于服务的架构中也是很大的挑战.大多数时候我们所讨论的事务是指在大量业务应用中都存在的ACID(atomicity、consistency、isolation和durability)事务.ACID事务用于维持数据库一致性,对同一个请求中的多个数据库更新操作进行协调,使得当事务处理过程中发生问题时,该请求所作出的所有数据库更新都可以回滚.
    考虑到基于服务的架构一般都是分布式架构,在多个远程服务之间传播和维护事务的上下文很困难.如图1-4所示,一个服务请求(红色X旁边的方框)可能需要调用多个远程服务来完成请求.红色X表明这种情况下无法实现ACID事务.
    事务问题在SOA架构中更为普遍,因为与微服务架构不同,SOA架构中通常使用多个服务来完成一个业务请求.我将在对比架构特点一章的"服务编排"一节中详细讨论这个问题.
    基于服务的架构一般更依赖于 BASE事务,而不是ACID事务.BASE事务一般包括基本的可用性、软性的状态和最终一致性(basic availability、soft state和eventual consistency).分布式应用依赖BASE事务来追求数据库中的最终一致性而不是每个中间事务的一致性.一个典型的BASE事务的例子是往ATM机里存钱.当通过ATM机向你的账户中存入现金,大概几分钟甚至几个小时后才会在账号中显现出来.换句话说,钱从离开自己的手到真正存入账户之间有一个软性的转换状态:钱已经离手,但是还没到达你的银行账户中.我们可以容忍这一延迟,并且寄希望于软状态和最终一致性,因为我们知道并信任这笔钱最终一定会到达我们的账号.从全系统视图的角度看,批处理作业也是依赖最终一致性的.
    迁移到到基于服务的架构需要我们改变对事务和一致性的认识.对于不能依赖最终一致性和软状态的而必需事务一致性的情况,可以将服务的粒度设计得较粗,从而把业务逻辑包装在一个服务内,最后通过ACID事务来实现事务级别的一致性.另一种方法是使用事件驱动技术,当请求状态变得一致时向相关客户推送通知.这种技术给应用带来了很高的复杂度,不过确实能够在使用BASE事务时实现事务状态管理.
    太复杂了?
    基于服务的架构相对于单体式应用来说是一种巨大的进步,但是正如你所看到的,他们同时也带来很多问题,例如服务合约、可用性、安全性以及事务管理等等.不幸的是,转向基于服务的架构,如微服务或者SOA,意味着必须在某些方面做出权衡.有鉴于此,除非做好准备并且原意去解决分布式系统所面对的种种问题,否则不要匆忙转向基于服务的架构.
    本节讨论的问题很复杂,但它们肯定不是不可克服的障碍.大多数使用基于服务的架构的团队最终都能顺利通过开源、商用和定制化的方案解决和克服这些问题.
    基于服务的架构是不是太复杂了?肯定是的.但是,事物总是两面的.伴随着复杂性,基于服务的架构也有一些额外的特性和能力,能够提高开发团队的效率,开发出更为可靠的、更为稳定的应用,同时降低总体开销并缩短产品进入市场的周期.接下来的三节中,我会对比微服务和SOA,帮助你了解哪种架构模式更适合自己.
    对比服务特性
    OASIS面向服务架构参考模型(OASIS Reference Model for Service Oriented Architecture)中将"服务"定义为"一种支持对一或多种能力进行访问的机制,这里的访问是通过使用预定义的接口来提供的,并且稳定地按照服务描述所规定的约束和策略来执行".换句话说,一个服务要提供某些业务能力,并提供定义良好的接口以及定义良好的合约以便(客户)进行访问.这个定义没有规定的是如何基于类别、组织所有关系以及粒度『如服务的规模』(classification、organizational ownership and granularity)来进一步地定义服务.理解这些服务特性有助于在特定架构模式下为服务的上下文给出定义.

    尽管微服务和SOA都有赖于服务作为其主要的架构组件,他们在服务特性上是有很大的差别的.本章将围绕不同模式下服务如何分类(也就是服务的分类学)、如何基于服务的所有者进行服务之间的协调以及微服务与SOA之间服务粒度上的不同展开讨论.

武汉PHP培训

    服务分类学
    服务分类学指的是在某种架构下服务是如何归类的.有两种服务分类的基本类型:服务类型和业务领域.服务类型分类法会根据整个架构中服务所扮演的角色进行分类.例如,某些服务是实现业务功能的,而另一些服务可能是实现非业务功能的,例如日志、审计和安全.业务领域分类法会根据服务在特定业务功能领域中所扮演的角色来进行分类,例如报表、交易处理和订单送货等等.
    服务类型分类一般在架构模式层进行定义,而业务领域分类则在架构实现层进行定义.尽管架构模式提供了很好的基础来定义服务类型,作为一个架构师,你可以按照自己的想法对其进行修改,定义自己的分类方法.本节中,我们会关注架构模式以及在微服务和SOA中比较常见的服务类型.
    微服务架构就服务类型而言其分类法并不复杂,一般来说主要有两类服务类型,如图2-1所示.功能服务(functional services)是指用来支持特定业务操作或功能的服务,而基础服务(infrastructure services)则负责支持非业务工作,例如认证、授权、审计、日志和监控.在微服务架构中,这是非常重要的区别,因为基础服务并不对外开放而仅作为供内部使用的私有共享服务,对其它服务可用.功能服务则提供外部访问能力,而且不对其它服务共享.
    SOA内的服务分类法跟微服务有很大不同.在SOA中,从全局架构来看有非常明确的、非常正式的服务类型,各自在整体架构中扮演不同角色.尽管在SOA中可以有任意数量的服务类型,架构模式定义了四种基本类型
    业务服务(business services)是一种抽象的、高层级的、粗粒度的服务,定义在企业层面的执行的核心业务操作.因为抽象,所以不依赖于任何实现或者协议,一般只包括服务名字,期望的输入以及期望的输出.可选地,这些服务类型还可以包括处理步骤或者跟服务相关的特殊编排规则.业务服务一般都用XML、Web Services Definition Language(WSDL)或者Business Process Execution Language(BPEL)等语言来表述.一般确认某个服务是否属于业务服务会在服务名上下文前后加上"我们是否在做某某的业务"来加以判断.例如,有两个服务,分别名为ProcessTrade(处理交易)和InsertCustomer(插入客户).那么"我们是否在做处理交易的业务"可以很清楚看出ProcessTrade是一个业务服务;而"我们是否在处理插入客户的业务"听上去就不对,所以不是一个好的业务服务抽象,更像是一个在处理业务服务时所调用的某个具体服务.
    企业服务(enterprise services)是具体的、企业层级的、粗粒度的服务,用以实现业务服务所定义的功能.如图2-2中所示,一般是介于抽象业务服务和对应具体企业服务实现之间的中间件,在其间起到桥梁作用.企业服务可以与业务服务之间存在一对一或一对多的对应关系.
    它们可以用任何语言和平台进行定制,或者采用第三方采购的产品(COTS)来实现.企业服务很独特的一点是它们通常会在组织内共享.例如,一个RetrieveCustomer(检索客户)的企业服务可能被组织内很多模块使用,用来接收客户信息.其它例如CheckTradeCompliance(检查交易合规) , CreateCustomer(创建客户), ValidateOrder(验证订单) 和 GetInventory(获取库存目录)等都是企业服务很好的例子.企业服务通常依赖应用服务(application services)和基础服务(infrastructure services)来完成特定业务请求.但是在某些情况下,某个企业服务也可能把完成特定请求所需要的所有业务功能都归入自身,形成自包含的服务.
    应用服务(application services)是细粒度的、特定于具体应用的服务,与某个特定应用的语境相关.应用服务提供在企业服务中没有的特定的业务功能.例如,一个大型保险公司汽车报价应用可能提供服务来计算汽车保险费率.这是一个只针对该应用而并不适用于整个企业的服务.应用服务可以从某个专用的用户界面直接调用,或者通过某个企业服务调用.应用服务的例子包括:AddDriver(添加司机)、AddVehicle(添加车辆)以及CalculateAutoQuote(计算机车报价)等等.
    SOA中最后一个基本服务类型是基础服务(infrastructure services).与微服务架构相同,这些服务用于实现非功能性任务,例如审计、安全和日志.在SOA中,基础服务可以从应用服务或者企业服务调用.
    需要记住的是,作为一个架构师,你既可以使用架构模式所提供的标准服务类型,也可以完全抛弃他们创建自己的分类方式.不管采用哪种方式,重要的事情是要确保针对架构存在定义良好且文档齐备的服务分类法.
    服务责任制与协调
    服务责任人(service owner)是组织内负责创建和维护某个服务的组别的类型.因为微服务架构仅支持有限的服务类型(功能服务和基础服务),应用开发团队一般都会同时负责这两种服务.尽管大量应用开发团队可能负责编写服务,需要了解的是他们都属于同一组别类型(即应用开发团队).
    对于SOA而言,一般对不同服务类型有不同服务责任人.业务服务的责任人通常是业务用户,而企业服务的责任人大多是是共享的服务团队或者架构师.应用服务的责任人一般是应用开发团队,基础服务的责任人一般是应用开发团队或者基础服务团队.中间件在SOA架构中经常使用,尽管不是一种服务,其责任人一般是整合架构师或者中间件团队.
    服务责任人的重要性体现在全局的服务协调.在SOA中,必须在创建或维护某个应用需求的时候在多个组之间进行协调.关于抽象的业务服务必须咨询业务用户,关于完成业务服务功能所需的企业服务必须咨询共享服务团队,应用开发团队之间必须相互协调才能保证企业服务可以调用底层功能.同样,必须协调基础团队来确保非功能性需求能够通过基础服务得到保障.最后,所有这些都需要与中间件团队或者管理消息中间件的整合架构师进行协调.
    在微服务场景中,完成某一业务请求通常只需要很少甚至完全不需要对多个服务进行协调.如果需要在多个服务责任人之间进行协调,也可以通过规模较小的应用开发团队快速而高效地完成.
    微服务和SOA在服务责任制和总体协调上的不同直接决定了两种架构模式下开发、测试、部署和维护服务上所需要的精力和时间.在这个问题上,微服务模式表现突出.因为服务比较轻量,各个组之间协调最少,服务可以很快被开发、测试、部署.而这些优势最终又转化为较短的投放市场周期、较低的开发和维护成本以及和更稳定的应用.
    服务粒度
    从服务角度来看微服务和SOA的最大区别在于服务粒度.如名字所示,微服务是规模较小的、细粒度的服务.更确切地说,微服务架构中的服务组件一般都是单一目的/用途的服务,只做一件事且做到极致.而对于SOA而言,服务组件规模相差可以很大,可能是很小的应用服务,也可以是很大的企业服务.实际上,很常见的一种情况是SOA架构中的某个服务组件是由一个很大规模的产品或者一个子系统来提供.
    有趣的是,SOA一开始碰到的最大挑战来自于服务粒度.如果不理解服务粒度影响,架构师很可能会设计粒度过细的服务,导致太多信息交互而影响整体性能.架构师和组件设计师很快学习到大规模的、粗粒度的、提供多种数据视图的服务是更好的服务模式.例如,相比较于太细粒度的数据读写服务,像GetCustomerAddress(获得客户地址)、GetCustomerName(获得客户名称)、UpdateCustomerName(更新客户名称)等等,架构师和共享服务团队更愿意采用部署企业级Customer(客户)服务的做法,用于处理更多粗粒度更新和接收数据视图,而把底层数据读写功能委托给并未开放给外部企业的应用级别服务.通过这种方式,像GetCustomerDemographics(获得客户统计数据)或者GetCustomerInformation(获取客户信息)之类的操作会返回一批客户数据,而不是单一的数据字段.
    粒度不同自然是跟服务组件的作用范围和功能差异相关.对于微服务而言,服务组件的功能(服务作用范围)倾向于做得较小,有时通过一两个模块就可以完成.对于SOA,服务倾向于包含尽量多的业务功能,有时会作为子系统(例如,索赔处理引擎或者库存系统)来实现.不过,SOA通常依赖于多个服务完成单个服务请求,而微服务却并不这样.我会在下一章的"服务编排"一节中详细讨论这个问题.
    无论使用微服务架构还是SOA,选择合适的粒度来设计服务并不是件容易的事情.服务粒度既影响性能也影响事务管理.服务的粒度太细时需要服务间通信来完成单一业务请求,从而导致大量的远程服务请求,占用掉宝贵的时间.
    在处理服务粒度时,我发现从粗粒度服务开始会更容易一些.随着对服务的用法的了解逐渐增加,不妨再考虑如何对其进行拆分.如Sam Newman在Building Microservices书中所说,"从少数几个大服务开始".只需要观察事务问题和服务之间通信量,尤其是在微服务架构下,如果发生相关问题很可能说明服务可能粒度太细了.
    粒度与模式选择
    本章所描述的三个服务特性中,服务粒度在根据情况进行架构模式选择的过程中具有最重要的潜在影响.微服务中规模很小的、细粒度的服务概念使得这种架构模式能够提升软件开发生命周期中的各个方面,包括开发、测试、部署和维护.尽管采用粗粒度服务肯定会解决性能和事务问题,这一转变反过来肯定也会给开发、测试、部署和维护带来负面影响.如果发现服务规模从小变大,那么最好选择SOA模式而不是更为简单的微服务架构模式.不过,如果能够将应用的业务功能分解为很小的、互相独立的部分,微服务模式应该是更好的选择.
    当比较微服务和SOA架构时,除了以上服务特性外,还有很多其他方面需要考虑.下一章中,我们会更多地从全局角度比较这些架构方面,包括每种模式下组件共享水平、服务编排与布置、使用中间件或简单API层以及如何访问远程服务等方面的不同.

    更多武汉PHP培训相关咨询,请扫描下方二维码

武汉PHP培训

上一篇:十年程序员用眼告诉你 2018 PHP 不一样
下一篇:在 PHP 7 中不要做的 10 件事

能够提高PHP程序员效率的小妙招

想要学好PHP要怎么做

你学php准备做什么工作呢

PHP前景如何,现在学PHP还有前途吗?

选择城市和中心
贵州省

广西省

海南省