微服务(microservices)微服务架构程序员

微服务的权衡[翻译]

2016-05-01  本文已影响154人  华子闲话

很多开发团队认为,对于整体架构来说,微服务架构风格是一种强有力的方式。但是其他团队认为微服务架构存在明显生产率的负担。和其它架构风格一样,微服务也有利弊。为了做出最好的选择,你必须理解这些并且使用到你特定的上下文。

微服务提供的好处:

1.强模块边界:微服务强化了模块结构,对于大型团队尤其重要。

2.独立部署:简单的服务更容易部署,并且因为它们是自治的,当它们出现问题时极少可能导致系统故障。

3.技术多样性:使用微服务你可以组合多种语言,开发框架和数据存储技术。

但是微服务也有代价:

1.分布:分布式系统更难组织,因为远程调用慢并且总是有失败风险。

2.最终一致性:对于分布式系统保持强一致性是极其困难的,这意味着每一个人必须管理最终一致性。

3.运维复杂:你需要一个成熟的运维团队来管理这么多经常要被重新部署的服务。

强模块边界

微服务第一个大的好处是强模块边界。这是一个重要还不可思议的好处,因为理论上没有原因说明为什么一个微服务本应该比一个整体有更强的模块边界。

那我说的强模块边界是什么呢?我想大多数人可能同意一个观点,把软件划分成多个模块是好的:软件的所有分块都是相互解耦的。你要让你的模块工作已至于如果我需要改变系统中某个部分,大部分时间我只需要理解系统中的一小部分就可以修改,并且我发现那一小部分非常简单。好的模块结构在任何组织都是有用的,但是随着软件大小的成长它的重要性会指数式增加。可能更重要的是,随着开发团队的壮大,模块结构变的更加重要。

微服务的拥护者很快提出Conways Law,它的概念是软件系统的结构反映了构建此软件的组织的沟通结构。对于更大的团队,尤其是如果这些团队在不同的地点,结构化软件并且认识到团队之间交流将会比在一个团队内的交流更少和更正式是非常重要的。在这种交流模式下微服务允许每个团队可以关心相对独立的单元。

正如我早前说的,没有原因说明为什么整体系统不应有好的模块结构。但是很多人注意到这种情况似乎很少,因此 Big Ball of Mud是最普遍的架构模式。事实上正是整体结构的挫败感驱使多个团队转向微服务。解耦的模块可以工作因为模块边界成为模块间引用的屏障。问题就是,在整体系统下很容易偷偷溜进边界周围。这样做可能是快速实现功能的一个有用的技术捷径,但是大范围地使用破坏模块结构,破坏团队的生产率。把模块放进独立的服务使边界更加坚固,使使用这些不好的解决方法更加困难。

耦合的一个重要的方面是持久化数据。微服务的主要特征之一是去中心化数据管理,它是说每一个服务管理自己的数据库,任何其它服务必须通过服务的API获取数据。这消除了集成数据库,在一个大系统中它是令人讨厌的耦合的一个主要地方。

郑重强调一下整体结构非常有可能强化模块边界,但是它需要纪律。相似地你可能进入一个微服务的大泥球,但是它需要很大精力做一些错事。以我看,使用微服务增加了你得到更好的模块的可能性。如果你对你的团队的纪律有信心,这可能消除了微服务的这个优势,但是随着团队的成长,保持纪律渐渐地变的更加困难,正如维护模块边界变的更加重要一样。

如果你得不到正确的边界,这个优势会变成一个障碍。对于Monolith First策略,这是两个主要原因之一,也是为什么那些早期倾向于运转微服务的人强调你只有在很好理解域的情况下使用微服务的两个主要原因之一

但是我仍然没有在这一点上按照警告做。你可以仅仅完全地说明在一段时候过后一个系统是如何维护模块的。所以当我们看到一个已经至少运行一些年的微服务系统,我们可以仅仅获取是否微服务带来了更好的模块。此外,早期使用者变的更加有才华,所以在我们获取一个由普通团队写的微服务系统的优势时会有一些延迟。即使这样,我们必须接受普通团队写的普通软件,而不是和顶级团队比较。我们必须与整体架构下的写的软件比较-这是一个巧妙的事实统计。

此时此刻,接下来是从我认识的使用这种风格的人那听到的早期证据。他们的意见是对于维护他们的模块,这种风格相当简单。

