最近阅读了一本架构方面的入门图书叫《从零开始学架构:照着做,你也能成为架构师》,部分内容比较不错,先做书摘总结,以便加深印象与未来回顾学习。
本文是该书第四部分,是书中第十一至十五章,主要介绍可扩展模式、分层架构、SOA架构、微服务、微内核架构等,涉及到可扩展思想、分层、SOA、微服务实践、OSGi架构等内容。
连续阅读,请点击如下链接:
第十一章 可扩展模式
-
软件系统的这种天生和内在的可扩展的特性,难点体现在如何以最小的代价去扩展系统,如何避免扩展时改动范围太大,是软件架构可扩展行设计的主要思考点。
-
所有的可扩展性架构设计,背后的基本思想都可以总结为一个字:**拆!**所谓拆,就是将原本大一统的系统拆分成多个规模小的部分,扩展时只修改其中一部分即可,无须整个系统到处都改,通过这种方式来减少改动范围,降低改动风险。这里的拆是让软件系统变得具备更好的可扩展性。形象的说,软件系统中的“拆”是建设性的,因此难度要高得多。
-
常见拆分思路:
- 面向流程拆分:将整个业务流程拆分为几个阶段,每个阶段作为一部分。
- 优点:扩展时大部分情况只需要修改某一层,少部分情况可能修改关联的两层,不会出现所有层都同时要修改。
- 面向服务拆分:将系统提供的服务拆分,每个服务作为一部分。
- 优点:对某个服务扩展,或者要增加新的服务时,只需要扩展相关服务即可,无需修改所有的服务。
- 面向功能拆分:将系统提供的功能拆分,每个功能作为一部分。
- 优点:对某个功能扩展,或者要增加新的功能时,只需要扩展相关功能即可,无需修改所有的服务。
从范围上来说,流程→服务→功能。
- 面向流程拆分:将整个业务流程拆分为几个阶段,每个阶段作为一部分。
-
不同的拆分方式,本质上决定了系统的扩展方式。而合理的拆分,能够强制保证即使程序员出错,出错的范围也不会太广,影响也不会太大。
-
典型的可扩展系统架构;
- 面向流程拆分:分层架构。
- 面向服务拆分:SOA、微服务。
- 面向功能拆分:微内核架构。
上述可扩展系统架构并不是非此即彼的,而是可以在系统架构设计中进行组合使用的。
第十二章 分层架构
- 分层架构是很常见的架构模式,通常情况下,N至少为2层。例如,C/S架构、B/S架构。常见的是3层架构(例MVC、MVP架构)、4层架构、5层架构比较少见,一般是比较复杂的系统才会达到或超过5层,例操作系统内核架构。几种分层架构:
- **C/S、B/S架构:**划分对象是整个业务系统,划分的维度是用户交互。
- **MVC架构、MVP架构:**划分的对象是单个业务子系统,划分的维度是职责,将不同的职责划分到独立层,但各层的依赖关系比较灵活。
- **逻辑分层架构:**划分的对象可以是单个业务子系统,也可以是整个业务系统,划分的维度也是职责。虽然都是基于职责划分,但逻辑分层架构和MVC架构、MVP架构的不同点在于,逻辑分层架构中的层是自顶向下依赖的。典型的有操作系统内核架构、TCP/IP架构。
- 分层架构设计最核心的一点就是需要保证各层之间的差异足够清晰,边界足够明显,让人看到架构图后就能看懂整个架构。
- 分层架构之所以能够较好地支撑系统扩展,本质在于:隔离关注点(separation of concerns),即每个层中的组建只会处理本层的逻辑。
- 并不是简单地分层就一定能够实现隔离关注定从而支撑快速扩展,分层时要保证层与层之间的依赖是稳定的,才能真正支撑快速扩展。
- 对于操作系统这类复杂的系统,接口本身也可以成为独立的一层。而对于一个简单的业务系统,接口可能就是Java语言上的几个interface定义,这种情况下如果独立为一层,看起来就比较重了。
- 分层结构的另外一个特点就是层层传递,也就是说一旦分层确定,整个业务流程是按照层进行依次传递的,不能在层之间进行跳跃。分层结构的这种约束,好处在于强制将分层依赖限定为两两依赖,降低了整体系统复杂度。但分层结构的代价就是冗余,也就是说,不管这个业务有多么简单,每层都必须要参与处理,甚至可能每层都写了一个简单的包装函数。
- 不建议自由选择绕过分层约束,分层架构的优势就体现在通过分层强制约束两两依赖,一旦自由选择绕过分层,时间一长,架构就会变得混乱。这样做就失去了分层架构的意义,也导致后续扩展时无法控制受影响范围,牵一发而动全身,无法支持快速扩展。除此以外,虽然分层架构的实现在某些场景下看起来有些繁琐和冗余,但复杂度却很低。
- 分层架构除了冗余另一个典型缺点就是性能,因为每一次业务请求都需要穿越所有的架构分层,有一些事情是多余的,多少都会有一些性能的浪费。但到了现在,硬件和网络的性能有了质的飞跃,其实分层模式理论上的这点性能损失,在实际应用中,绝大部分场景下都可以忽略不计。
第十三章 SOA架构
- SOA全称是Service Oriented Architecture,中文翻译为“面向服务的架构”,诞生于20世纪90年代。SOA提出的背景是企业内部IT系统重复建设且效率低下。
- SOA三个关键概念:
- 服务:所有业务功能都是一项服务,服务就意味着要对外提供开放的能力,当其他系统需要使用这项功能时,无需定制化开发。
- ESB:ESB的全称是Enterprise Service Bus,中文翻译为“企业服务总线”。从名字就可以看出,ESB参考了计算机总线的概念。
- 松耦合:松耦合的目的是减少各个服务之间的依赖和互相影响。
- SOA架构是比较高层级的架构设计概念,一般情况下我们可以说某个企业采用了SOA的架构来构建IT系统,但不会说某个独立系统采用了SOA架构。
- SOA解决了传统IT系统重复建设和扩展效率低的问题,但其本身也引入了更多的复杂性。SOA最为人诟病就是ESB,ESB需要实现与各种系统间的协议转换、数据转换、透明的动态路由等功能,工作量和复杂度都很大,而且转换需要耗费大量计算性能。ESB本身会成为整个系统的性能瓶颈。
第十四章 微服务
-
微服务架构模式是一种将单个应用程序开发为一套**小型服务的方法,每个小型服务都在自己的流程中运行,并与轻量级机制(通常是HTTP资源API)进行通信。这些服务围绕业务功能构建,可通过全自动**部署机制独立部署。
-
微服务与SOA关系
-
**服务粒度:**SOA的服务粒度要粗一些,而微服务的服务粒度要细一些。
-
**服务通信:**微服务推荐使用统一的协议和格式,例如RESTful协议、RPC协议,无需ESB这样的重量级实现。而微服务的"dumb pipes"仅仅做消息传递,对消息格式和内容一无所知。
-
**服务交付:**微服务的架构理念要求“快速交付”,相应地要求采取自动化测试、持续集成、自动化部署等敏捷开发相关的最佳实践。如果没有这些基础能力支撑,微服务规模一旦变大(例如超过20个微服务),整体就难以达到快速交付的要求,这也是很多企业在实行微服务时踩过的一个明显的坑,就是系统拆分为微服务后,部署的成本成指数上升。
-
**应用场景:**SOA更加适合于庞大、复杂、异构的企业级系统。微服务更加适合于快捷、轻量级、基于Web的互联网系统,这类系统业务变化很快,需要快速尝试、快速交付;同时基本都是基于Web,虽然开发技术可能差异很大(例如Java、C++、.NET等),但对外接口基本都是提供HTTP RESTful风格的接口,无需考虑在接口层进行类似SOA的ESB那样的处理。
总结表格如下:
对比维度 SOA 微服务 服务粒度 粗 细 服务通信 重量级,ESB 轻量级,例如RESTful 服务交付 慢 快 应用场景 企业级 互联网 SOA和微服务本质上是两种不同的架构设计理念,只是在“服务”这个点上有交集而已,因此两者的关系应该是第三种模式。
-
-
微服务的陷阱
-
**服务划分过细,服务间关系复杂:**服务划分过细,单个服务的复杂度确实下降了,但整个系统的复杂度却上升了,因为微服务将系统内的复杂度转移为系统间的复杂度了。从理论的角度来计算,n个服务的复杂度是\(\frac{n×(n-1)}{2}\),整体系统的复杂度是随着微服务数量的增加呈指数级增加的。
-
**服务数量太多,团队效率急剧下降:**微服务的“微”字,本身就是一个陷阱,很多团队看到“微”字后,就想到必须将服务拆分得很细,有的团队人员规模的5-6人,然而却拆分出30多个微服务,平均每个人要维护5个以上的微服务。这样做给工作效率带来了明显的影响,一个简单的需求开发就需要涉及多个微服务。光是微服务之间的接口就有6-7个,无论涉及、开发,还是测试、部署,都需要工程师不停地在不同的服务间切换。
-
调用链太长,性能下降
-
调用链太长,问题定位困难
-
没有自动化支撑,无法快速交付
-
没有服务治理,微服务数量多了后管理混乱
总结一下,微服务的陷阱主要有以下几点:
- 微服务拆分过细,过分强调“small”;
- 微服务基础设施不健全,忽略了“automated”;
- 微服务并不轻量级,规模大了后,“lightweight”不再适应。
-
-
微服务最佳实践
-
服务粒度:建议基于团队规模进行拆分。“三个火枪手”微服务拆分粒度原则,即一个微服务三个人负责开发。当我们在实施微服务架构时,根据团队规模来划分微服务数量,如果业务规模继续发展,团队规模扩大,我们再将已有的微服务进行拆分。
这样做的道理是:从系统规模来讲,3个人负责开发一个系统,系统的复杂度刚好达到每个人都能全面理解整个系统,又能够进行分工的粒度;从团队管理来说,3个人可以形成一个稳定备份;从技术提升角度来说,3个人的技术小组既能够形成有效讨论,又能够快速达成一致意见。
“三个火枪手”的原则主要应用于微服务设计和开发阶段,如果微服务经过一段时间发展后已经比较稳定,处于维护期了,无须太多的开发,那么1个人维护1个微服务甚至几个微服务都可以。
-
拆分方法:
- 基于业务逻辑拆分:最常见拆分方式,将系统中的业务模块按照职责范围识别出来,每个单独的业务模块拆分为一个独立的服务。
- 基于可扩展拆分:将系统中的业务模块按照稳定性进行排序,将已经成熟和改动不大的服务拆分为稳定服务,将经常变化和迭代的服务拆分为变动服务。这样的拆分主要是为了提升项目快速迭代的效率避免在开发的时候,不小心影响已有的成熟功能导致线上问题。
- 基于可靠性拆分:将系统中的业务模块按照优先级顺序,将可靠性要求高的核心服务和可靠性要求低的非核心服务拆分开来,然后重点保证核心服务的高可用。这样拆分可以避免非核心业务故障影响核心服务、核心服务高可用方案可以更简单、能够降低高可用成本。
- 基于性能拆分:类似于基于可靠性拆分,将性能要求高或性能压力大的模块拆分出来,避免性能压力大的服务影响其他服务。
以上几种拆分方式不是多选一,而是可以根据实际情况自由排列组合。
-
基础设施:
微服务并没有减少复杂度,而只是将复杂度从ESB转移到了基础设施。例如“服务发现”“服务路由”等其实都是ESB的功能,只是在微服务中剥离出来成了独立的基础系统。
每项微服务基础设施都是一个平台、一个系统、一个解决方案,如果要自己实现,其过程和做业务系统类似,都需要经过需求分析、架构设计、开发、测试、部署上线等步骤。
-
自动化测试
微服务将原本大一统的系统拆分为多个独立运行的“微”服务,微服务之间的接口数量大大增加,并且微服务提倡快速交付,版本周期短,版本更新频繁。因此必须通过自动化测试系统来完成绝大部分测试回归的工作。
自动化测试涵盖的范围包括代码级的单元测试、单个系统级的集成测试、系统间的接口测试,理想情况是每类测试都自动化。如果因为团队规模和人力的原因无法全面覆盖,至少要做到接口测试自动化。
-
自动化部署
相比大一统的系统,微服务需要部署的节点增加了几倍甚至几十倍,微服务部署的频率也会大幅提升,综合计算下来,微服务部署的次数是大一统系统部署次数的几十倍。这么大量的部署操作,如果继续采用人工手工处理,需要投入大量的人力,且容易出错,因此需要自动化部署的系统来完成部署操作。
自动化部署系统包括版本管理、资源管理(例机器管理、虚拟机管理)、部署操作、回退操作等功能。
-
配置中心
微服务需要一个统一的配置中心来管理所有微服务节点的配置。配置中心包括配置版本管理(例同样的微服务,有10个节点是给移动用户服务的,有20个节点给联通用户服务的,配置项都一样,配置值不一样)、增删改查配置、节点管理、配置同步、配置推送等功能。
-
接口框架
微服务提倡轻量级的通信方式,一般采用HTTP RESTful或RPC方式统一接口协议。但在实践过程中,光统一接口协议还不够,还需要统一接口传递的数据格式。例如,我们需要指定接口协议为HTTP RESTful,但我们还需要指定HTTP RESTful的数据格式采用JSON,并且JSON的数据都遵循一定规范。
同时,我们需要统一接口框架。接口框架不是一个可运行的系统,一般以库或包的形式提供给所有微服务调用。例如,针对上面的JSON样例,可以由某个基础技术团队提供多种不同语言的解析包(Java、Python、C等)。
-
API网关
微服务需要一个统一的API网关,负责外部系统的访问操作。
API网关是外部系统访问的接口,所有的外部系统接入系统都需要通过API网关,主要包括接入鉴权(是否允许接入)、权限控制(可以访问哪些功能)、传输加密、请求路由、流量控制等功能。
-
服务发现
节点的变化能被即使同步到所有其他依赖的微服务。这就是服务的自动注册和发现。服务发现主要由自理式和代理式两种。
自理式结构就是指每个微服务自己完成服务发现。
代理式结构是指微服务之间有一个负载均衡系统,由负载均衡系统来完成微服务之间的服务发现。代理式的方式更清晰,微服务本身的实现也简单许多,但这个方案风险较大,第一是可用性风险,第二是性能奉献,因此LOAD BALANCER系统需要设计成集群的模式,但LOAD BALANCER集群的实现本身又增加了复杂性。
不管是自理式还是代理式,服务发现的核心功能就是服务注册表,注册表记录了所有的服务节点的配置和状态,每个微服务启动后都需要将自己的信息注册到服务注册表,然后由微服务或LOAD BALANCER系统到服务注册表查询可用服务。
-
服务路由
服务路由和服务发现紧密相关,服务路由一般不会设计成一个独立运行的系统,通常情况下是和服务发现放在一起实现的。对于自理式服务发现,服务路由是微服务内部实现的;对于代理式服务发现,服务路由是由LOAD BALANCER系统实现的。常见的路由算法有:随机路由、轮询路由、最小压力路由、最小连接数路由等算法。
-
服务容错
需要微服务能够自动应对出错常见,及时进行处理。否则如果节点一鼓掌就需要人工处理,投入人力大,处理速度慢。而一旦处理速度慢,则故障就很快扩散。常见的服务容错包括请求充实、流控和服务隔离。
流控:通常情况下,流控由各个微服务节点自己实现,可以将流控策略包装成公共库提供给各个微服务使用,减少重复实现。
服务隔离:当某个微服务节点故障时,最快最简单的处理方式就是直接将当前故障节点下线隔离,避免故障进行扩散。通常情况下,服务隔离分为主动隔离、被动隔离和手动隔离。
-
服务监控
服务监控主要是有实时搜集信息并进行分析,避免故障后再来分析,减少了处理时间。服务监控可以在实时分析的基础上进行预警,在问题萌芽的阶段发觉并预警,降低了问题影响的范围和时间。
-
服务跟踪
即跟踪某一个请求在微服务中的完整路径。服务跟踪的关键技术有标注点、跟总数和span。
服务跟踪一般主要用于采样跟踪和染色跟踪。
-
服务安全
部分敏感数据或操作只能部分微服务可以访问,而不是所有的微服务都可以访问。因此需要设计服务安全机制来保证业务和数据的安全性。服务安全主要分为接入安全、数据安全、传输安全等部分。
服务安全可以集成到配置中心系统中进行实现,即配置中心配置微服务的接入安全策略和数据安全策略,微服务节点从配置中心获取这些配置信息,然后在处理具体的微服务调用请求时根据安全策略进行处理。由于这些策略是通用的,一般会把策略封装成通用的库提供给各个微服务调用。
-
-
第十五章 微内核架构
-
Microkernel Architecture,中文翻译为“微内核架构”,也被称为插件化架构(Plug-in Architecture),是一种面向功能进行拆分的可扩展性架构,通常用于实现基于产品(英文原文为product-based,指存在多个版本、需要下载安装才能使用,与web-based相对应)的应用。
**微内核架构包含两类组件:核心系统(core system)和插件模块(plug-in modules)。**核心系统功能比较稳定,不会因为业务功能扩展而不断修改,插件模块可以根据业务功能的需要不断地扩展。微内核架构通过隔离变化到插件的方式提供了灵活性、可扩展性。
-
微内核核心系统设计关键技术:
- 插件管理:核心系统需要知道当前有哪些插件可用,如何加载这些插件,什么时候加载插件。常见的实现方法是插件注册表机制。
- 插件连接:插件如何连接到核心系统。常见的连接机制有OSGi(Eclipse)、消息模式、依赖注入(Spring)、甚至使用分布式的协议都是可以的,比如RPC或HTTP Web的方式。
- 插件通信:指插件间的通信。由于插件之间没有直接联系,通信必须通过核心系统,因此核心系统需要提供插件通信机制。
-
OSGi架构
- 全称Open Services Gateway Initiative,本身其实是指OSGi Alliance。现在我们讨论OSGi,已经和嵌入式应用关联不大了,更多的是将OSGi当做一个微内核的架构模式。
- Eclipse采用的是OSGi框架称为Equinox,类似的实现还有Apache的Felix,Spring的Spring DM。
- 模块层(Module):完成插件管理功能。
- 生命周期层(Lifecycle):完成插件连接功能,提供了执行时模块管理、模块对底层OSGi框架的访问。
- 服务层(Service):完成插件通信的功能。
-
规则引擎架构
- 规则引擎从结构上来看也属于微内核架构的一种具体体现,其中执行引擎可以看做微内核,执行引擎解析配置好的业务流,执行其中的条件和规则,通过这种方式来支持业务的灵活多变。规则引擎在计费、保险、促销等业务领域应用较多。
- 规则引擎能够很灵活的应对促销方案规则组织组合之类的需求,主要是其可扩展、易理解、高效率。
- 目前最常用的规则引擎是开源的JBoss Drools,采用java编写,基于Rete算法。Drools具有以下优点:
- 非常活跃的社区支持以及广泛的应用;
- 快速的执行速度;
- 与Java Rule Engine API(JSR-94)兼容;
- 提供基于Web的BRMS——Guvnor。
其他相关摘要
- OSGi中,插件被称为Bundle。