微服务架构设计模式——单体架构

首先,要明确单体架构的定义是什么,才好与其他架构作区别于讨论。以下是我觉得对单体架构总结的比较好的定义

Monolithic application has single code base with multiple modules. Modules are divided as either for business features or technical features. It has single build system which build entire application and/or dependency. It also has single executable or deployable binary.

Sometime it also called multi-tier architecture because monolithic applications are divided in three or more layers or tire i.e. presentation, business, database, application, etc.

单体架构通常是一个应用,单个Java War包或者Jar包,内部根据业务需求和技术需求分层,所以也可以称作多层架构,有展现层(负责处理HTTP请求并响应HTML或者JSON/XML)、业务层(应用的业务逻辑)、数据库层(用于访问数据库的数据访问对象)、应用层(消息层,比如实现AMQP协议的中间件ActiveMQ或者IBM MQ)等等。

一个架构之所以流行必然有其价值,最早之前,企业开发的方式为单体架构,由于早前的设备主要集中在笔记本、台式机,那个时期智能手机和平板电脑还未出现或者流行开来,所以前端主要还是浏览器,后端负责业务的逻辑实现,而且部署非常简单,只要将War包放到Web容器(如Tomcat, WebSphere)上运行即可,目前很多金融机构,如银行仍是采用这种架构模式开发应用,主要优点如下:

易于开发 — 当前开发工具与IDE的设计目标即在于支持单体应用的开发。
易于部署 — 你只需要将该WAR(或者目录层级)部署在合适的运行环境中即可。
易于扩展 — 你可以在负载均衡器后面运行多个应用副本实现扩展。
易于测试 - 只要运行应用就可以进行端到端的测试,前端测试也很简单。

但是缺点也很明显:

1. 随着业务的增长,单体应用巨大的代码库对那些团队新成员来说不好上手,应用难以被理解和进行修改(旧代码的改动可能影响应用的正常运行),进而导致开发速度减慢。由于没有清晰的模块边界,模块化会逐渐消失。另外,由于难以正确把握代码变化,导致代码质量逐步下滑,陷入恶性循环。
2. 代码库越大,IDE速度越慢,开发者的生产效率越低。
3. 过载的Web容器——应用越大,Web容器启动时间越长。容器启动耗费时间,极大影响到开发者的生产效率。对部署工作也有负面影响。
4. 持续部署困难——巨大的单体应用本身就是频繁部署的一大障碍。为了更新一个组件,你必须重新部署整个应用。这会中断那些可能与更改无关的后台任务(例如Java应用中的Quartz任务),同时可能引发问题。另外,未被更新的组件有可能无法正常启动。重新部署会增加风险,进而阻碍频繁更新。因为用户界面开发者经常需要进行快速迭代与频繁重新部署,所以这对用户界面开发者而言更加是个难题。举个例子,在汇丰,经常要关闭多个应用,才能部署新的应用,很有可能重新启动部署的新应用后其他应用不可用了,而问题是在用户上班的时候才发现,对业务造成非常严重的影响,甚至可能被监管机构罚款。
5. 应用扩展困难——单体架构只能进行一维伸缩。一方面,它可以通过运行多个应用副本来增加业务容量,实现扩展。一些云服务甚至可以根据负载量动态调整实例数量。但在另一方面,数据量增大会使得该架构无法伸缩。每个应用实例需要访问所有数据,导致缓存低效,加大内存占用和I/O流量。另外,不同的应用组件有不同的资源需求——有的是CPU密集型的,另外一些是内存密集型的。单体架构无法单独伸缩每个组件。
6. 难于进行规模化开发——单体应用是规模化开发的障碍。应用一旦达到特定规模,需要将现有组织拆分成多个团队,每个团队负责不同的功能模块。单体应用的问题在于它使团队无法独立展开工作。团队需要在工作进度和重新部署上进行协调。对于各团队而言,这使得变更和更新产品变得异常困难,沟通成本的大大增加使得项目进展缓慢,延期是非常正常且难以避免的现象。
7.需要长期关注同一套技术栈——单体架构迫使我们长期使用在开发初期选定的技术堆栈(在某些情况下,可能是某些技术的特定版本)。单体应用是渐进采用新技术的障碍。举例来说,如果我们选择了JVM,那么我们可以选择Java以外的一些语言,因为Groovy和Scala等基于JVM的语言也可以和Java进行良好的互操作。但此时以非JVM语言编写的组件就无法在该单体架构中使用。另外,如果大家所使用的应用平台框架已经过时,那么我们将很难将应用迁移到其它更新并且更完善的框架当中。有时候为了采用一套新型平台框架,我们甚至需要重写整个应用,这是风险很大的工作。所以在一些比较传统的软件行业,例如金融业,为了保持业务的稳定,几十年前写的代码仍在运行,但是招聘到能读懂和维护代码的工作人员很难,例如AS400,Mainframe,这些比较早的机器上还运行着COBOL代码等一些市面上罕见的程序语言。

Chris Richardson在他的书(Microservice Patterns)中举了个食品电商的例子,该食品电商采用典型单体架构,如下图所示,

食品电商单体架构图

当业务急剧增长后,可以看到业务团队分成了多个,代码Deploy到生产环境变得十分漫长,持续的集成化进行的不是很顺利,最后在生产环境,应用还容易出问题,非常难以维护。所以单体架构适用于早起小型团队快速开发,到了业务量非常庞大的场景,以互联网尤为明显,变得难以适应,原来的优点变得微乎其微,所造成的问题倒是对业务有严重的影响。书中也提到,该电商公司曾尝试使用新的技术栈如spring framework或者新的语言来扩展和提升应用的性能,由于兼容性的不足,不得不重构整个应用,费时费力,无法做到平缓顺滑升级。

业务扩大后开发流程

至于对单体架构的种种缺点,Richardson提出微服务的架构设计模式来解决,详细的关于微服务架构设计模式会在下一篇文章中展开。

参考资料:

Chris Richardson  —— Microservice Patterns

Monolithic vs Microservice Architecture

猜你喜欢

转载自blog.csdn.net/u010145219/article/details/92014844