一个案例研究特别有意思。这个团队做了一个错误的决定,在一个不足够复杂到包含Microservice Premium的系统上使用微服务。项目遇到了麻烦需要营救,所以更多的人投入到这个项目。此刻微服务架构变的有帮助,因为系统能够承受开发人员的快速涌入,团队能够更容易的利用更多团队成员相对于团队在整块系统的情况下。结果项目加快了比在整块系统下期望的更多的生产率,使团队赶上。结果仍然有一些净负数的,软件花费的员工工时大于在整体架构下花费的时间,但是微服务架构支持极速增加。

分布

微服务使用分布式系统来提高模块化。但是分布式软件有一个主要的劣势,也正是它的分布式。一旦你要打分布式牌,你要遭受一大堆复杂性。我不认为微服务社区和分布式对象活动一样关于它们的开销是没有经验的,但是复杂性仍然存在。

这些复杂性中的一个是性能。很多天你必须在一个真正不寻常的点上观察进程内函数调用变成一个性能瓶颈,但是远程调用慢。如果你的服务调用了好几次远程服务,每一个远程服务又好几次调用其它远程服务,这些响应时间意味着一些糟糕的延迟特征。

当然你可以做一些事情减轻这种问题。首先你可以增加你的调用粒度,以至于你使用更少的调用。这使你的编码模型复杂化,现在你必须思考如何批处理你的内部服务间交互。它也只能带你到这,因为你将要不得不至少调用每一个合作服务一次。

第二种减轻方法是使用异步。如果并发的使用6个异步,你会和最慢的调用一样慢而不是它们延迟的和。这是一个大的性能优化,但是它带来另一个认知成本。异步编程是很难的:很难写对,同时更难调试。但是我听到的大多数微服务例子使用异步为了获得可接受的性能。

速度可靠之后,你期望进程内函数调用能够工作,但是一个远程调用可能在任何时候失败。随着更多微服务,会有更多潜在的失败点。聪明的开发人员知道这个并且为失败做设计。幸运地是为异步合作采取的各种措施也适用于处理失败的情况并且结果能够提高弹性。不是太多的补偿,但是,你仍然有为每一个远程调用执行失败结论的复杂性事情。

这仅仅是分布式计算的前两个谬论

对这个问题有一些警告。首先很多这些问题随着整体架构突然发生当它发展的时候。很少的整体架构是真正自包含的,常常有其它的系统,常常是遗留系统需要一同工作。与它们交互涉及到通过网路同时引用了这些相同的问题。这既是为什么很多人倾向于更快地转移到微服务来处理与远程系统同交互。这种问题也是一个经验能够帮忙的地方,一个更加熟练的团队将更好的处理这种分布式问题。

但是分布式一直是一个成本。我一直勉强使用分布式,并且认为很多人很快使用分布式是因为他们低估了它的问题。

最终一致性

我确信你知道网站需要一点耐心。你更新一些内容,你的屏幕被刷新同时更新的内容没有了。你等了一两分钟,点击刷新,它出现了。

这是一个非常令人不快的可用性问题,几乎确定是由于最终一致性危险造成的。你的更新被粉红色节点接收,但是你的获取请求被绿色节点处理。直到绿色节点从粉色节点得到它的更新,否则你是处在一个不一致的窗口。最终它将会一致,但是直到最终一致时,你一直疑惑是否那里出错了。

像这种不一致情况特别令人不快,但是它们可能是非常重要的。业务逻辑可能根据不一致信息作出决定而结束,当这种情况发生时,诊断是哪里出错将会极为困难,因为任何调查都是在一致窗口已经关闭很长时间之后发生。

微服务引入最终一致性内容由于它们值得赞赏的主张关于去中心化数据管理。使用整体架构,你可以在一个事务里更新一长串内容。微服务需要多个资源去更新,同时分布式事物很头疼。所以现在,开发人员需要注意一致性问题,并且搞清楚当数据不同步时在代码将要做任何回退之前如何检测。

整体架构的世界对于这些问题也不自由。随着系统的发展,有更多的需求需要使用缓存去提高性能,缓存失效是另一个问题。大部分应用使用离线锁来避免长链接的数据库事务。外部系统需要更新,这些更新不能与一个事务管理器协作。业务处理常常对不一致的容忍度比你认为的要强,因为业务常常更珍视使用性(业务过程有一种CAP定理的自然理解)。

和其它分布式问题一样,整体架构不能完全避免一致性问题,但是它们遭受这种问题更少,尤其是当它们很小的时候。

独立部署

