微服务架构的引入

      一直以来,系统的架构设计是IT领域经久不衰的话题之一,是每个系统构建过程中极其关键的一部分,它决定了系统是否能够被正确、有效地构建。那什么是系统架构设计?系统架构设计描述了在应用系统的内部,如何根据业务、技术、组织、灵活性、可扩展性以及可维护性等多种因素,将应用系统划分成不同的部分,并使这些部分彼此之间相互分工、相互协作,从而为用户提供某种特定价值的方式。

      随着面向对象分析、设计模式、企业架构模式等方法论的深入人心,从功能实现、代码组织的角度考虑,系统中不同职责的部分逐渐被划分到了如下三个层次:

    ●表示层,聚焦数据显示和用户交互。

    ●业务逻辑层,聚焦业务逻辑处理。

    ●数据访问层,聚焦数据的存储与访问。

      每一层负责的部分更趋向于具体化、细致化,这就是最初的软件三层架构。三层架构的出现,不仅解决了系统间调用复杂、职责不清的问题,更有效地降低了层与层之间的依赖关系,成为软件架构的经典模式之一。虽然三层架构将系统在逻辑上分成了三层,但它并不是物理上的分层。也就是说,对不同层的代码而言,经历编译、打包、部署后,所有的代码最终还是运行在同一个进程中。对于这种功能集中、代码中心化、一个发布包、部署后运行在同一进程的应用程序,我们通常称之为单块架构应用。典型的单块架构应用,莫过于传统的J2EE项目所构建的产品或者项目,它们存在的形态一般是WAR包或者EAR包。当部署这类应用时,通常是将整个包作为一个整体,部署在某个Web容器,如Tomcat或者Jetty中。当这类应用运行起来后,所有的功能也都运行在同一个进程中。随着业务的不断扩大,需求功能的持续增加,单块架构已经很难满足业务快速变化的需要。一方面,代码的可维护性、扩展性、灵活性在降低;另一方面,系统的修改成本、构建以及维护成本在显著增加。因此,单块架构应用的改造与重构势在必行。

1.单块架构及其面临的挑战

三层应用架构

      现实生活中,“层”这个字的含义,大家一点都不陌生。我们经常说楼房高多少层,蛋糕有几层等。通常来说,层有好几种定义,但其中最耳熟能详的,莫过于“层”能帮助我们划分出构成某整体事物的、上下相互支撑的不同部分。譬如,我们喜欢吃的蛋糕,一般是由三层组成:第一层的蛋糕体、第二层的奶油和第三层的水果。从顶部至底部,每一层依赖于下一层,从底部到顶部,每一层又支撑着上一层。在软件架构模式领域,经过多年的发展,也有了层的概念:

      ●层能够被单独构造。

      ●每层具有区别于其他层的显著特点。

      ●层与层之间能够互相连接,互相支撑,互相作用,相互协作,从而构成一个整体。

      ●层的内部可以被替换成其他可工作的部分,但对整体的影响不大。

       以Web应用程序为例,在Web应用程序开发的早期,由于受到面向过程的思维及设计方式的影响,所有的逻辑代码并没有明显的区分,因此代码之间的调用相互交错,错综复杂。譬如,我们早期使用的ASP、JSP以及PHP,都是将所有的页面逻辑、业务逻辑以及数据库访问逻辑放在一起,这是我们通常提到的一层架构。

      随着Java、.NET等高级语言的快速发展,这些语言为开发者提供了越来越方便的数据访问机制,如Java语言的JDBC、IO流,或者.NET的ADO.NET等。这时候,数据访问部分的代码逐渐有了清晰的结构,但表示逻辑和业务逻辑依然交织在一起,我们称这个阶段为二层架构阶段

       随着面向对象分析、面向对象设计、面向对象原则、设计模式、企业架构模式等理念以及方法论的不断发展,从为用户提供功能以及有效组织软件结构的角度考虑,Web应用中不同职责的部分逐渐被定义在了不同的层次,每一层负责的部分更趋向于具体化、细致化,于是软件的三层架构逐渐出现了。

      三层架构通常包括表示层、业务逻辑层以及数据访问层。

     ●表示层

     表示层部分通常指当用户使用应用程序时,看见的、听见的、输入的或者交互的部分。譬如,有可能是信息的显示、音乐的播放、可以输入的文本框、单选按钮,以及可单击的按钮等。通过这些元素,用户同软件进行交互并获取期望的结果。目前的用户接口大部分情况下为Web方式,当然也可以是桌面软件的形式,例如.NET的WINFORM或者Java的SWING。

      ●业务逻辑层

      业务逻辑部分是根据用户输入的信息,进行逻辑计算或者业务处理的部分。业务逻辑层主要聚焦应用程序对业务问题的逻辑处理,以及业务流程的操作,它是大部分软件系统区别于其他系统的核心。譬如,当用户单击一个按钮后,它可能会触发业务逻辑部分的代码进行运算,生成用户期望的结果。举例来说,在一个电子商务平台中,作为用户,当我们下单购买某商品后,应用程序的业务逻辑层会对订单进行处理,如计算折扣、进行配送等。

     ●数据访问层

     在用户同应用程序交互的过程中,会产生数据。这类数据需要通过某种机制被有效地保存,并在将来能够被重复使用,或者提供给其他系统。这种机制或者方法就是数据访问层最关注的部分。也就是说,它关注的是应用程序是如何有效地将数据存储到数据库、文件系统或者其他存储介质中。有一点要注意的是,它关注的是对原始数据的操作(数据库或者文件系统等存取数据的形式以及接口),而非原始数据的存储介质本身(数据库或者文件系统本身)。

