当前位置:CIO技术探讨 → 正文

如何过渡到微服务架构

责任编辑:cres 作者:Parminder Singh Kocher |来源:企业网D1Net  2019-01-04 10:16:45 原创文章 企业网D1Net

当你遇到可扩展性问题或发现该问题已经变得代价高昂,并且你很难以对整体式应用程序进行定期的更新时,那么你是时候转向微服务方法了。下面来看看怎么做。
 
至此,你知道了微服务的定义和工作原理,现在是时候开始着手解决问题了:即如何实现向微服务过渡。
 
对微服务过渡的需求
 
整体式应用程序十分庞大(就代码行而言),也十分复杂(就功能相互依赖性、数据等方面而论),它为各大地理区域的数十万用户提供服务,它需要多个开发人员和IT工程师的参与。整体式应用程序可能类似于图1所呈现的样子。
 
有时,即使具备所有这些特性,应用程序一开始也许能正常运行。你可能不会遇到应用程序可扩展性或性能方面的难题。但随着时间的推移和使用的增加,问题会显现出来,而不同的应用程序会出现不同的问题。
 
例如,对于云应用程序或网络应用程序,由于有更多用户使用你的服务,你可能会遇到扩展性问题,又或者是由于耗时更长的构建时间和回归测试,云应用程序或网络应用程序可能会变得十分昂贵,而且你很难发布常规的新更新。如图2所示,整体式应用程序的用户或开发人员可能会遇到右侧列出的一个或多个问题。
 
 
 
那时,向微服务迁移就不仅仅是一个时髦的想法了,这听起来就像是救命稻草。迁移将类似于图3中所示的应用程序。
 
 
那么,你如何做出这样的改变呢?有两种可能的情况:
 
• 创建全新的应用程序。
• 转换或迁移已存在的单一应用程序。
 
后一种情况的可能性更大,但无论你目前处于什么样的情况,了解这两种情况的来龙去脉是值得的。
 
使用微服务创建新的应用程序
 
我还没有发现多少从头开始构建基于微服务的应用程序的真实场景。通常情况是,应用程序已经到位,我所研究的大多数应用程序中,从整体式架构过度到微服务架构的情况更常见。在这些例子中,架构师和开发人员的意图一直是重用一些现有的实施方案。但由于各种技能在市场上唾手可得,一些成功的实现方案已经公布,我们将看到更多从头开始构建基于微服务的应用程序的例子,因此探索这种情况当然是值得的。
 
假设你已经了解了所有要求,你已经着手设计你要构建的应用程序的架构。在你开始时,有很多常见的最佳实践可供你考虑,这些实践将在以下各节中逐一介绍。
 
组织的就绪情况
 
你必须问自己的第一个问题是,你的组织是否已准备好过渡到微服务。这意味着贵组织的各个部门现在需要以下列方式对构建和发布软件进行不同的思考:
 
• 团队结构。整体性应用程序团队(如果有这么一个团队)必须分解为几个高绩效的团队,这些团队已经了解微服务的最佳实践或接受过微服务最佳实践方面的培训。如图3所示,新系统将由一系列独立服务构成,各个独立服务负责提供特定的服务。这是微服务范式的一个关键优势:它减少了通信方面的开销,包括多个连续不断的会议。团队试图解决什么业务问题或领域,就按什么形式进行组织。于是乎,通信就关系到人们要遵循的时间和一系列标准/协议,以便这些微服务可以作为一个彼此协作的平台。
• 所有的团队都必须做好准备,独立于其他团队运作。团队必须达到标准的Scrum团队的规模;否则,沟通将再次成为问题。执行力是关键,所有的团队都必须能够满足不断变化的业务需求。
• 工具和培训。组织是否已经准备好投资新工具和人员培训,这是关键需求之一。在大多数情况下,组织必须淘汰现有的工具和流程,转而采用新的工具和流程。这将需要投入大量的资本,花钱雇用具备新技能的人并重新培训现有的员工。从长远来看,如果采用微服务的决定是正确的,那么组织将节约成本并收回投资。
 
基于服务的方法
 
与整体式应用程序不同,对于微服务,你需要采用自足的,基于服务的方法。将你的应用程序设想为一系列松散地结合在一起的服务,这些服务相互通信以提供完整的应用程序功能。每项服务都必须被视为一项独立的,完备的服务,其自身的生命周期可由独立的团队进行开发和维护。这些团队可以从各种技术中进行选择,包括最适合其服务需求的语言或数据库。
 
例如,对于电子商务站点,团队会编写完全独立的服务,如购物车方面的微服务(具备内存数据库),以及另一个服务,如下单方面的微服务(具备关系数据库)。实际的应用程序可以将微服务用于基本功能,例如身份验证、账户、用户注册和通知,这些功能的业务逻辑封装在API网关中,该API网关基于客户端和外部请求调用这些微服务。
 
提醒一下:微服务可能是单个开发人员所实现的小型服务,或者是由需要几个开发人员开发的复杂服务所实现的小型服务。由于使用了微服务,规模不再重要;这一切都要看情况,即某个服务必须提供的一个特定的功能。
 
此时人们还必须考虑其它方面,如扩展能力、性能和安全性。扩展能力方面的需求可能各不相同,并且在每个微服务级别按需提供这种需求。所有级别的安全性都必须予以考虑,包括静态数据、进程间通信、动态数据等。
 
