本文翻译:吴嘉俊
1. 介绍
微服务,当今业界最热门的话题之一,bulingbuling的,每个人,每个公司都想做,但有多少是真正从公司的人和组织结构角度去思考微服务会带来的变革。
这篇文章中,我们会从核心的原理,到准备实际操作的这个流程来讨论微服务架构。但是,这是一个每天都发生着大量创新的领域,所以,在这篇文章中将要讨论的所有内容,都是现在发生的实践,这些实践,是否在未来还有用,我们需要谨慎的去看待。无论好坏,业界仍在围绕开发和操作微服务不断的在实践中前进。
虽然对于如何正确的实施微服务有非常多的方法方式,但是真相却是:没有一条真正统一,有效的路让你万无一失。微服务化是持续学习和改进的过程,同时又需要尽可能控制住系统复杂度。不要把本文中所讨论的问题和答案看做理所当然,请保持开放的心态,并对新的挑战做好应对即可。
2. 我们身边的单块应用(monolith)
曾几何时,传统的单层架构和C/S架构(薄客户端/富服务端)是搭建所有应用和平台的首选方案。公平的说,对于大部分的应用,他们确实工作的很好(并且现在仍然工作的很好),但是突然有一天,微服务架构出现了,瞬间给所有的这些架构贴上了可怕的标签,许多人将他们视为老古董。
围绕技术的过度宣传会扰乱基本的常识,微服务就是一个典型的例子。单块应用并没有什么问题,并且目前仍然有不少成功的单块应用在正常的运行着。然后,确实单块应用会有一些限制需要我们去改进,我们就从单块应用的几个核心问题作为入手点,来看看为什么会选择采用微服务架构。
不管你是否认可,在很多公司里面,单块应用就是一个庞然大物。维护费用非常高,大量的bug增加了回归测试次数,降低产品质量,同时,新需求又需要耗费时间开发,导致整体项目难以按时交付。这就是一个很好的时机,回过头分析到底什么地方出了问题,应该怎么改进。在大多数情况下,把独立的代码库,直接分解成一组相对独立的模块或者组件,通过建立适当的API(不必改变模型打包方式),可能是最简单和最便宜的解决方案。
但是,你经常会遇到可伸缩性问题,包括软件平台的伸缩和工程组织的伸缩性,在面对单块应用架构的时候,非常难以解决。对于这点,经典的康威法则(Conway’s law)总结的非常到位。
“设计系统的组织,其产生的设计等同于组织之内、组织之间的沟通结构” –http://www.melconway.com/Home/Committees_Paper.html
是否微服务就是隧道尽头的明灯么?这完全是可能的,但是,你必须做好改变你以前遵循的工程组织和开发实践。当然,这将是一次颠簸的旅程,但是应该在早期强调,在本文中,我们不会质疑微服务架构(并将您推向微服务),而是假设您已经做了研究,并且强烈相信微服务就是寻找的答案。
3. 拥抱微服务架构
那么,“微服务”和“微服务架构”到底是什么意思?您可能会发现有很多不同的存在细微差别的定义,但是最完整、最容易理解的定义还是由Martin Fowlerin在他的关于微服务体系结构的文章中给出的:
简而言之,微服务架构风格,就像是把一个单独的应用程序开发为一套小服务,每个小服务运行在自己的进程中,并使用轻量级机制通信,通常是 HTTP API。这些服务围绕业务能力来构建,并通过完全自动化部署机制来独立部署。这些服务使用不同的编程语言书写,以及不同数据存储技术,并保持最低限度的集中式管理。– https://www.martinfowler.com/articles/microservices.html
微服务的前缀”微“常常会让人产生迷惑,到底这个”微“应该是多大才合适?当然,这个很难有一个确切的度量。一个比较靠谱的度量方式就是,每一个服务都应该针对一个明确可行的目标。另一种比较有争议的对”微”的范围定义是:一个微服务必须足够的小,让一个程序员(更正式的表述:服务的维护者)能完整的理解。
有两条基本的路线让你能够更快速的拥抱微服务:要么直接按照微服务架构开始一个新的项目,要么着手修改一个单块应用的架构。为了更好的实施微服务,有一些基本的先决条件和原则需要遵守。
首先,微服务必须基于正确的领域模型设计。有两本这方面的书值得大家阅读:[The Domain-Driven Design: Tackling Complexity in the Heart of Software]和 [Implementing Domain-Driven Design],这两本书是关于DDD的最靠谱的两本书。如果你对你的领域模型了解的还不够深刻,我建议你先不要着急打开微服务的大门。
良好的领域模型设计,这一点的重要性很快就会变得清晰起来,但是当您从头开始开发应用程序时,由于未知因素较多,所以在具体实施过程中,还是会遇到很多困难。
3.1 细化架构
总体来看,微服务架构定义了如何将你的应用以一组服务的形式组织管理,但是并没有具体规定服务怎么实现,以及服务之间应该怎么通信等更细节的结构。从某种意义上来说,微服务架构应该被看做一种超级(高层次)架构。
因此,至于单个微服务内部的架构选择,可以是多种多样的,比如ports and adapters(https://staging.cockburn.us/hexagonal-architecture/),clean%EF%BC%8Cclean)architecture(https://8thlight.com/blog/uncle-bob/2012/08/13/the-clean-architecture.html),onion%EF%BC%8Conion)architecture(https://jeffreypalermo.com/2008/07/the-onion-architecture-part-1/),或者老式的分层架构,都是可以使用的。%EF%BC%8C%E6%88%96%E8%80%85%E8%80%81%E5%BC%8F%E7%9A%84%E5%88%86%E5%B1%82%E6%9E%B6%E6%9E%84%EF%BC%8C%E9%83%BD%E6%98%AF%E5%8F%AF%E4%BB%A5%E4%BD%BF%E7%94%A8%E7%9A%84%E3%80%82)
3.2 有界上下文(Bounded Context)
有界上下文的概念来自于领域模型驱动的概念。当应用到微服务架构时,它概述了每个微服务负责的业务子域的边界。有界上下文成为微服务的基础契约,也是微服务对外部系统的边界。
整个应用的业务领域模型由该系统中所有微服务的领域模型组成,这些领域模型之间由有界的上下文将它们粘在一起。显然,如果业务领域没有很好地定义和分解,那么它们前面的领域模型、有界上下文和微服务也是如此。
3.3 所有权(Ownership)
每一个微服务必须作为它管理的领域模型的唯一来源,包括该领域的数据。特别重要的,在微服务架构中,每个服务必须切断和其他数据共享的诱惑,比如直接从数据存储源中读取其他服务的数据,等绕过微服务契约建立的额外联系。
但是,在真实系统中,没有绝对的独立应用,所以必须要找到一个处理方法。实际上,数据共享并不是唯一的选择,你可能立刻会遇到将部分数据冗余化的需求,接下来,还要找到一个方案提供数据的同步。
你将要做的每个实现都应该被分解为多个部分,并明确地放在正确的微服务(或一组微服务)中。
从组织的角度来看,所有权转化为为每个微服务(或者一些微服务)提供一个独立的跨职能团队。跨职能是实现成熟和最终责任的重要一步:你创建它,你部署它,你运行它,你支持它(或者简单说:你构建,你运维)。
3.4 独立部署
每一个微服务必须和其他服务保持独立:不仅仅是在开发阶段,也包括部署阶段。部署的分离,并且更重要的,独立扩展的能力,是微服务架构最重要的力量。将微服务视为自治单元,基本上与平台和基础设施无关,随时随地都可以部署。
3.5 版本控制
独立的另一方面,意味着每一个微服务应该有自己的生命周期和版本控制。这次,在讨论控制权的同时,我们还要考虑合作。在任何一个松耦合的分布式系统中,契约是非常容易被打破。契约的修改,必须及时有效的在相关的团队中进行沟通,以便让所有人都知道即将到来的改变是什么,应该怎么应对。
保持向前和向后兼容的能力,是微服务架构中必须处理的事情。这是另一种责任:不仅仅要保证新版本能够顺利的升级和运行,还要保证目前现有的微服务客户端能完美的继续运行。
3.6 正确的工具
微服务架构真正的拥抱“选择正确的工具来工作”的哲学,在选择开发语言,框架,库的时候,不再统一固定。不同的微服务面对不同的需求,应该选择更合适的工具来完成,而不同实现技术栈之间,也能通过微服务间有效的沟通,轻松的集成到一起。
4. 单块应用分布式化的危险
公平的讲,微服务架构在提供了很多优秀特性的同时,也引入了很多复杂的问题。毫无疑问,选择的开发语言或者框架,会更加放大这些复杂性。
当选择采用微服务之后,很多团队陷入了仍然采用过去一样的组织结构和开发过程;到最后,更可能得到的不是一个微服务架构应用,而是一个分布式的单块应用,这对于开发者和组织者都是一个噩梦。下面我们就这个问题再多谈一些。
4.1 每个方法都是远程调用
由于每个微服务都位于一个单独的进程中,所以每个函数调用都可能导致上游微服务间的网络请求风暴。这个问题通过代码去检查比较困难,要处理这个问题,需要从架构的第一天就做好准备。网络调用的消耗成本很高,而且所有的网络调用都可能出现意想不到的错误,让应用有一万种失败的方式。
4.2 通信量
大多数情况下,一个微服务往往需要和上游的几个微服务进行沟通,这非常正常,也符合预期。但是,当一个微服务需要调用大量的其他微服务,或者一个微服务会发出大量的调用请求以完成任务,这就是一个显然的服务划分错误的标志。服务间高频的通信不仅会受到网络延迟和故障的影响,还会让出现无效的中介器和代理;
4.3 循环依赖
服务间通信的极端版本,就是两个微服务间的循环通信,不管是直接的还是间接的。循环依赖常常不那么明显,但是确实是洪水猛兽。即使您找到了神奇的顺序,将这些相互依赖的微服务部署到生产环境中,迟早它们也会使应用程序屈服。
4.4 共享
有太多开发者总结的最佳实践和模式,又要遵守DRY原则和代码重用原则,导致如何抽取和管理微服务之间的共同基础代码是特别困难的事情。
实际上,我们知道的代码重复(特别是广为人知的Ctrl+C/Ctrl+V编程大法)必须在开发中尽量避免。然而,在微服务架构的上下文中,不同微服务之间的共享代码反而会引入最高级别的代码耦合。
但是,在实际开发中,要做到不在微服务间共享代码或者库,特别是当各个微服务使用相同的代码或平台开发的时候,其实是很难的。在这种情况下,如果将共享的代码/库减少到最小甚至是没有,绝对是一门值得追求的艺术。否则,这种共享将会拖累应用,最后变成分布式的单块应用。
5. 小结
在这篇文章中,我们非常概要的介绍了微服务架构,它带来的优势,它引入的复杂度和对工程组织结构的显著改变。这种架构带来了大量的机会,但是另一方面,可能产生错误的概率也非常高。
原文:https://www.javacodegeeks.com/2018/07/microservices-for-java-developers-introduction.html
想获取更多技术视频,请前往叩丁狼官网:http://www.wolfcode.cn/openClassWeb_listDetail.html
网友评论