单块架构

      虽然软件的三层架构帮助我们将应用在逻辑上分成了三层,但它并不是物理上的分层。这也就意味着,即便我们将应用架构分成了所谓的三层,经过开发团队对不同层的代码实现,经历编译(非静态语言则忽略编译阶段)、打包、部署后,不考虑负载均衡以及水平扩展的情况,最终还是运行在同一台机器的同一个进程中。对于这种功能集中、代码和数据中心化、一个发布包、部署后运行在同一进程的应用程序,我们通常称之为单块架构应用。典型的单块架构应用,莫过于传统的J2EE项目所构建的产品或者项目,它们存在的形态一般是WAR包或者EAR包。当部署这类应用时,通常是将整个一块作为一个整体,部署在同一个Web容器,如Tomcat或者Jetty中。当这类应用运行起来后,所有的功能也都运行在同一个进程中。

     对于单块架构应用的定义,其实是在分层软件架构设计的系统基础之上,从部署模式、运行模式角度去考虑的一种定义方式。

单块架构的优势

易于开发

对单块架构的应用程序而言,开发方式相对简单。首先从概念上,现有的大部分工具、应用服务器、框架都是这类单块架构应用程序,容易理解而且为人所熟知。如果从实践角度出发,现有的集成开发工具比较适合单块架构的应用程序,像NetBeans、Eclipse、IDEA等,它们都能够有效加载并配置整个应用程序的依赖,方便开发人员开发、运行、调试等。

易于测试

单块架构应用程序也非常容易被测试,因为所有的功能都运行在一个进程中,启动集成开发环境或者将发布包部署到某一环境,一旦启动该进程,就可以立即开始系统测试或者功能测试。

易于部署

对单块架构的应用程序而言,部署也比较容易。实际上,由于所有的功能最终都会打成一个包,因此只需复制该软件包到服务器相应的位置即可。当然,部署的方式可以有很多种,最简单的可以使用SCP远程复制到指定的目录下,当然也可以使用某些自动化的工具来完成。

易于水平伸缩

对单块架构的应用程序而言,水平伸缩也比较容易。实际上,由于所有的功能最终都会打成一个包,且只能运行在一个进程中,因此单块架构的水平伸缩,更确切地理解其实是克隆,即新建一个服务器节点,配置好该节点的运行环境,复制软件包到相应的位置,运行该应用程序。

 

单块架构面临的挑战

维护成本增加

随着应用程序的功能越来越多,团队越来越大,相应的沟通成本、管理成本、人员协调成本必然会显著增加。譬如,对于使用Java编写的中型应用而言,当代码量为几万行时,可能只需要几人左右的团队维护。当代码量上升到几十万行级别时,可能需要几十人甚至是上百人的团队。随着应用程序功能的增多,当出现缺陷时,有可能引起缺陷的原因组合就会比较多,这也会导致分析缺陷、定位缺陷、修复缺陷的成本相应增高,也就意味着缺陷的平均修复周期可能会花费更长时间。另外,随着代码量的增加,在开发人员对全局功能缺乏深度理解的情况下,修复一个缺陷,还有可能引入其他缺陷。在自动化测试机制不完善的情况下,很可能导致该过程陷入“修复越多,缺陷越多”的恶性循环,最终导致维护成本高居不下.

持续交付周期长