进程间(服务到服务的)通信
 
安全性和通信协议是必须考虑的关键方面。异步通信是最佳选择,因为它可以使所有请求按计划进行,并且不会长时间占用资源。
 
使用RabbitMQ之类的消息总线可能有助于这种通信。RabbitMQ很简单,并且每秒可以达到数十万条消息的规模。为了防止消息传递系统在发生故障时成为单点故障,你必须正确设计消息传递总线以实现更高的可用性。除RabbitMQ外还有其它选择,如ActiveMQ,这是另一个轻量级消息传递平台。
 
安全性是现阶段的关键。除了选择正确的通信协议之外,人们还可以使用AppDynamics等行业标准的工具来监视进程间通信并以此作为衡量标准。所有的异常情况都必须自动向安全团队发出报告。
 
当微服务的数量达到数千个时,事情的处理就变得很复杂。我会在第三章中解释如何通过发现服务(discovery service)和API网关解决此类问题。
 
选择技术
 
过渡到微服务的最大优势是,它使选择更加多样化。每个团队都可以独立选择最适合既定微服务使用的语言、技术、数据库等。在整体式方式中,团队通常不具备这种灵活性,因此请确保你不会忽视机会,更不要错过机会。
 
即使一个团队正在处理多个微服务,每个微服务也必须被视为一个完备的服务,并且要对这些微服务进行分析。在为每个微服务选择技术时,请必须牢记扩展性、部署、构建时间、集成和插件的可操作性等因素。对于具有较轻巧的数据但访问速度较快的微服务,内存数据库也许是最佳选择,而其它数据库则可能共享相同的关系数据库或NoSQL数据库。
 
实施
 
实施是关键阶段;这是所有培训和最佳实践方面的知识派上用场的地方。你要记住的一些关键方面包括:
 
• 独立性。每个微服务都必须具备高度自主性,有自己的生命周期并以这种方式得到处理。独立性需要开发和维护,而不依赖于其它微服务。
• 源代码控制。安装适当的版本控制系统是必须的,每个微服务必须遵循标准。将存储库标准化也很有用,因为这可以确保所有团队使用相同的源代码控制机制。这在各方面都有所帮助(例如代码评估),使人们可以在一个地方轻松地访问所有的代码。从长远来看,用同一个源代码来控制所有的服务是有意义的。
• 环境。所有不同的环境(例如开发、测试、阶段和生产)必须得到适当的保护,实现适当的自动化。这里的自动化包括构建过程;这样代码就可以根据需要进行集成,每天都要进行集成。虽然Jenkins得到了广泛的使用,但还有几种工具可供人们使用。Jenkins是一个开源工具,这个工具有助于将软件构建自动化,有助于发布过程,包括持续集成和持续交付(CI / CD)。
• 自动防止故障。一切都有可能出错,而软件故障是不可避免的。必须在微服务开发中解决下游服务的故障处理问题。即使其它的服务失败了,也必须失败得优雅些,以至于用户不能看到失败。这包括管理服务响应时间(超时),处理下游服务的API更改并限制自动重试的次数。
 
使用微服务时,不要害怕用复制粘贴的办法来重用代码,但要有限度。这可能会导致一些代码重复,但总比使用共享的代码要好,共享的代码最终可能会产生耦合的服务(coupling service)。在微服务中,你需要去耦合,而不需要紧耦合(tight coupling)。例如,你将编写代码,以使用服务的输出响应。每次从任意一个客户端调用相同的服务时,你都可以复制此代码。重用代码的另一种方法是创建公共库。多个客户端可以使用相同的库,但每个客户端必须负责库的维护。
 
当你创建太多库,并且每个客户端要维护不同版本的库时,这有时极具挑战性。在这种情况下,你可能必须包含同一个库的多个不同版本,并且由于向后兼容性问题和类似的问题,构建过程可能会变得十分困难。根据你的需要,只要你可以通过客户端控制库的数量和版本的数量,并对其实施严格的流程,你就可以采用任何一种方式。这肯定会让你避免大量的代码重复。
 
鉴于微服务的庞大数量,对问题进行调试可能会变得十分困难,因此你需要在此阶段进行某种检测。其中一个最佳实践就是,使用唯一的请求ID标记每个请求并记录每个请求。此唯一ID能发现原始请求,并且应由各个服务将其传递给所有的下游请求。
 
当你看到问题时,你可以清楚地追溯日志并发现有问题的服务。如果你建立了一个集中化的日志记录系统,此解决方案将最有效。所有服务都应用标准格式将所有消息记录到此共享系统,以便团队可以根据需要从一个地方(从基础设施到应用程序)重现事件。用于集中式日志记录的共享库是值得研究的。市场上有几种日志管理和聚合工具(例如ELK(Elasticsearch,Logstash,Kibana)和Splunk),它们都十分理想。
 
部署
 
自动化是部署过程中的关键。如果没有自动化,微服务范式几乎是不可能成功的。微服务也许有成百上千个,但对敏捷交付来说,自动化是必须的。
 
