# 架构学习书摘总结（四）可扩展架构模式

> 作者：zning（https://ning.ae） · 发布：2019/06/07 23:44 下午 (UTC+8) · 原文：https://zning.me/15599222898499.html

最近阅读了一本架构方面的入门图书叫《从零开始学架构：照着做，你也能成为架构师》，部分内容比较不错，先做书摘总结，以便加深印象与未来回顾学习。

本文是该书第四部分，是书中第十一至十五章，主要介绍可扩展模式、分层架构、SOA架构、微服务、微内核架构等，涉及到可扩展思想、分层、SOA、微服务实践、OSGi架构等内容。

连续阅读，请点击如下链接：

* [架构学习书摘总结（一）概念和基础部分](./15511868502157.html)

* [架构学习书摘总结（二）高性能架构模式](./15517030839592.html)

* [架构学习书摘总结（三）高可用架构模式](./15521364926344.html)

* [架构学习书摘总结（四）可扩展架构模式](./15599222898499.html)

* [架构学习书摘总结（五）架构实战](./15600074562241.html)

## 第十一章 可扩展模式

1. 软件系统的这种天生和内在的可扩展的特性，难点体现在如何以最小的代价去扩展系统，如何避免扩展时改动范围太大，是软件架构可扩展行设计的主要思考点。
2. 所有的可扩展性架构设计，背后的基本思想都可以总结为一个字：**拆！**所谓拆，就是将原本大一统的系统拆分成多个规模小的部分，扩展时只修改其中一部分即可，无须整个系统到处都改，通过这种方式来减少改动范围，降低改动风险。这里的拆是让软件系统变得具备更好的可扩展性。形象的说，软件系统中的“拆”是建设性的，因此难度要高得多。
3. 常见拆分思路：
    1. 面向流程拆分：将整个业务流程拆分为几个阶段，每个阶段作为一部分。
        * 优点：扩展时大部分情况只需要修改某一层，少部分情况可能修改关联的两层，不会出现所有层都同时要修改。
    2. 面向服务拆分：将系统提供的服务拆分，每个服务作为一部分。
        * 优点：对某个服务扩展，或者要增加新的服务时，只需要扩展相关服务即可，无需修改所有的服务。
    3. 面向功能拆分：将系统提供的功能拆分，每个功能作为一部分。
        * 优点：对某个功能扩展，或者要增加新的功能时，只需要扩展相关功能即可，无需修改所有的服务。

    从范围上来说，流程→服务→功能。

1. 不同的拆分方式，本质上决定了系统的扩展方式。而合理的拆分，能够强制保证即使程序员出错，出错的范围也不会太广，影响也不会太大。
2. 典型的可扩展系统架构；
    1. 面向流程拆分：分层架构。
    2. 面向服务拆分：SOA、微服务。
    3. 面向功能拆分：微内核架构。

    上述可扩展系统架构并不是非此即彼的，而是可以在系统架构设计中进行组合使用的。

## 第十二章 分层架构

1. 分层架构是很常见的架构模式，通常情况下，N至少为2层。例如，C/S架构、B/S架构。常见的是3层架构（例MVC、MVP架构）、4层架构、5层架构比较少见，一般是比较复杂的系统才会达到或超过5层，例操作系统内核架构。几种分层架构：
    1. **C/S、B/S架构：**划分对象是整个业务系统，划分的维度是用户交互。
    2. **MVC架构、MVP架构：**划分的对象是单个业务子系统，划分的维度是职责，将不同的职责划分到独立层，但各层的依赖关系比较灵活。
    3. **逻辑分层架构：**划分的对象可以是单个业务子系统，也可以是整个业务系统，划分的维度也是职责。虽然都是基于职责划分，但逻辑分层架构和MVC架构、MVP架构的不同点在于，逻辑分层架构中的层是自顶向下依赖的。典型的有操作系统内核架构、TCP/IP架构。