对模块边界和分布式系统的复杂性的权衡充满了我在这个领域的整个职业生涯。但是在过去的10年有一件事情明显改变了,就是发布到产线的角色。在20世纪产品发布几乎是一个痛苦又极少的事情,在周末的白天或者晚上将软件有问题的部分切换到做有用事情的地方。但是现在,熟练的团队频繁的发布到产线,很多组织实践持续交付,运行他们一天内做多次发布。

这种转变已经对软件工业有了深远影响,它与微服务活动深深的缠绕在一起。多个微服务的成就都是被部署大的整块架构应用的难题触发的,在整体架构中一个小的改变都可能引起整个部署失败。微服务的一个主要原则是服务是组件,可以独立部署的。所以现在当你做了一个改变,你仅仅需要测试和部署一个小的服务。如果你把它弄乱了,你不用将整个系统停掉。毕竟,由于对失败设计的需要,即使你的组件完全失败也不应该阻止系统的其它部分工作,即使有一些优雅的降级处理。

这种关系是一种双向道。随着很多微服务需要频繁发布,你的部署要一起进行是基本要求。这就是为什么快速应用部署和基础的快速规定是微服务的前提条件。对于超出基本要求的任何事情,你需要进行持续交付。

持续交付的很大好处是从想法到可运行软件的周期减少了。这样做的阻止能够快速应对市场变化,比他们的竞争对手更快地引用新功能。

尽管很多人引用持续交付作为使用微服务的一个原因,但是本质上一个大型的整体系统也能做到持续交付。Facebook和Etsy就是两个最有名的例子。也有足够多的尝试微服务架构做独立部署失败的例子,多个服务需要小心合作发布。当我听到很多人争论使用微服务更容易进行持续交付,比起他们对于模块化的实践重要性,我更不坚信他们在微服务上的看法-尽管模块化天然地与交付速度有很强的关联。

运维复杂化

能够快速部署一个小的独立的单元对于部署来说是极好的,但是随着5,6个应用转成上百个小的微服务,它把额外的负担放到了运维上。很多组织发现处理如此多的快速改变的工具的困难代价很高。

这强化了持续交付的重要作用。虽然持续交付对整体架构是一个可用的技能,几乎一直要划分精力才能得到,对于一系列微服务设置它是一种基本要求。没有持续交付促进的自动化和合作,就没有办法处理10多个服务。由于对管理和监控这些服务的需求增加,运维复杂性也增加了。此外对于整体应用有用的成熟度级别,如果微服务在混合场景下,成熟度级别也是必须的。

处理这种运维复杂度需要一大堆新的技能和工具-特别强调在技能上。工具仍然不成熟,但是我的直觉告诉我即使使用更好的工具,在微服务环境下对技能的低障碍也是更高的。

到目前为止对于更好的技能和工具的需求不是处理这些运维复杂性的最难的部分。为了高效的做所有事情你也需要引入devops 文化:开发人员,运维和其它涉及到软件交付的人之间更好合作。文化的改变是困难的,尤其在更大,更久的组织。如果你不能弥补技能和文化的改变,你的整体应用将会被阻碍,但是你的微服务应用也会痛苦。

技术多样性

因为每一个微服务是独立的部署单元,在每个微服务下你可以自由考虑你的技术选择。微服务可以使用不同的语言,不能的库和不同的数据存储器。这允许团队对于任务选择合适的工具,某个语言和库对一个特定类型的问题更合适。

技术多样性的讨论常常集中在对工作最好的工具上,但是微服务最大的好处是更普通的版本问题。在整体架构下你可能仅仅使用一个库,一个地方的一个版本,这常常导致升级问题。系统的某个部分需要升级从而使用新功能但是不可以因为升级会打断系统的其它部分。处理版本问题是这些问题中的一个,随着代码变大,这些问题会以指数级变得更难。

使用多种技术有风险,开发组织将会不知所措。我知道的大多数组织鼓励有限的技术集合。这种鼓励通过为诸如监控等提供基本的工具来支持,这使服务附着于一个公共环境的小文件上更加简单。

不要低估支持实验的价值。对于一个整体架构系统,早期对语言和框架的决定是很难被颠覆的。10年后或许这个决定把团队锁定到一个不方便的技术上。微服务允许团队实践新工具,渐渐地迁移系统一次一个服务。一个更强的技术变得非常明确。

原文链接:Microservice Trade-Offs

上一篇下一篇

猜你喜欢

热点阅读