试想一下部署数千个微服务并对其进行维护的情景。当其中一个微服务发生故障时会怎样?你怎么知道哪台机器有足够的资源来运行你的微服务?在自动化没有到位的情况下管理这种故障变得非常复杂。而Kubernetes和Docker Swarm等各种工具则可以将部署过程自动化。
 
运营
 
该过程的操作部分也必须自动化。再说一次,我谈论的是数百上千个微服务——因此组织的能力必须十分成熟,成熟到能够处理这种级别的复杂度。你需要一个支持系统,包括以下东西:
 
• 从基础设施、应用程序API乃至最终的性能,一切都必须受到监控,一切都必须实施能在适当阈值下触发的自动警报。不妨创建一个实时的仪表盘,在问题出现期间,仪表盘会显示数据并发出警报。
• 按需的扩展性。有了微服务,扩展性就成了最简单的任务。提供你想要扩展的微服务的另一个实例,并将其放在现有的负载均衡器之后;一切就设置好了。但在规模化的环境中,这也需要自动化。这关系到设置一个整数值来分辨你要为特定微服务运行的实例数。
• API的曝光度。在大多数情况下,你希望在外部公开API,以供外部用户使用。最好用边缘服务器来完成,因为它可以处理所有外部请求。边缘服务器可以使用API网关和发现服务来完成工作,你可以为每种设备类型(例如移动设备或浏览器)或用例使用一个边缘服务器。网飞创建了一个名为Zuul的开源应用程序,该程序可用于此功能及其它功能。
• 断路器(Circuit breaker)。向失败的服务发送请求毫无意义。因此,你可以构建一个断路器,这个断路器可以追踪向每个服务发出的每一个请求是否成功。在多个故障发生的情况下,在一段时间内,你应该阻止对该特定服务发出的所有请求(“断开电路”)。在设定的时间到期后应该发出下一个请求,依此类推。一旦响应成功就重新连接电路。这必须在服务实例的级别上完成。网飞的Hystrix提供了一个实施开源断路器的方案。
 
将整体式应用程序迁移到微服务
 
虽然构建基于微服务的新应用程序的大多数最佳实践也适用于从现有的整体式应用程序进行迁移,还有一些额外的准则(但是如果遵循这些准则)可以使迁移变得更简单,更高效。
 
虽然将整个整体式应用程序转换为完全基于微服务的应用程序的做法看似正确,但在某些情况下,将每个功能转换为微服务,这可能并不高效,或成本可能非常高。毕竟,你最终可能会从头开始编写应用程序。正确的迁移方法可能是渐进式方法,如图4所示。
 
 
接下来的问题是:从哪里开始使用当前的整体式应用程序?如果应用程序真的很旧,很耗时且难以拆分(也就是说,如果内聚性的程度很高的话),那么从头开始可能会更好。在其他情况下,即可以快速禁用部分代码并且技术架构没有完全过时,那么你最好先将组件重建为微服务并替换旧代码。
 
微服务标准
 
于是乎,问题就变成了应该先迁移什么组件,甚至变成了迁移组件是否有必要。这让我想到了我所谓的“微服务标准”,微服务标准概述了多种可能方法中的一种方法,即选择应该迁移到微服务的功能并确定其优先级。微服务标准就是你建立的一系列规则,这些规则可以根据组织此刻的需要将现有的整体式应用程序组件转换为微服务,要么可以转换,要么不能。
 
这里所说的“时间”非常重要,因为随着时间的推移,组织的需求可能会发生变化,你可能不得不回过头来,在晚些时候将更多组件转换为微服务。换句话说,随着需求的变化,整体式应用程序的其它组件可能会具备转化为微服务的资格。
 
以下是在转换过程中可被视为微服务标准的最佳做法:
 
• 你需要确定哪些功能用得多。首先将频频使用的服务或应用程序功能转换为微服务。请记住:微服务只执行一个有明确定义的服务。牢记这一原则并相应地对应用程序进行划分。
• 你很可能会碰到性能不佳的组件,但你还有其它的组件可选择。你也许有开源的插件可用,或者你可能想从头开始构建服务。请记住,微服务的边界是很关键的东西。只要你设计微服务的目的是让它单单把一件事做好,那就没问题。确定服务的边界往往很难,你会发现,只要多实践,边界就更容易确定了。考察微服务边界的另一种方法是,你必须在几周内(如果必须这么做的话)重写整个微服务,而不是花费几个月的时间来重写服务。
• 更好的技术替代方案或多语言编程。领域特定语言(Domain-specific language)可用于解决问题域(problem domain)方面的问题。这尤其适用于各种组件,即你过去收到大量增强请求的组件,而你希望这些能够继续收到这样的请求。使用市面上的新语言或功能不仅可以将此类组件的实施工作简化,而且还可以使未来的维护和更新变得更加容易,如果你是这么认为的,那么现在正是解决此类更改的正确时机。在其他情况下,你可能会发现,另一种语言提供的并发抽象比当前使用的抽象更容易。你可以将新语言用于已知的微服务,而应用程序的其余部分仍然可以使用不同的语言。同样,你可能希望某些微服务的速度变得非常快,你还有可能决定用C语言编写这些微服务,以获得最大的收益,而不是用另一种高级语言编写。利用这种灵活性才是最重要的。
• 存储方面的替代方案或多混合持久化(polyglot persistence)。随着大数据的兴起,应用程序的某些组件可能会通过NoSQL数据库而不是关系数据库来实现价值。如果应用程序中任何一个诸如此类的组件可能从此替代方案中受益,那么这可能是转向NoSQL的合适时机。
 