2. 分层架构设计最核心的一点就是需要保证各层之间的差异足够清晰，边界足够明显，让人看到架构图后就能看懂整个架构。
3. 分层架构之所以能够较好地支撑系统扩展，本质在于：隔离关注点(separation of concerns)，即每个层中的组建只会处理本层的逻辑。
4. 并不是简单地分层就一定能够实现隔离关注定从而支撑快速扩展，分层时要保证层与层之间的依赖是稳定的，才能真正支撑快速扩展。
5. 对于操作系统这类复杂的系统，接口本身也可以成为独立的一层。而对于一个简单的业务系统，接口可能就是Java语言上的几个interface定义，这种情况下如果独立为一层，看起来就比较重了。
6. 分层结构的另外一个特点就是层层传递，也就是说一旦分层确定，整个业务流程是按照层进行依次传递的，不能在层之间进行跳跃。分层结构的这种约束，好处在于强制将分层依赖限定为两两依赖，降低了整体系统复杂度。但分层结构的代价就是冗余，也就是说，不管这个业务有多么简单，每层都必须要参与处理，甚至可能每层都写了一个简单的包装函数。
7. 不建议自由选择绕过分层约束，分层架构的优势就体现在通过分层强制约束两两依赖，一旦自由选择绕过分层，时间一长，架构就会变得混乱。这样做就失去了分层架构的意义，也导致后续扩展时无法控制受影响范围，牵一发而动全身，无法支持快速扩展。除此以外，虽然分层架构的实现在某些场景下看起来有些繁琐和冗余，但复杂度却很低。
8. 分层架构除了冗余另一个典型缺点就是性能，因为每一次业务请求都需要穿越所有的架构分层，有一些事情是多余的，多少都会有一些性能的浪费。但到了现在，硬件和网络的性能有了质的飞跃，其实分层模式理论上的这点性能损失，在实际应用中，绝大部分场景下都可以忽略不计。

## 第十三章 SOA架构
1. SOA全称是Service Oriented Architecture，中文翻译为“面向服务的架构”，诞生于20世纪90年代。SOA提出的背景是企业内部IT系统重复建设且效率低下。
2. SOA三个关键概念：
    1. 服务：所有业务功能都是一项服务，服务就意味着要对外提供开放的能力，当其他系统需要使用这项功能时，无需定制化开发。
    2. ESB：ESB的全称是Enterprise Service Bus，中文翻译为“企业服务总线”。从名字就可以看出，ESB参考了计算机总线的概念。
    3. 松耦合：松耦合的目的是减少各个服务之间的依赖和互相影响。
3. SOA架构是比较高层级的架构设计概念，一般情况下我们可以说某个企业采用了SOA的架构来构建IT系统，但不会说某个独立系统采用了SOA架构。
4. SOA解决了传统IT系统重复建设和扩展效率低的问题，但其本身也引入了更多的复杂性。SOA最为人诟病就是ESB，ESB需要实现与各种系统间的协议转换、数据转换、透明的动态路由等功能，工作量和复杂度都很大，而且转换需要耗费大量计算性能。ESB本身会成为整个系统的性能瓶颈。

## 第十四章 微服务

1. 微服务架构模式是一种将单个应用程序开发为一套**_小型_**服务的方法，每个小型服务都在自己的流程中运行，并与**_轻量级_**机制（通常是HTTP资源API）进行通信。这些服务围绕业务功能构建，可通过**_全自动_**部署机制独立部署。
2. 微服务与SOA关系
    1. **服务粒度：**SOA的服务粒度要粗一些，而微服务的服务粒度要细一些。

    2. **服务通信：**微服务推荐使用统一的协议和格式，例如RESTful协议、RPC协议，无需ESB这样的重量级实现。而微服务的"dumb pipes"仅仅做消息传递，对消息格式和内容一无所知。
    3. **服务交付：**微服务的架构理念要求“快速交付”，相应地要求采取自动化测试、持续集成、自动化部署等敏捷开发相关的最佳实践。如果没有这些基础能力支撑，微服务规模一旦变大（例如超过20个微服务），整体就难以达到快速交付的要求，这也是很多企业在实行微服务时踩过的一个明显的坑，就是系统拆分为微服务后，部署的成本成指数上升。
    4. **应用场景：**SOA更加适合于庞大、复杂、异构的企业级系统。微服务更加适合于快捷、轻量级、基于Web的互联网系统，这类系统业务变化很快，需要快速尝试、快速交付；同时基本都是基于Web，虽然开发技术可能差异很大（例如Java、C++、.NET等），但对外接口基本都是提供HTTP RESTful风格的接口，无需考虑在接口层进行类似SOA的ESB那样的处理。
    
    总结表格如下：
    
    | 对比维度 | SOA | 微服务 |
    | --- | --- | --- |
    | 服务粒度 | 粗 | 细 |
    | 服务通信 | 重量级，ESB | 轻量级，例如RESTful |
    | 服务交付 | 慢 | 快 |
    | 应用场景 | 企业级 | 互联网 |

    SOA和微服务本质上是两种不同的架构设计理念，只是在“服务”这个点上有交集而已，因此两者的关系应该是第三种模式。

