The microservice architecture is poisonous, when not to use microservices?

In the past four years, the use of microservices to build applications seems to have become a standard. Most of the teams I have worked with have also shown varying degrees of interest.


image.png

The elasticity, high availability, low coupling, agility promised by microservices, and the ability to solve the problems caused by the monolithic architecture are the main reasons for its popularity.


But in recent times, some reservations and precautions for microservices seem to have attracted people's attention.


In this article, I want to focus on the application of microservices, what are its shortcomings, and under what circumstances should be carefully considered using microservice architecture.


What is a microservice


At the industrial level, the definition of the basic characteristics of microservices is relatively consistent.


These characteristics can be summarized as follows:

  • Microservices are a pattern applied to component design (how services are grouped) and deployment architecture (how services are deployed and communicated).

  • Microservices are suitable for creating distributed applications with "a certain functional complexity".

  • Each service must be small.

  • Each service is divided by function to achieve separation of concerns.

  • Each service remains autonomous and decoupled from each other, and can be deployed, version controlled, and scaled independently.

  • The various services communicate through a combination of lightweight APIs and asynchronous channels.

  • Each service has an independent state and can only be accessed through the service itself.


A typical microservice implementation mode is as follows:

image.png

Figure 1: Typical microservice implementation pattern


From the above picture we can see:

  • Each group of services in microservices has its own front end (composed of an API and an optional UI component), a domain layer that implements its own service domain logic, and independent data storage.

  • Front-end composite. Combine all front-end components (UI components or API) into a consistent front-end (composite UI or API gateway).

  • An event bus serves as the backbone of asynchronous communication.


The main problem is that for those use cases that use microservice architecture, people's views on microservices tend to be consistent.


This is why I want to take the opposite approach and try to illustrate the situations in which microservices may not be the best choice.


The challenges of microservices


The programmer knows the advantages, but knows nothing about the cost.


—— Rich Hickey (Clojure designer)


Implementing microservices requires weighing the pros and cons. Since the focus of this article is not to criticize the flaws of microservices, it is as concise as possible.


Microservices are difficult to design correctly


There is a special book "Microservices AntiPatterns and Pitfalls " to record its defects. It requires very, very many iterations to complete a satisfactory domain design.


At the same time, there are no direct answers to several basic and structured questions, and adjustments and iterations are often required, such as: how to divide concerns horizontally, how to share data and how to replicate data, how to manage reports, and whether it should be included in the service UI components, etc.


Microservices introduce complexity


Microservices introduce a certain degree of complexity, which has been recorded in detail, the most famous of which is "microservices-not free lunch".

image.png

Figure 2: The number of APIs has doubled


The challenges brought by microservices include:

  • The number of APIs has been doubled. This makes it difficult to change the code, introduces the complexity of version control, and increases the difficulty of service functional decomposition.

  • Introduced network delay. There is a trade-off between scalability and increased response time when composing services.

  • Given the CAP theory, it is very complicated to handle transactions that span multiple services. Unlike a monolithic architecture with a single database, these transactions are usually not handled by the infrastructure.

  • Debugging distributed systems is complicated (see "Microservices—not a free lunch"). Errors in asynchronous systems, inter-service locks, and race conditions are difficult to locate and eliminate.


Although these complexities can be overcome by technical means, it requires technical personnel to pay extra energy and cannot allow them to focus on achieving more valuable business functions.


Microservices require organizational changes


Microservices require organizations to shift to autonomous, cross-functional teams. According to Conway's law, this is a crucial step.


This means that front-end and back-end developers, data platform engineers, QA, product managers, and operations personnel must work together in a team.

image.png

Figure 3: Microservices require organizational changes


This organization works very smoothly. This is because most dependencies exist within the team, and because the priorities are the same, they can all be resolved quickly.


Microservices require process and practice changes


微服务需要过程和实践的改变。从偶尔发布几个大版本,到经常发布许多小版本。


从手动的资源供给,到基础设施即代码等自动化形式的资源供给。微服务架构的成功依赖于组织和流程改变的能力,而这往往是最难的。

image.png

图 4:微服务需要过程和实践的改变


微服务需要深入的技术栈


上面讨论的这些技术挑战意味着团队的技术集需要更加全面的拓展。


团队成员需要理解分布式系统、DevOps、基础架构即代码(IaC)、不同类型的数据库、前端组件化和复合化、单元测试、全自动发布、迭代、小版本发布计划、测试工具、多版本管理等等。


什么时候不应该使用微服务


应用程序规模太小


应用程序规模太小不足以证明微服务的合理性。当然,这个应用在未来可能会出现增长,直到整个领域添加到其中。


在这种情况下,当接近 RoI 阈值时,使用微服务。同样的道理也适用于那些小型团队。

image.png

图 5:代码行数与维护成本


领域不明确


领域不明确或不确定,使得领域模型不确定。比如,当产品被描述为“门户”时、当你开始创业准备做一个应用时、当一个 CRM 系统要管理订单甚至是有邮递外送时,这种问题就会凸显。


在这种情况下,单体结构要灵活得多。在晚上,当你独自将 CRM 领域转换成逻辑解决方案的时候,你可能会惊讶于利用 IDE 来进行重构所带来的便利性以及单元测试套件带来的安全感。