随着应用程序的功能越来越多,代码越来越复杂,构建和部署时间也会相应增加。在现有部署流水线稳定工作的情况下,对单块架构应用程序做任何细微的修改以及代码提交,都会触发部署流水线,令其对整个应用程序进行代码编译、运行单元测试、代码检查、构建并生成部署包、验证功能等,这也就意味着流水线的反馈周期变长,单位时间内构建的效率变低了。

新人培养周期长

随着应用程序的功能越来越多,代码变得越来越复杂,对于新加入团队的成员而言,了解行业背景、熟悉应用程序业务、配置本地开发环境这些看似简单的任务,将会花费越来越长的时间。

技术选型成本高

传统的单块架构系统倾向于采用统一的技术平台或方案来解决所有问题。通常,技术栈的决策是在团队开发之前经过架构师、技术经理慎重评估后选定的,每个团队成员都必须使用相同的开发语言、持久化存储及消息系统,而且要使用类似的工具。随着应用程序的复杂性逐渐增加以及功能越来越多,如果团队希望尝试引入新的框架、技术,或者对现有技术栈升级,通常会面临不小的风险。另一方面,互联网行业不仅市场变化快,而且技术变化也快。

对单块架构的应用而言,初始的技术选型严重限制了其将来采用不同语言或框架的能力。如果想尝试新的编程语言或者框架,没有完备的功能测试集,很难平滑完成替换,而且系统规模越大,风险越高。

可扩展性差

无论是垂直扩展还是水平扩展,单块架构都存在不同程度的扩展性问题。

垂直扩展

如果应用程序的所有功能代码都运行在同一个服务器上,将会导致应用程序的扩展非常困难。如果扩展要求紧急,那么垂直扩展(VerticalScaling或Scale-up)可能是最容易的(如果钱不是问题的话)。在大多数情况下,如果舍得砸钱上IBM的服务器、Oracle的数据库或者来自EMC的存储设备,不用改变一行代码,整个世界都会变好的。不幸的是,伴随着业务的增加,数据的增加,垂直扩展可能会变得一次比一次吃力,成本越来越高。

水平扩展

水平扩展(HorizontalScaling或Scale-out)通常的做法是建立一个集群,通过在集群中不断添加新节点,然后借助前端的负载均衡器,将用户的请求按照某种算法,譬如轮转法、散列法或者最小连接法等合理地将请求分配到不同的节点上。但是,对于单块架构而言,由于所有程序代码都运行在服务器上的同一个进程中,会导致应用程序的水平扩展成本非常高。譬如,如果应用程序某部分的功能是内存密集型的,需要缓存大量数据,而另外一部分功能是CPU密集型的,需要进行大量的运算,那么每次实施水平扩展,运行该应用的服务器都必须有足够的内存和强劲的CPU来满足需求。

构建全功能团队难

单块架构的开发模式在分工时往往以技能为单位,比如用户体验团队、服务端团队和数据库团队等,这样的分工可能会导致任何功能上的改变都需要跨团队沟通和协调。

 

2.微服务架构综述

什么是微服务架构

微服务架构是一种架构模式,它提倡将单一应用程序划分成一组小的服务,服务之间互相协调、互相配合,为用户提供最终价值。每个服务运行在其独立的进程中,服务与服务间采用轻量级的通信机制互相沟通(通常是基于HTTP的RESTfulAPI)。每个服务都围绕着具体业务进行构建,并且能够被独立地部署到生产环境、类生产环境等。另外,应尽量避免统一的、集中式的服务管理机制,对具体的一个服务而言,应根据业务上下文,选择合适的语言、工具对其进行构建。

多微才够微:

微服务架构通过对特定业务领域的分析与建模,将复杂的应用分解成小而专一、耦合度低并且高度自治的一组服务,每个服务都是很小的应用。那么,微服务中提到的“微”,到底是个什么样的“微”呢?

代码行数,对于实现同样的功能,选择不同的语言,代码的行数会千差万别。因此,代码行数这种量化的数字显然无法成为衡量微服务是否够“微”的决定因素。

重写时间,同样的周期,对于不同的个体而言,结果可能不尽相同。我们知道,对于功能的替换或者重写,很大程度取决于个体成员的工作经验、擅长的开发语言、对业务背景的了解等。

多长时间能够重写该服务也不能作为衡量其是否“微”的重要因素。

团队觉得好才是真的好,微服务到底有多微,是个仁者见仁,智者见智的问题,最重要的是团队觉得合适。

业务独立性,应该保证微服务是具有业务独立性的单元,并不能只是为了微而微。

团队自主性,考虑到团队的沟通及协作成本,一般不建议超过10个人。当团队超过10个人,在沟通、协作上所耗费的成本会显著增加,而这也是大部分敏捷实践里提倡的。当团队成员超过10个人的时候,可以考虑继续再划分子团队,让不同的子团队承担独立的工作,这也是笔者在实践中通常采用的做法。

