![cfd94c1cbcfdf7766e834dbeeb60ba06.png](https://i-blog.csdnimg.cn/blog_migrate/636ed8f066f2d79d0f8de847d484cb69.jpeg)
关注「前端向后」微信公众号,你将收获一系列「用心原创」的高质量技术文章,主题包括但不限于前端、Node.js以及服务端技术
本文首发于 ayqy.net ,原文链接:http://www.ayqy.net/blog/微服务架构(microservices)/
零.从 Monolithic application 说起
Monolith means composed all in one piece. The Monolithic application describes a single-tiered software application in which different components combined into a single program from a single platform.
(摘自Introduction to Monolithic Architecture and MicroServices Architecture)
把软件应用的不同组件都放到一个程序中,就叫 Monolithic application。例如,通过编程语言的基本特性将应用划分成类、函数和命名空间,用部署流水线来保证变更都经过测试后才部署到生产环境,并通过负载均衡机制运行多个实例,将其进行横向扩展:
All your logic for handling a request runs in a single process, allowing you to use the basic features of your language to divide up the application into classes, functions, and namespaces. With some care, you can run and test the application on a developer's laptop, and use a deployment pipeline to ensure that changes are properly tested and deployed into production. You can horizontally scale the monolith by running many instances behind a load-balancer.
在这种架构模式下,应用程序也能很好地工作,但存在 2 个问题:
- 变更受限制:很小的一处变更也需要对整个应用进行重新构建和部署,而且难以控制变更的影响范围
- 不利于扩展:无法仅扩展应用中需要更多资源的那些部分,只能扩展整个应用
这些限制在云环境下尤其突出。于是,微服务架构登上了舞台
一.微服务架构是什么?
Microservices are a software development technique—a variant of the service-oriented architecture (SOA) architectural style that structures an application as a collection of loosely coupled services. In a microservices architecture, services are fine-grained and the protocols are lightweight.
(摘自Microservices)
面向服务架构(SOA)的一种变体,把应用程序设计成一系列松耦合的细粒度服务,并通过轻量级的通信协议组织起来
Building applications as suites of services. As well as the fact that services are independently deployable and scalable, each service also provides a firm module boundary, even allowing for different services to be written in different programming languages. They can also be managed by different teams.
具体地,将应用构建成一组小型服务。这些服务都能够独立部署、独立扩展,每个服务都具有稳固的模块边界,甚至允许使用不同的编程语言来编写不同服务,也可以由不同的团队来管理
![b46b1c13d5860662e92fe798f2f87fea.png](https://i-blog.csdnimg.cn/blog_migrate/59a6bf048af381aeb22d1c37feb432ed.jpeg)
微服务与 SOA
Service-oriented architecture (SOA) is a style of software design where services are provided to the other components by application components, through a communication protocol over a network.
(摘自Service-oriented architecture)
SOA 中,服务由应用程序组件通过网络通信协议提供给其它组件。因此,微服务架构算是 SOA 的一种变体,或者说是特例,特指满足某些特征的 SOA 设计
二.微服务架构的 9 大特征
通过服务进行组件化(Componentization via Services)
组件可以理解为能够独立更换升级的软件单元,一系列组件插在一起构成软件系统,就像物理世界中我们所见到的那样:
Our definition is that a component is a unit of software that is independently replaceable and upgradeable. There's been a desire to build systems by plugging together components, much in the way we see things are made in the physical world.
在微服务架构中,组件就是服务,通过 Web 服务请求或 RPC 之类的机制通信。这种服务粒度的组件化方式有 2 点优势:
- 服务能够独立部署
- 服务具有显式的对外接口(PublishedInterface)
独立部署,意味着对一个服务的内部改动只需要重新部署该服务,涉及服务接口改动时才需要协同修改多个服务。另一方面,还可以通过服务边界和服务协议方面的演进来尽可能减少这样的关联
显式的对外接口则是一种强约束,能够保证组件的封装性,避免组件间出现过度的紧耦合
但比起进程内调用,RPC 的性能成本更高,因此 RPC 接口大多是粗粒度的,也往往更难使用。另一方面,如果想要调整组件职责的话,重构成本也更高
围绕业务功能来组织团队(Organized around Business Capabilities)
微服务允许将系统根据业务功能分解成一系列服务,因此可以围绕业务功能来组织跨职能的团队。并且,这种组织结构还有利于强化服务边界:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8rxLM9xU-1577238129023)(https://martinfowler.com/articles/microservices/images/PreferFunctionalStaffOrganization.png)]
P.S.康威定律,设计结构最终都会与该组织的沟通结构相一致:
Any organization that designs a system (defined broadly) will produce a design whose structure is a copy of the organization's communication structure. -- Melvyn Conway, 1967
沟通结构改变设计结构的一个很有意思的例子是,一些团队会把逻辑塞到自己能够掌控的应用中,以避免跨团队协作的沟通成本:
A smart team will optimise around this and plump for the lesser of two evils - just force the logic into whichever application they have access to.
比起在 Monolithic application 中按业务线划分团队,以服务为边界更清晰、约束力也更强。因为很容易出现跨越模块边界的业务功能,而服务边界相对稳固一些
做产品而不是做项目(Products not Projects)
微服务架构倾向于一个产品由所属开发团队长期维护/演进,而不是项目交付后转由另一个维护团队负责:
Microservice proponents tend to avoid this model, preferring instead the notion that a team should own a product over its full lifetime.
这种产品理念能够在开发团队与用户之间建立持续的关联,让开发团队关注到软件如何帮助用户增进业务功能:
There is an on-going relationship where the question is how can software assist its users to enhance the business capability.
智能端点和傻瓜式管道(Smart endpoints and dumb pipes)
通信机制上,一个典型的例子是企业服务总线(Enterprise Service Bus),消息都流经 ESB,由 ESB 负责消息路由、编排、转换以及业务规则的应用,随后到达端点(endpoints)进行处理。这种模式下,端点可以保持傻瓜式,因为很多逻辑都在 ESB 消息管道里处理了。因此,称之为智能管道和傻瓜式端点(smart pipes and dumb endpoints)
而微服务倾向于相反的做法,智能端点和傻瓜式管道(smart endpoints and dumb pipes):
That the lanes of communication should be stripped of business processing and logic and should literally only distribute messages between components. It's then the components themselves that do processing / logic / validation etc... on those messages.
即,管道只负责在组件之间分发消息,由服务本身针对消息做相应处理
去中心化技术治理(Decentralized Governance)
中心化技术治理最大的问题在于其局限性,统一的技术栈并不一定适用于所有场景:
Experience shows that this approach is constricting - not every problem is a nail and not every solution a hammer, we prefer using the right tool for the job.
而在微服务背景下,每个服务单独构建,就有了选择不同技术栈的机会,允许用更合适的工具去做不同的事情。这种技术栈上的自由有助于服务独立演进,自然选择出更好的模式
当然,“以前没得选,现在能选了”并不意味着百花齐放就是好的,因为维护不同技术生态的成本可能高过其收益:
We don’t end up with 20 different languages in the same system because each of them is opinionated and brings their own vision inside the system, maintaining different ecosystem is very expensive and potentially confusing without providing too many benefits.
权衡之下,我们可以将选择范围限制到某几种技术栈,而不再与一种技术栈强绑定:
But a trade-off could help out, having a limited list of languages or frameworks we can pick from can really help. Suddenly, we are not tightly coupled with one stack only.
去中心化数据管理(Decentralized Data Management)
从最抽象的层面看,去中心化地管理数据,意味着各个系统对客观世界所形成的概念模型各不相同。比如销售人员眼中的客户与开发人员所理解的不同,相同的概念在两个视角中可能也存在微妙的差异
应对这种情况的有效措施是领域驱动设计(Domain-Driven Design)中的界限上下文(Bounded Context):
应该显式地定义某个模型所应用的上下文。还应该在团队组织、应用中特定部分的使用以及像代码库和数据库模式等物理表现等方面显式地设定边界。要保持边界中模型的严格一致,而不要受外界问题的影响与干扰。
(摘自初窥 Bounded Context)
即,给模型概念限定一个上下文,在该上下文中保证概念严格一致。把一个复杂领域划分成多个界限上下文,再将其间关联勾画出来,就是概念模型层面的去中心化:
DDD divides a complex domain up into multiple bounded contexts and maps out the relationships between them.
具体到数据存储上,微服务也进行类似的去中心化策略,让每一个服务管理自己的数据库。这些数据库可以是相同数据库的不同实例,也可以是完全不同的数据库系统,称之为混合持久化:
Microservices prefer letting each service manage its own database, either different instances of the same database technology, or entirely different database systems - an approach called Polyglot Persistence.
P.S.对于去中心化数据存储带来的数据一致性问题,可以考虑通过一些补偿操作来让数据最终达到一致,具体见Starbucks Does Not Use Two-Phase Commit
基础设施自动化(Infrastructure Automation)
与 Monolithic application 相比,微服务的部署要更复杂一些。因为在复杂的网络环境中,部署多个服务比部署一个独立应用更困难:
![e16a061564a7804659c4c56aa0c94cbc.png](https://i-blog.csdnimg.cn/blog_migrate/0f077f4419361a1dc0b17e4d8f811f82.jpeg)
但云计算的发展让基础设施自动化成为可能,大大降低了服务构建、部署、运维的复杂性,让我们可以利用基础设施自动化实现生产环境中的微服务管理
容错设计(Design for failure)
在微服务背景下,客户端的容错设计更为重要:
A consequence of using services as components, is that applications need to be designed so that they can tolerate the failure of services. Any service call could fail due to unavailability of the supplier, the client has to respond to this as gracefully as possible.
比起 Monolithic application,这种容错设计带来的额外复杂性算是一种劣势
另一方面,为了快速检测到故障点,甚至尽可能自动恢复服务,实时监控在微服务架构中也格外重要
P.S.关于容错设计的更多信息,见Fault Tolerance in a High Volume, Distributed System
演进式设计(Evolutionary Design)
组件的划分在微服务架构中很关键,关系到能否减少变化。一般原则是该组件能否独立更换和升级:
The key property of a component is the notion of independent replacement and upgradeability.
然而,从另一个角度看,控制变化并不一定非要减少变化,如果确保这些变化能够如预期地快速进行,也是一种极好的控制
Change control doesn't necessarily mean change reduction - with the right attitudes and tools you can make frequent, fast, and well-controlled changes to software.
把微服务架构提供的服务分解能力当做一种工具来使用,以此实现服务粒度的变化控制:
- 预期一些服务将来会作废,不必长期演进
- 把那些会同时变化的东西放到同一个服务中,把很少发生变化的部分放到单独服务中,与经常发生变化的部分区分开
三.微服务架构的关键问题
首先,准确定义组件边界不是件容易的事情:
It's hard to figure out exactly where the component boundaries should lie.
因此,演进式设计退而求其次,让边界更容易重构(降低试错成本):
Evolutionary design recognizes the difficulties of getting boundaries right and thus the importance of it being easy to refactor them. But when your components are services with remote communications, then refactoring is much harder than with in-process libraries.
另一方面,如果设计不好的话,这样做只是把组件内的复杂度转移到了组件之间的连接上,变得更难控制:
Another issue is If the components do not compose cleanly, then all you are doing is shifting complexity from inside a component to the connections between components. Not just does this just move complexity around, it moves it to a place that's less explicit and harder to control.
很可能出现这样的局面,单个简单服务内部看起来变好了,服务之间杂乱的连接却被忽略了:
It's easy to think things are better when you are looking at the inside of a small, simple component, while missing messy connections between services.
参考资料
- Microservices
- “微服务”博客中译完整版:上文的中译版
- Microservices Resource Guide
- Microservices: What are smart endpoints and dumb pipes?
- I don’t understand micro-frontends.