这就是你必须考虑的关键方面,即你必须考虑整体式应用程序中的每个服务或功能,你首先要优先处理这些项目的转化工作。一旦你从高优先级项目得出数值,你就可以应用其它规则。
 
• 修改方面的请求。在所有软件的生命周期中追踪新的改善请求或更改,这是一件很重要的事情。由于受到构建时间和部署时间的限制,需要频频修改功能很适合微服务。将这些服务分离就可以减少构建时间和部署时间,因为你不必构建整个应用程序,只需更改微服务,这也可能会增加应用程序其余部分的可用时间。
• 应用程序的某些部分总是会增加部署的复杂性。在整体式应用程序中,即使特定功能未受影响,你仍然必须完成整个构建和部署过程。如果存在这样的情况,去除应用程序的这些部分并用微服务取而代之,这大有裨益,这样你就可以减少整个应用程序其余部分的总体部署时间。在我们了解容器后,我们会详细讨论这种做法。
• 辅助服务(Helper service)。在大多数应用程序中,核心服务或主服务依赖于某些帮助程序服务。这些辅助功能的可用性可能会影响核心服务的可用性。例如,在服务台应用程序中,工单服务取决于产品目录服务。如果产品目录服务不可用,则用户无法提交要求解决问题的工单。如果存在这种情况,你必须将辅助服务转换为微服务并以合适的方式使其具有高度的可用性,以便辅助服务可以更好地为核心服务提供服务。(这些服务也称为断路服务(circuit-breaker service)。)
 
根据应用程序的不同,这些标准可能需要将大多数服务转换为微服务,不过这也没关系。这里的目的是简化转换过程,以便你可以确定路线图的优先事项并对其进行定义,即迁移到基于微服务的架构的路线图。
 
为服务重建架构
 
一旦你确定了要作为微服务迁移的功能,你就可以按照早期方案中的最佳实践开始重新架构所选的服务。以下是需要注意的方面:
 
• 微服务定义。为每个功能定义合适的微服务,这些微服务应包括通信机制(API)、技术定义等。试想一下你的现有功能所使用的数据,或相应地创建和规划微服务的数据策略。如果该函数在甲骨文这样体量较大的数据库上,那么移植到MySQL是否有意义?你要确定如何管理数据关系。最后,将每个微服务用作单独的应用程序。
• 重构代码。如果你不换用编程语言,你就可以重用某些代码。以存储/数据库层为例——共享与专用,在内存中与在外部。我们的目标不是添加新功能(除非真的有必要),而是重新打包现有代码并公开所需的API。
• 在开始编码之前,请确定源代码控制机制和版本控制机制,并确保这些标准得到了遵循。每个微服务都是一个单独的项目,并作为单独的应用程序部署。
• 数据迁移。如果你决定创建新的数据库,那么你还必须迁移旧数据。这通常是通过编写简单的SQL脚本来处理,具体取决于你的源和目标。
• 整体式代码。为了防止不得不回滚的问题,你一开始就得将现有代码留在整体式应用程序中。你要么更新其余的代码以使用新的微服务,要么分割应用程序流量(如果可能的话),从而使用整体式版本和微服务版本,第二种情况更好。这样你就有机会测试性能并关注性能。一旦有把握,你就可以将所有流量移动到微服务并禁用旧代码或将其删除。
• 独立的构建、部署和管理。独立地构建和部署每个微服务。在推出新版本的微服务时,你可以在一段时间内划分旧版本和新版本之间的流量。这意味着你可能在生产环境中运行同一个微服务的两个版本或更多版本。某些用户流量可以被转至新的微服务版本,以确保服务正常运行。如果新版本没有以最佳方式工作,或没有按预期执行,那么将所有的流量回滚到先前的版本并继续对新版本进行开发则变得很容易。这里的关键是,建立可重复的自动部署流程并转向持续交付。
•旧代码删除。如果你还没有确认一切都得到了妥善的迁移并按预期运作,那你就不能删除临时代码并从旧存储位置删除数据。请务必在此过程中进行备份。
 
微服务的混合方法
 
在编写全新的应用程序时,开发人员可以直接遵循微服务架构的原则和蓝图来构建软件应用程序。
 
开发人员有时会遵循一种将微服务和整体性应用程序混合起来的方法。在这种情况下,他们可以将部分应用程序开发为微服务,其余部分则遵循基于特定标准的标准SOA/MVC实践(译注:SOA即面向服务的架构,MVC即模型-视图-控制器模式)。这个想法就是,并非应用所有的应用程序组件都可以用作微服务。
 
微服务提供了很大的灵活性,但这种灵活性部署是没有代价的。混合方法就是在灵活性和成本之间取得平衡,条件是,组件最终可以从整体性部件中提取出来并根据需要转换为微服务。关键是在此过渡期间牢记这两种方法和微服务标准。

关键字:

原创文章 企业网D1Net

x 如何过渡到微服务架构 扫一扫
分享本文到朋友圈
当前位置:CIO技术探讨 → 正文

如何过渡到微服务架构