单一职责:

对于每个服务而言,我们希望它处理的业务逻辑能够单一,在服务架构层面遵循单一职责原则。也就是说,微服务架构中的每个服务,都是具有业务逻辑的,符合高内聚、低耦合原则以及单一职责原则的单元,不同的服务通过“管道”的方式灵活组合,从而构建出庞大的系统。

即,高内聚、低耦合

轻量级通信:

服务之间应通过轻量级的通信机制,实现彼此间的互通互联,互相协作。所谓轻量级通信机制,通常指语言无关、平台无关的交互方式。譬如,某些复杂的系统,由Java、Ruby以及Node等不同开发语言实现的部分组成,不同部分之间能够采用语言无关、平台无关的方式进行交互,

对于轻量级通信的格式而言,我们熟悉的XML或者JSON,它们的解析和使用基本与语言无关、平台无关。对于轻量级通信的协议而言,通常基于HTTP,能让服务间的通信变得标准化并且无状态化。目前,大家所熟悉的REST(RepresentationalStateTransfer),是实现服务之间互相协作的轻量级通信机制之一。

对于微服务而言,通过使用语言无关、平台无关的轻量级通信机制,使服务与服务之间的协作变得更加标准化,也就意味着在保持服务外部通信机制轻量级的情况下,团队可以选择更适合的语言、工具或者平台来开发服务本身。

独立性:

独立性指在应用的交付过程中,开发、测试以及部署的独立。

在单块架构中,功能的开发、测试、构建以及部署耦合度较高,相互影响。

对于每个服务,都有独立的测试机制,并不必担心破坏其他功能而需要建立大范围的回归测试。也就是说,从测试的角度而言,服务和服务之间是松耦合的。

由于构建包是独立的,部署流程也就能够独立,因此服务能够运行在不同的进程中。从部署的角度考虑,服务和服务之间也是高度解耦的.

进程隔离

在单块架构中,整个系统运行在同一个进程中,虽然我们将应用程序的代码分成逻辑上的三层、四层甚至更多层,但它并不是物理上的分层。这也意味着,经过开发团队对不同层的代码实现,经历过编译、打包、部署后,不考虑负载均衡以及水平扩展的情况,应用的所有功能会运行在某机器的同一个进程中。所有功能都运行在同一个进程中,也就意味着,当对应用进行部署时,必须停掉当前正在运行的应用,部署完成后,再重新启动进程,无法做到独立部署。如果当前某应用中包含定时任务的功能,则要考虑在什么时间窗口适合部署,是否先停掉消息队列或者切断与数据源的联系,以防止数据被读入应用程序内存,但还未处理完,应用就被停止而导致的数据不一致性。

微服务架构其实是将单一的应用程序划分成一组小的服务,每个服务都是具有业务属性的独立单元,同时能够被独立开发、独立运行、独立测试以及独立部署。

微服务的诞生背景

互联网行业的快速发展;

敏捷、惊异方法论的深入人心;

单块架构系统面临的挑战;

容器虚拟化技术,特别是Docker的出现;

如果说之前的敏捷、精益、持续交付以及DevOps是微服务诞生的催化剂,那Docker的出现,则有效解决了微服务的环境搭建、部署以及运维成本高的问题,为微服务朝大规模应用起到了推波助澜的关键作用。所以,微服务的诞生绝不是偶然,是多重因素推动下的必然产物。

微服务不是银弹

对于微服务而言,其优势是很明显的:

独立性;

单一职责;

技术多样性;

微服务的优势,解决了传统的单块架构系统随着业务需求的快速变化而面临的挑战,使得其看起来像一个完美的解决方案。那微服务是否是传说中的银弹?

实际上,在微服务的实施过程中,需要考虑如下因素:

●分布式系统的复杂度:性能、可靠性、异步、数据一致性、工具

●运维成本:配置、部署、监控与告警、日志收集;

●部署自动化

●DevOps与组织架构

●服务间依赖测试

●服务间依赖管理

备注:

DevOps(Development和Operations的组合词)是一组过程、方法与系统的统称,用于促进开发(应用程序/软件工程)、技术运营和质量保障(QA)部门之间的沟通、协作与整合。

它是一种重视“软件开发人员(Dev)”和“IT运维技术人员(Ops)”之间沟通合作的文化、运动或惯例。透过自动化“软件交付”和“架构变更”的流程,来使得构建、测试、发布软件能够更加地快捷、频繁和可靠。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值