1. 微服务的陷阱
    1. **服务划分过细，服务间关系复杂：**服务划分过细，单个服务的复杂度确实下降了，但整个系统的复杂度却上升了，因为微服务将系统内的复杂度转移为系统间的复杂度了。从理论的角度来计算，n个服务的复杂度是$\frac{n×(n-1)}{2}$，整体系统的复杂度是随着微服务数量的增加呈指数级增加的。

    2. **服务数量太多，团队效率急剧下降：**微服务的“微”字，本身就是一个陷阱，很多团队看到“微”字后，就想到必须将服务拆分得很细，有的团队人员规模的5-6人，然而却拆分出30多个微服务，平均每个人要维护5个以上的微服务。这样做给工作效率带来了明显的影响，一个简单的需求开发就需要涉及多个微服务。光是微服务之间的接口就有6-7个，无论涉及、开发，还是测试、部署，都需要工程师不停地在不同的服务间切换。
    3. **调用链太长，性能下降**
    4. **调用链太长，问题定位困难**
    5. **没有自动化支撑，无法快速交付**
    6. **没有服务治理，微服务数量多了后管理混乱**

    总结一下，微服务的陷阱主要有以下几点：
    
    1. 微服务拆分过细，过分强调“small”；
    2. 微服务基础设施不健全，忽略了“automated”；
    3. 微服务并不轻量级，规模大了后，“lightweight”不再适应。