责任编辑:cres 作者:Parminder Singh Kocher |来源:企业网D1Net  2019-01-04 10:16:45 原创文章 企业网D1Net

当你遇到可扩展性问题或发现该问题已经变得代价高昂,并且你很难以对整体式应用程序进行定期的更新时,那么你是时候转向微服务方法了。下面来看看怎么做。
 
至此,你知道了微服务的定义和工作原理,现在是时候开始着手解决问题了:即如何实现向微服务过渡。
 
对微服务过渡的需求
 
整体式应用程序十分庞大(就代码行而言),也十分复杂(就功能相互依赖性、数据等方面而论),它为各大地理区域的数十万用户提供服务,它需要多个开发人员和IT工程师的参与。整体式应用程序可能类似于图1所呈现的样子。
 
有时,即使具备所有这些特性,应用程序一开始也许能正常运行。你可能不会遇到应用程序可扩展性或性能方面的难题。但随着时间的推移和使用的增加,问题会显现出来,而不同的应用程序会出现不同的问题。
 
例如,对于云应用程序或网络应用程序,由于有更多用户使用你的服务,你可能会遇到扩展性问题,又或者是由于耗时更长的构建时间和回归测试,云应用程序或网络应用程序可能会变得十分昂贵,而且你很难发布常规的新更新。如图2所示,整体式应用程序的用户或开发人员可能会遇到右侧列出的一个或多个问题。
 
 
 
那时,向微服务迁移就不仅仅是一个时髦的想法了,这听起来就像是救命稻草。迁移将类似于图3中所示的应用程序。
 
 
那么,你如何做出这样的改变呢?有两种可能的情况:
 
• 创建全新的应用程序。
• 转换或迁移已存在的单一应用程序。
 
后一种情况的可能性更大,但无论你目前处于什么样的情况,了解这两种情况的来龙去脉是值得的。
 
使用微服务创建新的应用程序
 
我还没有发现多少从头开始构建基于微服务的应用程序的真实场景。通常情况是,应用程序已经到位,我所研究的大多数应用程序中,从整体式架构过度到微服务架构的情况更常见。在这些例子中,架构师和开发人员的意图一直是重用一些现有的实施方案。但由于各种技能在市场上唾手可得,一些成功的实现方案已经公布,我们将看到更多从头开始构建基于微服务的应用程序的例子,因此探索这种情况当然是值得的。
 
假设你已经了解了所有要求,你已经着手设计你要构建的应用程序的架构。在你开始时,有很多常见的最佳实践可供你考虑,这些实践将在以下各节中逐一介绍。
 
组织的就绪情况
 
你必须问自己的第一个问题是,你的组织是否已准备好过渡到微服务。这意味着贵组织的各个部门现在需要以下列方式对构建和发布软件进行不同的思考:
 
• 团队结构。整体性应用程序团队(如果有这么一个团队)必须分解为几个高绩效的团队,这些团队已经了解微服务的最佳实践或接受过微服务最佳实践方面的培训。如图3所示,新系统将由一系列独立服务构成,各个独立服务负责提供特定的服务。这是微服务范式的一个关键优势:它减少了通信方面的开销,包括多个连续不断的会议。团队试图解决什么业务问题或领域,就按什么形式进行组织。于是乎,通信就关系到人们要遵循的时间和一系列标准/协议,以便这些微服务可以作为一个彼此协作的平台。
• 所有的团队都必须做好准备,独立于其他团队运作。团队必须达到标准的Scrum团队的规模;否则,沟通将再次成为问题。执行力是关键,所有的团队都必须能够满足不断变化的业务需求。
• 工具和培训。组织是否已经准备好投资新工具和人员培训,这是关键需求之一。在大多数情况下,组织必须淘汰现有的工具和流程,转而采用新的工具和流程。这将需要投入大量的资本,花钱雇用具备新技能的人并重新培训现有的员工。从长远来看,如果采用微服务的决定是正确的,那么组织将节约成本并收回投资。
 
基于服务的方法
 
与整体式应用程序不同,对于微服务,你需要采用自足的,基于服务的方法。将你的应用程序设想为一系列松散地结合在一起的服务,这些服务相互通信以提供完整的应用程序功能。每项服务都必须被视为一项独立的,完备的服务,其自身的生命周期可由独立的团队进行开发和维护。这些团队可以从各种技术中进行选择,包括最适合其服务需求的语言或数据库。
 
例如,对于电子商务站点,团队会编写完全独立的服务,如购物车方面的微服务(具备内存数据库),以及另一个服务,如下单方面的微服务(具备关系数据库)。实际的应用程序可以将微服务用于基本功能,例如身份验证、账户、用户注册和通知,这些功能的业务逻辑封装在API网关中,该API网关基于客户端和外部请求调用这些微服务。
 
提醒一下:微服务可能是单个开发人员所实现的小型服务,或者是由需要几个开发人员开发的复杂服务所实现的小型服务。由于使用了微服务,规模不再重要;这一切都要看情况,即某个服务必须提供的一个特定的功能。
 
此时人们还必须考虑其它方面,如扩展能力、性能和安全性。扩展能力方面的需求可能各不相同,并且在每个微服务级别按需提供这种需求。所有级别的安全性都必须予以考虑,包括静态数据、进程间通信、动态数据等。
 