组织不能做出改变


组织不能改变以适应微服务。它仍然包含一个数据组、一个前端组、一个后端组等等。


康韦定律有利于将服务组成一个分层的微服务体系结构。你可以将图 1 与图 6 进行比较。

image.png

图 6:传统的组织形式来做微服务


由于不同的团队有不同的优先级,导致跨团队的依赖关系环环相扣,造成延迟和冲突。


缺乏理解


团队缺乏对微服务概念、DDD 或概念设计的经验和理解。虽然这可能算不上关键,但你应该仔细阅读相关文档并向有经验的人寻求建议。


一个体系结构设计不良的的产物往往是一个高耦合的分布式“单体架构”系统,以及随之而来的一切问题:网络的通信性和延迟、复杂性、隐藏的依赖、部署时产生耦合等等。


我们大多数人都喜欢学习新事物,但并非所有人都喜欢,况且学习需要时间和精力。


有时候甚至要不断地犯错误,包括大错误,然后才可能学到一些东西。甚至在某些情况下需要废弃初始的版本,然后从头开始。这些都是潜在的成本,必须要在做出决定之前考虑清楚。


管理层也需要尽早适应重构,在某些极端情况下甚至要接受从头开始一个项目。

经常失败。早点失败。快速失败。拥抱失败是走向成功的一种方式。不要害怕失败,要学会接受失败。


——Gary Burnison, CEO of Korn Ferry


接受失败不是一件容易的事情,因为沉没成本往往会错误指导你的下一步决策。


其他


团队不成熟,技术栈不适应微服务或者人员流动率高。因为系统的无序性(熵)会随着时间的推移而不断增大,代码的维护性也会随着时间的推移而下降。


而且由于一个更复杂的系统更难维护,这可能会加剧第 3.4 带来的问题。


困惑和压力往往会让人们退回到他们所熟悉的圈子。他们会“抄近路”把东西弄出来,或者走捷径来规避复杂性。


很快,这样产生的软件架构可能会被污染到技术组件、“核心”库、服务与服务之间的引用、编排器甚至“CSV 导入服务”,然后这些服务开始进入彼此的数据库。


接下来,有人会问“我们应该如何编排部署以管理服务之间的依赖关系?”这无异于是软件版本的地狱,这种系统也被称为分布式“单体架构”。

image.png

图 7:组件依赖


运行和调试的复杂性可能会降低开发的整体效率。跨服务的 Bug 调查和日志分析是非常复杂的。


这会带来一个问题,那就是这些工作只能交给那些团队中技术经验更加丰富的成员。


但是这些成员的关注点应该是如何保持系统长期稳定运行,而不是救火。简而言之,在这种情况下,微服务不但没有带来优势,反而会让整个团队为消极结果买单。


应该如何抉择?


所有软件系统都可以分解为两个主要元素:策略和细节。策略元素包含所有业务规则和过程。策略是系统的真正价值所在。


而细节是使人类、其他系统和程序员能够与策略进行通信的必备基础,但是这些细节都不会影响策略的行为。细节包括 IO 设备、数据库、Web 系统、服务器、框架、通信协议等等。


架构师的目标是为系统创建一个外形。这个外形将策略看做是系统中最重要的元素,同时做到细节与策略无关。这使得有关细节的决策可以延迟和推后。


—— Robert C. Martin, Clean Architecture


如果您正在构建的应用程序有一个相当清晰的领域,未来会演进到一个相当的规模,在项目开始就会配置大型的团队,并且你对团队的技术有信心,你在分布式设计方面有一些经验或者至少有一些素养,同时又能获得管理层方面对于失败和学习的支持和容忍,那么微服务会是一个很好的选择。


但是要注意有时布局候微服务可能会适得其反。如果你所处的场景与前面的描述相类似,那么使用一些更简单的架构作为开始可能更加明智。


比如一个单体架构或者一个分层架构(本身可能包含一些专门的服务)。大部分微服务架构能够解决的问题,其他方案也能解决。


低耦合、可伸缩性和前瞻性的系统来自于精心设计的应用程序架构。这种架构往往具有明确定义的边界和专门的数据存储。


微服务只能通过提供物理限制来满足这种场景。另一种创建物理限制的方法是通过组件(DLL、JAR)。组件架构和部署架构的选择应该尽可能的慎重。


容器和基础结构即代码(IaS)可以与微服务架构一起配合使用。事实上,它们往往更容易实现,因为网络是直接的,配置的数量不那么重要。同时容器也能让搭建和销毁环境变得更加容易,并可以加速开发环境的部署。


构建自动化和频繁发布可以通过增加关注点和减少在制品(Reduced WIP)、小批量(Small Batches)、原子化更改流(Atomic Change Flow)和减少协作来实现。


对于复杂的分布式系统,微服务无疑是一个很好的选择。但微服务并不是唯一的选择,对于微服务的诉求往往会促使人们做出采用它们的决定,而忽略了它带来的种种问题。


A person should consider various choices, and then make a conscious, literate, and rational choice.



Guess you like

Origin blog.51cto.com/14410880/2551528