1. 微服务最佳实践
    1. **服务粒度：**建议基于团队规模进行拆分。**“三个火枪手”微服务拆分粒度原则**，即一个微服务三个人负责开发。当我们在实施微服务架构时，根据团队规模来划分微服务数量，如果业务规模继续发展，团队规模扩大，我们再将已有的微服务进行拆分。

        这样做的道理是：从系统规模来讲，3个人负责开发一个系统，系统的复杂度刚好达到每个人都能全面理解整个系统，又能够进行分工的粒度；从团队管理来说，3个人可以形成一个稳定备份；从技术提升角度来说，3个人的技术小组既能够形成有效讨论，又能够快速达成一致意见。
        
        “三个火枪手”的原则主要应用于微服务设计和开发阶段，如果微服务经过一段时间发展后已经比较稳定，处于维护期了，无须太多的开发，那么1个人维护1个微服务甚至几个微服务都可以。
        
    1. **拆分方法：**
        1. 基于业务逻辑拆分：最常见拆分方式，将系统中的业务模块按照职责范围识别出来，每个单独的业务模块拆分为一个独立的服务。
        2. 基于可扩展拆分：将系统中的业务模块按照稳定性进行排序，将已经成熟和改动不大的服务拆分为稳定服务，将经常变化和迭代的服务拆分为变动服务。这样的拆分主要是为了提升项目快速迭代的效率避免在开发的时候，不小心影响已有的成熟功能导致线上问题。
        3. 基于可靠性拆分：将系统中的业务模块按照优先级顺序，将可靠性要求高的核心服务和可靠性要求低的非核心服务拆分开来，然后重点保证核心服务的高可用。这样拆分可以避免非核心业务故障影响核心服务、核心服务高可用方案可以更简单、能够降低高可用成本。
        4. 基于性能拆分：类似于基于可靠性拆分，将性能要求高或性能压力大的模块拆分出来，避免性能压力大的服务影响其他服务。

        以上几种拆分方式不是多选一，而是可以根据实际情况自由排列组合。

    1. **基础设施：**

        微服务并没有减少复杂度，而只是将复杂度从ESB转移到了基础设施。例如“服务发现”“服务路由”等其实都是ESB的功能，只是在微服务中剥离出来成了独立的基础系统。
        
        每项微服务基础设施都是一个平台、一个系统、一个解决方案，如果要自己实现，其过程和做业务系统类似，都需要经过需求分析、架构设计、开发、测试、部署上线等步骤。
        
        1. 自动化测试

            微服务将原本大一统的系统拆分为多个独立运行的“微”服务，微服务之间的接口数量大大增加，并且微服务提倡快速交付，版本周期短，版本更新频繁。因此必须通过自动化测试系统来完成绝大部分测试回归的工作。
            
            自动化测试涵盖的范围包括代码级的单元测试、单个系统级的集成测试、系统间的接口测试，理想情况是每类测试都自动化。如果因为团队规模和人力的原因无法全面覆盖，至少要做到接口测试自动化。
        
        1. 自动化部署

            相比大一统的系统，微服务需要部署的节点增加了几倍甚至几十倍，微服务部署的频率也会大幅提升，综合计算下来，微服务部署的次数是大一统系统部署次数的几十倍。这么大量的部署操作，如果继续采用人工手工处理，需要投入大量的人力，且容易出错，因此需要自动化部署的系统来完成部署操作。
            
            自动化部署系统包括版本管理、资源管理（例机器管理、虚拟机管理）、部署操作、回退操作等功能。        

        1. 配置中心

            微服务需要一个统一的配置中心来管理所有微服务节点的配置。配置中心包括配置版本管理（例同样的微服务，有10个节点是给移动用户服务的，有20个节点给联通用户服务的，配置项都一样，配置值不一样）、增删改查配置、节点管理、配置同步、配置推送等功能。
        
        1. 接口框架

            微服务提倡轻量级的通信方式，一般采用HTTP RESTful或RPC方式统一接口协议。但在实践过程中，光统一接口协议还不够，还需要统一接口传递的数据格式。例如，我们需要指定接口协议为HTTP RESTful，但我们还需要指定HTTP RESTful的数据格式采用JSON，并且JSON的数据都遵循一定规范。
            
            同时，我们需要统一接口框架。接口框架不是一个可运行的系统，一般以库或包的形式提供给所有微服务调用。例如，针对上面的JSON样例，可以由某个基础技术团队提供多种不同语言的解析包(Java、Python、C等)。
            
        1. API网关

            微服务需要一个统一的API网关，负责外部系统的访问操作。
            
            API网关是外部系统访问的接口，所有的外部系统接入系统都需要通过API网关，主要包括接入鉴权（是否允许接入）、权限控制（可以访问哪些功能）、传输加密、请求路由、流量控制等功能。
        
        1. 服务发现
    
            节点的变化能被即使同步到所有其他依赖的微服务。这就是服务的自动注册和发现。服务发现主要由自理式和代理式两种。
            
            自理式结构就是指每个微服务自己完成服务发现。
            
            代理式结构是指微服务之间有一个负载均衡系统，由负载均衡系统来完成微服务之间的服务发现。代理式的方式更清晰，微服务本身的实现也简单许多，但这个方案风险较大，第一是可用性风险，第二是性能奉献，因此LOAD BALANCER系统需要设计成集群的模式，但LOAD BALANCER集群的实现本身又增加了复杂性。
            
            不管是自理式还是代理式，服务发现的核心功能就是服务注册表，注册表记录了所有的服务节点的配置和状态，每个微服务启动后都需要将自己的信息注册到服务注册表，然后由微服务或LOAD BALANCER系统到服务注册表查询可用服务。
        
        1. 服务路由

            服务路由和服务发现紧密相关，服务路由一般不会设计成一个独立运行的系统，通常情况下是和服务发现放在一起实现的。对于自理式服务发现，服务路由是微服务内部实现的；对于代理式服务发现，服务路由是由LOAD BALANCER系统实现的。常见的路由算法有：随机路由、轮询路由、最小压力路由、最小连接数路由等算法。
        
        1. 服务容错

            需要微服务能够自动应对出错常见，及时进行处理。否则如果节点一鼓掌就需要人工处理，投入人力大，处理速度慢。而一旦处理速度慢，则故障就很快扩散。常见的服务容错包括请求充实、流控和服务隔离。
            
            流控：通常情况下，流控由各个微服务节点自己实现，可以将流控策略包装成公共库提供给各个微服务使用，减少重复实现。
            
            服务隔离：当某个微服务节点故障时，最快最简单的处理方式就是直接将当前故障节点下线隔离，避免故障进行扩散。通常情况下，服务隔离分为主动隔离、被动隔离和手动隔离。
        
        1. 服务监控

            服务监控主要是有实时搜集信息并进行分析，避免故障后再来分析，减少了处理时间。服务监控可以在实时分析的基础上进行预警，在问题萌芽的阶段发觉并预警，降低了问题影响的范围和时间。
        
        1. 服务跟踪

            即跟踪某一个请求在微服务中的完整路径。服务跟踪的关键技术有标注点、跟总数和span。
            
            服务跟踪一般主要用于采样跟踪和染色跟踪。
                
        1. 服务安全

            部分敏感数据或操作只能部分微服务可以访问，而不是所有的微服务都可以访问。因此需要设计服务安全机制来保证业务和数据的安全性。服务安全主要分为接入安全、数据安全、传输安全等部分。
            
            服务安全可以集成到配置中心系统中进行实现，即配置中心配置微服务的接入安全策略和数据安全策略，微服务节点从配置中心获取这些配置信息，然后在处理具体的微服务调用请求时根据安全策略进行处理。由于这些策略是通用的，一般会把策略封装成通用的库提供给各个微服务调用。