进程间(服务到服务的)通信
 
安全性和通信协议是必须考虑的关键方面。异步通信是最佳选择,因为它可以使所有请求按计划进行,并且不会长时间占用资源。
 
使用RabbitMQ之类的消息总线可能有助于这种通信。RabbitMQ很简单,并且每秒可以达到数十万条消息的规模。为了防止消息传递系统在发生故障时成为单点故障,你必须正确设计消息传递总线以实现更高的可用性。除RabbitMQ外还有其它选择,如ActiveMQ,这是另一个轻量级消息传递平台。
 
安全性是现阶段的关键。除了选择正确的通信协议之外,人们还可以使用AppDynamics等行业标准的工具来监视进程间通信并以此作为衡量标准。所有的异常情况都必须自动向安全团队发出报告。
 
当微服务的数量达到数千个时,事情的处理就变得很复杂。我会在第三章中解释如何通过发现服务(discovery service)和API网关解决此类问题。
 
选择技术
 
过渡到微服务的最大优势是,它使选择更加多样化。每个团队都可以独立选择最适合既定微服务使用的语言、技术、数据库等。在整体式方式中,团队通常不具备这种灵活性,因此请确保你不会忽视机会,更不要错过机会。
 
即使一个团队正在处理多个微服务,每个微服务也必须被视为一个完备的服务,并且要对这些微服务进行分析。在为每个微服务选择技术时,请必须牢记扩展性、部署、构建时间、集成和插件的可操作性等因素。对于具有较轻巧的数据但访问速度较快的微服务,内存数据库也许是最佳选择,而其它数据库则可能共享相同的关系数据库或NoSQL数据库。
 
实施
 
实施是关键阶段;这是所有培训和最佳实践方面的知识派上用场的地方。你要记住的一些关键方面包括:
 
• 独立性。每个微服务都必须具备高度自主性,有自己的生命周期并以这种方式得到处理。独立性需要开发和维护,而不依赖于其它微服务。
• 源代码控制。安装适当的版本控制系统是必须的,每个微服务必须遵循标准。将存储库标准化也很有用,因为这可以确保所有团队使用相同的源代码控制机制。这在各方面都有所帮助(例如代码评估),使人们可以在一个地方轻松地访问所有的代码。从长远来看,用同一个源代码来控制所有的服务是有意义的。
• 环境。所有不同的环境(例如开发、测试、阶段和生产)必须得到适当的保护,实现适当的自动化。这里的自动化包括构建过程;这样代码就可以根据需要进行集成,每天都要进行集成。虽然Jenkins得到了广泛的使用,但还有几种工具可供人们使用。Jenkins是一个开源工具,这个工具有助于将软件构建自动化,有助于发布过程,包括持续集成和持续交付(CI / CD)。
• 自动防止故障。一切都有可能出错,而软件故障是不可避免的。必须在微服务开发中解决下游服务的故障处理问题。即使其它的服务失败了,也必须失败得优雅些,以至于用户不能看到失败。这包括管理服务响应时间(超时),处理下游服务的API更改并限制自动重试的次数。
 
使用微服务时,不要害怕用复制粘贴的办法来重用代码,但要有限度。这可能会导致一些代码重复,但总比使用共享的代码要好,共享的代码最终可能会产生耦合的服务(coupling service)。在微服务中,你需要去耦合,而不需要紧耦合(tight coupling)。例如,你将编写代码,以使用服务的输出响应。每次从任意一个客户端调用相同的服务时,你都可以复制此代码。重用代码的另一种方法是创建公共库。多个客户端可以使用相同的库,但每个客户端必须负责库的维护。
 
当你创建太多库,并且每个客户端要维护不同版本的库时,这有时极具挑战性。在这种情况下,你可能必须包含同一个库的多个不同版本,并且由于向后兼容性问题和类似的问题,构建过程可能会变得十分困难。根据你的需要,只要你可以通过客户端控制库的数量和版本的数量,并对其实施严格的流程,你就可以采用任何一种方式。这肯定会让你避免大量的代码重复。
 
鉴于微服务的庞大数量,对问题进行调试可能会变得十分困难,因此你需要在此阶段进行某种检测。其中一个最佳实践就是,使用唯一的请求ID标记每个请求并记录每个请求。此唯一ID能发现原始请求,并且应由各个服务将其传递给所有的下游请求。
 
当你看到问题时,你可以清楚地追溯日志并发现有问题的服务。如果你建立了一个集中化的日志记录系统,此解决方案将最有效。所有服务都应用标准格式将所有消息记录到此共享系统,以便团队可以根据需要从一个地方(从基础设施到应用程序)重现事件。用于集中式日志记录的共享库是值得研究的。市场上有几种日志管理和聚合工具(例如ELK(Elasticsearch,Logstash,Kibana)和Splunk),它们都十分理想。
 
部署
 
自动化是部署过程中的关键。如果没有自动化,微服务范式几乎是不可能成功的。微服务也许有成百上千个,但对敏捷交付来说,自动化是必须的。
 
试想一下部署数千个微服务并对其进行维护的情景。当其中一个微服务发生故障时会怎样?你怎么知道哪台机器有足够的资源来运行你的微服务?在自动化没有到位的情况下管理这种故障变得非常复杂。而Kubernetes和Docker Swarm等各种工具则可以将部署过程自动化。
 
