1 单体应用架构
一个归档包(例如war包格式)包含所有功能的应用程序,通常称为单体应用,而架构单体应用的方法,就是单体应用架构。以下为电影售票系统单体架构示意图。
![](https://img.haomeiwen.com/i13026144/5db797fa91c8deb7.png)
单体应用存在的一些问题:
-
复杂性高:项目中可能存在包含模块非常多,但是模块的边界模糊、依赖关系不清晰、代码质量参差不齐、混乱的堆砌在一起,修改起来很容易让人心惊胆战,甚至添加一个简单的功能,或者修改一个bug都会带来隐含的缺陷;
-
技术债务:随着时间的推移、需求变更和人员更迭,会逐渐形成应用程序的技术债务,并且越积越多。"不坏不修(Not broken,don't fix)",这在软件开发中非常的常见,在单体应用中这种思想更甚。已使用的系统设计或代码难以被修改,因为应用程序中的其他模块可能会以意料之外的方式使用它;
-
部署频率低:随着代码的增多,构建和部署的时间也会增加。而在单体应用中,每次的功能的变更或缺陷的修复都会导致需要重新部署整个应用。全量部署的方式耗时长、影响范围大、风险高,这使得单体应用项目上线部署的频率较低。而部署频率低又导致两次发布之间会有大量的功能变更和缺陷修复,出错概率比较高。
-
可靠性差:某个应用Bug,可能会导致整个应用的崩溃
-
扩展能力受限: 单体应用作为一个整体进行扩展,无法根据业务模块的需要进行伸缩。例如,应用中有的模块是计算密集型的,它需要强劲的CPU;有的模块是IO密集型的,需要更大的内存。由于这些模块部署在一起,不得不在硬件的选择上做出妥协。
-
阻碍技术创新:单体应用往往使用统一的技术平台或方案解决所有的问题,团队中的每个成员都必须使用相同的开发语言和框架,要想引入新技术框架或新技术平台会非常困难。例如,一个使用Struts2构建的单体应用,如果想要换成Spring MVC,毫无疑问切换的成本是非常高的。
2 如何解决单体应用架构存在的问题
为了解决以上存在的问题,产生了微服务这种架构设计模式。
什么是微服务?
就目前来看,微服务本身并没有一个严格的定义,每个人对微服务的理解都不同。Martin Fowler在它的博客中是这样描述微服务的:
"微服务架构风格是一种将一个单一应用程序开发为一组小型服务的方法,每个服务运行在自己的进程中,服务间通信采用轻量级通信机制(通常用HTTP资源API)。这些服务围绕业务能力构建并且可通过全自动部署机制独立部署。这些服务公用一个最小型的集中式管理,服务可用不同的语言开发,使用不同的数据存储技术。"
可以从中看到,微服务架构应具备以下特性:
- 每个微服务可独立运行在自己的进程里;
- 一系列独立运行的微服务共同构建起整个系统;
- 每个服务为独立的业务开发,一个微服务只关注某个特定的功能,例如订单管理、用户管理等;
- 微服务之间通过一些轻量的通信机制进行通信,例如通过RESTful API进行调用;
- 可以使用不同的语言与数据储存技术;
- 全自动的部署机制。
以电影售票系统为例,使用微服务来架构该应用,架构图如下所示。将整个应用分解为多个微服务,各个微服务独立运行在自己的进程中,并分别有自己的数据库,微服务之间使用REST或者其他协议通信。
![](https://img.haomeiwen.com/i13026144/7df184d7f01d4f22.png)
微服务架构的优点与挑战
相对于单体应用架构来说,微服务架构有着显著的优点。但是,微服务并非是完美的,使用微服务也为我们的工作带来了一定的挑战。
微服务架构的优点
-
易于开发和维护:一个微服务只会关注一个特定的业务功能,所以它业务清晰、代码量较少。开发和维护单个微服务相对简单。而整个应用是由若干个微服务构建而成的,所以整个应用也会被维持一个可控状态;
-
单个微服务启动较快:单个微服务代码量较少,所以启动会比较快;
-
局部修改容易部署:单体应用只要有修改,就得重新部署这个服务即可;
-
技术栈不受限:在微服务架构中,可以结合项目业务以及团队的特点,合理的选择技术栈。例如某些服务可使用关系型数据库MySQL;某些服务有图形计算的需求,可使用Neo4j;甚至可根据需要,部分微服务使用Java开发,部分微服务使用Node.js开发;
-
按需伸缩:可根据需求,实现细粒度的扩展。例如,系统中的某个微服务遇到了瓶颈,可以结合这个微服务的业务特点,增加内存、升级CPU或者增加节点。
但是,完美的东西并不存在,以下是微服务架构面临的问题
微服务架构面临的问题
微服务虽然有很多吸引人的地方,但它并不是免费的午餐,使用它同样是有代价的。
-
运维要求较高:更多的服务意味着更多的运维投入。在单体架构中,只需要保证一个应用正常运行。而在微服务中,需要保证几十甚至几百个服务的正常运行与协作,这给运维带来了很大的挑战。
-
分布式固有的复杂性:使用微服务构建的是分布式系统。对于一个分布式系统,系统容错、网络延迟、分布式事务等都会带来巨大的挑战。
-
接口调用成本高:微服务之间通过接口进行通信。如果修改某一个微服务的API,可能所有使用了该接口的微服务都需要做调整。
-
重复劳动:很多服务可能都会使用到相同的功能,而这个功能并没有达到分解为一个微服务的程度,这个时候,可能各个服务都会开发这一个功能,从而导致代码重复。尽管可以使用共享库来解决这个问题(例如可以将这个功能封装成公共组件)
微服务设计原则
-
单一职责原则:单一职责原则指的是一个单元(类、方法或者服务等)只应关注整个系统功能中单独、有界限的一部分。单一职责原则可以帮助我们优雅的开发、更敏捷地交付。单一职责原则是SOLID原则之一。
-
服务自治原则:服务自治是指每个微服务应具备独立的业务能力、依赖于运行环境。在微服务架构中,服务是独立的业务单元,应该与其他服务高度解耦。每个微服务从开发、测试、构建、部署,都应当可以独立运行,而不依赖其他的服务。
-
轻量级通信机制:微服务之间应该通过轻量级的通信机制进行交互。轻量级的通信机制应该具备两点:首先是它的体量较轻;其次是它应该跨语言、跨平台的。例如我们所熟悉的REST协议,就是一个典型的"轻量级通信机制";而例如Java的RMI则协议就不符合轻量级通信机制的要求,因为它绑定了Java语言。而微服务架构中,常用的协议有REST、AMQP、STOMP、MQTT等。
-
微服务粒度:微服务的粒度是难点,也常常是争论的焦点。应当使用合理的粒度划分微服务,而不是一味地把服务做小。代码量的多少不能作为微服务划分的依据,因为不同的微服务本身的业务复杂性不同,代码量也不同。在微服务的设计阶段,就应确定其边界。微服务之间的相对独立并保持松耦合。其中,领域驱动设计(Domain Driven Design,简称DDD)中的"界限上下文"可作为划分微服务边界、确定微服务粒度的重要依据。
微服务架构的演进是一个循序渐进的过程。在演进过程中,常常会根据业务的变化,对微服务进行重构,甚至重新划分,从而让架构更加合理。最终,当微服务的开发、部署、测试以及运维的效率很高,并且成本很低时,一个好的微服务架构就形成了。
下一篇中,将介绍微服务实战。
网友评论