## 第十五章 微内核架构

1. Microkernel Architecture，中文翻译为“微内核架构”，也被称为插件化架构(Plug-in Architecture)，是一种面向功能进行拆分的可扩展性架构，通常用于实现基于产品（英文原文为product-based，指存在多个版本、需要下载安装才能使用，与web-based相对应）的应用。

    **微内核架构包含两类组件：核心系统(core system)和插件模块(plug-in modules)。**核心系统功能比较稳定，不会因为业务功能扩展而不断修改，插件模块可以根据业务功能的需要不断地扩展。微内核架构通过隔离变化到插件的方式提供了灵活性、可扩展性。

1. 微内核核心系统设计关键技术：
    1. 插件管理：核心系统需要知道当前有哪些插件可用，如何加载这些插件，什么时候加载插件。常见的实现方法是插件注册表机制。
    2. 插件连接：插件如何连接到核心系统。常见的连接机制有OSGi(Eclipse)、消息模式、依赖注入(Spring)、甚至使用分布式的协议都是可以的，比如RPC或HTTP Web的方式。
    3. 插件通信：指插件间的通信。由于插件之间没有直接联系，通信必须通过核心系统，因此核心系统需要提供插件通信机制。

2. OSGi架构
    1. 全称Open Services Gateway Initiative，本身其实是指OSGi Alliance。现在我们讨论OSGi，已经和嵌入式应用关联不大了，更多的是将OSGi当做一个微内核的架构模式。
    2. Eclipse采用的是OSGi框架称为Equinox，类似的实现还有Apache的Felix，Spring的Spring DM。
    3. 模块层(Module)：完成插件管理功能。
    4. 生命周期层(Lifecycle)：完成插件连接功能，提供了执行时模块管理、模块对底层OSGi框架的访问。
    5. 服务层(Service)：完成插件通信的功能。

3. 规则引擎架构
    1. 规则引擎从结构上来看也属于微内核架构的一种具体体现，其中执行引擎可以看做微内核，执行引擎解析配置好的业务流，执行其中的条件和规则，通过这种方式来支持业务的灵活多变。规则引擎在计费、保险、促销等业务领域应用较多。
    2. 规则引擎能够很灵活的应对促销方案规则组织组合之类的需求，主要是其可扩展、易理解、高效率。
    3. 目前最常用的规则引擎是开源的JBoss Drools，采用java编写，基于Rete算法。Drools具有以下优点：
        1. 非常活跃的社区支持以及广泛的应用；
        2. 快速的执行速度；
        3. 与Java Rule Engine API(JSR-94)兼容；
        4. 提供基于Web的BRMS——Guvnor。

## 其他相关摘要

1. OSGi中，插件被称为Bundle。