运营
 
该过程的操作部分也必须自动化。再说一次,我谈论的是数百上千个微服务——因此组织的能力必须十分成熟,成熟到能够处理这种级别的复杂度。你需要一个支持系统,包括以下东西:
 
• 从基础设施、应用程序API乃至最终的性能,一切都必须受到监控,一切都必须实施能在适当阈值下触发的自动警报。不妨创建一个实时的仪表盘,在问题出现期间,仪表盘会显示数据并发出警报。
• 按需的扩展性。有了微服务,扩展性就成了最简单的任务。提供你想要扩展的微服务的另一个实例,并将其放在现有的负载均衡器之后;一切就设置好了。但在规模化的环境中,这也需要自动化。这关系到设置一个整数值来分辨你要为特定微服务运行的实例数。
• API的曝光度。在大多数情况下,你希望在外部公开API,以供外部用户使用。最好用边缘服务器来完成,因为它可以处理所有外部请求。边缘服务器可以使用API网关和发现服务来完成工作,你可以为每种设备类型(例如移动设备或浏览器)或用例使用一个边缘服务器。网飞创建了一个名为Zuul的开源应用程序,该程序可用于此功能及其它功能。
• 断路器(Circuit breaker)。向失败的服务发送请求毫无意义。因此,你可以构建一个断路器,这个断路器可以追踪向每个服务发出的每一个请求是否成功。在多个故障发生的情况下,在一段时间内,你应该阻止对该特定服务发出的所有请求(“断开电路”)。在设定的时间到期后应该发出下一个请求,依此类推。一旦响应成功就重新连接电路。这必须在服务实例的级别上完成。网飞的Hystrix提供了一个实施开源断路器的方案。
 
将整体式应用程序迁移到微服务
 
虽然构建基于微服务的新应用程序的大多数最佳实践也适用于从现有的整体式应用程序进行迁移,还有一些额外的准则(但是如果遵循这些准则)可以使迁移变得更简单,更高效。
 
虽然将整个整体式应用程序转换为完全基于微服务的应用程序的做法看似正确,但在某些情况下,将每个功能转换为微服务,这可能并不高效,或成本可能非常高。毕竟,你最终可能会从头开始编写应用程序。正确的迁移方法可能是渐进式方法,如图4所示。
 
 
接下来的问题是:从哪里开始使用当前的整体式应用程序?如果应用程序真的很旧,很耗时且难以拆分(也就是说,如果内聚性的程度很高的话),那么从头开始可能会更好。在其他情况下,即可以快速禁用部分代码并且技术架构没有完全过时,那么你最好先将组件重建为微服务并替换旧代码。
 
微服务标准
 
于是乎,问题就变成了应该先迁移什么组件,甚至变成了迁移组件是否有必要。这让我想到了我所谓的“微服务标准”,微服务标准概述了多种可能方法中的一种方法,即选择应该迁移到微服务的功能并确定其优先级。微服务标准就是你建立的一系列规则,这些规则可以根据组织此刻的需要将现有的整体式应用程序组件转换为微服务,要么可以转换,要么不能。
 
这里所说的“时间”非常重要,因为随着时间的推移,组织的需求可能会发生变化,你可能不得不回过头来,在晚些时候将更多组件转换为微服务。换句话说,随着需求的变化,整体式应用程序的其它组件可能会具备转化为微服务的资格。
 
以下是在转换过程中可被视为微服务标准的最佳做法:
 
• 你需要确定哪些功能用得多。首先将频频使用的服务或应用程序功能转换为微服务。请记住:微服务只执行一个有明确定义的服务。牢记这一原则并相应地对应用程序进行划分。
• 你很可能会碰到性能不佳的组件,但你还有其它的组件可选择。你也许有开源的插件可用,或者你可能想从头开始构建服务。请记住,微服务的边界是很关键的东西。只要你设计微服务的目的是让它单单把一件事做好,那就没问题。确定服务的边界往往很难,你会发现,只要多实践,边界就更容易确定了。考察微服务边界的另一种方法是,你必须在几周内(如果必须这么做的话)重写整个微服务,而不是花费几个月的时间来重写服务。
• 更好的技术替代方案或多语言编程。领域特定语言(Domain-specific language)可用于解决问题域(problem domain)方面的问题。这尤其适用于各种组件,即你过去收到大量增强请求的组件,而你希望这些能够继续收到这样的请求。使用市面上的新语言或功能不仅可以将此类组件的实施工作简化,而且还可以使未来的维护和更新变得更加容易,如果你是这么认为的,那么现在正是解决此类更改的正确时机。在其他情况下,你可能会发现,另一种语言提供的并发抽象比当前使用的抽象更容易。你可以将新语言用于已知的微服务,而应用程序的其余部分仍然可以使用不同的语言。同样,你可能希望某些微服务的速度变得非常快,你还有可能决定用C语言编写这些微服务,以获得最大的收益,而不是用另一种高级语言编写。利用这种灵活性才是最重要的。
• 存储方面的替代方案或多混合持久化(polyglot persistence)。随着大数据的兴起,应用程序的某些组件可能会通过NoSQL数据库而不是关系数据库来实现价值。如果应用程序中任何一个诸如此类的组件可能从此替代方案中受益,那么这可能是转向NoSQL的合适时机。
 
这就是你必须考虑的关键方面,即你必须考虑整体式应用程序中的每个服务或功能,你首先要优先处理这些项目的转化工作。一旦你从高优先级项目得出数值,你就可以应用其它规则。
 
• 修改方面的请求。在所有软件的生命周期中追踪新的改善请求或更改,这是一件很重要的事情。由于受到构建时间和部署时间的限制,需要频频修改功能很适合微服务。将这些服务分离就可以减少构建时间和部署时间,因为你不必构建整个应用程序,只需更改微服务,这也可能会增加应用程序其余部分的可用时间。
• 应用程序的某些部分总是会增加部署的复杂性。在整体式应用程序中,即使特定功能未受影响,你仍然必须完成整个构建和部署过程。如果存在这样的情况,去除应用程序的这些部分并用微服务取而代之,这大有裨益,这样你就可以减少整个应用程序其余部分的总体部署时间。在我们了解容器后,我们会详细讨论这种做法。
• 辅助服务(Helper service)。在大多数应用程序中,核心服务或主服务依赖于某些帮助程序服务。这些辅助功能的可用性可能会影响核心服务的可用性。例如,在服务台应用程序中,工单服务取决于产品目录服务。如果产品目录服务不可用,则用户无法提交要求解决问题的工单。如果存在这种情况,你必须将辅助服务转换为微服务并以合适的方式使其具有高度的可用性,以便辅助服务可以更好地为核心服务提供服务。(这些服务也称为断路服务(circuit-breaker service)。)
 
根据应用程序的不同,这些标准可能需要将大多数服务转换为微服务,不过这也没关系。这里的目的是简化转换过程,以便你可以确定路线图的优先事项并对其进行定义,即迁移到基于微服务的架构的路线图。
 
为服务重建架构
 
一旦你确定了要作为微服务迁移的功能,你就可以按照早期方案中的最佳实践开始重新架构所选的服务。以下是需要注意的方面:
 
• 微服务定义。为每个功能定义合适的微服务,这些微服务应包括通信机制(API)、技术定义等。试想一下你的现有功能所使用的数据,或相应地创建和规划微服务的数据策略。如果该函数在甲骨文这样体量较大的数据库上,那么移植到MySQL是否有意义?你要确定如何管理数据关系。最后,将每个微服务用作单独的应用程序。
• 重构代码。如果你不换用编程语言,你就可以重用某些代码。以存储/数据库层为例——共享与专用,在内存中与在外部。我们的目标不是添加新功能(除非真的有必要),而是重新打包现有代码并公开所需的API。
• 在开始编码之前,请确定源代码控制机制和版本控制机制,并确保这些标准得到了遵循。每个微服务都是一个单独的项目,并作为单独的应用程序部署。
• 数据迁移。如果你决定创建新的数据库,那么你还必须迁移旧数据。这通常是通过编写简单的SQL脚本来处理,具体取决于你的源和目标。
• 整体式代码。为了防止不得不回滚的问题,你一开始就得将现有代码留在整体式应用程序中。你要么更新其余的代码以使用新的微服务,要么分割应用程序流量(如果可能的话),从而使用整体式版本和微服务版本,第二种情况更好。这样你就有机会测试性能并关注性能。一旦有把握,你就可以将所有流量移动到微服务并禁用旧代码或将其删除。
• 独立的构建、部署和管理。独立地构建和部署每个微服务。在推出新版本的微服务时,你可以在一段时间内划分旧版本和新版本之间的流量。这意味着你可能在生产环境中运行同一个微服务的两个版本或更多版本。某些用户流量可以被转至新的微服务版本,以确保服务正常运行。如果新版本没有以最佳方式工作,或没有按预期执行,那么将所有的流量回滚到先前的版本并继续对新版本进行开发则变得很容易。这里的关键是,建立可重复的自动部署流程并转向持续交付。
•旧代码删除。如果你还没有确认一切都得到了妥善的迁移并按预期运作,那你就不能删除临时代码并从旧存储位置删除数据。请务必在此过程中进行备份。
 
微服务的混合方法
 
在编写全新的应用程序时,开发人员可以直接遵循微服务架构的原则和蓝图来构建软件应用程序。
 
开发人员有时会遵循一种将微服务和整体性应用程序混合起来的方法。在这种情况下,他们可以将部分应用程序开发为微服务,其余部分则遵循基于特定标准的标准SOA/MVC实践(译注:SOA即面向服务的架构,MVC即模型-视图-控制器模式)。这个想法就是,并非应用所有的应用程序组件都可以用作微服务。
 
微服务提供了很大的灵活性,但这种灵活性部署是没有代价的。混合方法就是在灵活性和成本之间取得平衡,条件是,组件最终可以从整体性部件中提取出来并根据需要转换为微服务。关键是在此过渡期间牢记这两种方法和微服务标准。

关键字:

原创文章 企业网D1Net

电子周刊
回到顶部

关于我们联系我们版权声明隐私条款广告服务友情链接投稿中心招贤纳士

企业网版权所有 ©2010-2024 京ICP备09108050号-6 京公网安备 11010502049343号

^