Appearance
系统架构的演变
随着互联网的发展,网站应用的规模不断扩大,常规的应用架构已无法应对,分布式服务架构以及微服务架构势在必行,亟需一个治理系统确保架构有条不紊的演进。
单体应用架构
Web 应用程序发展的早期,大部分 web 工程(包含前端页面,web 层代码,service 层代码,dao 层代码)是将所有的功能模块,打包到一起并部署到一个 web 容器中运行,这种系统就叫做单体架构。

比如搭建一个电商系统:客户下订单,商品展示,用户管理。

面对业务发展与用户量增加带来的高并发访问,可以将单体应用进行集群部署,并增加负载均衡服务器(如 Nginx 等)。另外,还需要增加集群部署的缓存服务器和文件服务器,并将数据库读写分离。
用负载均衡服务器分发高并发的网络请求,用户的访问被分派到不同的应用服务器,用户量增加时,添加应用服务器即可。通过添加缓存服务器来缓解数据库的数据以及数据库读取数据的压力。大多数的读取操作是由缓存完成,但仍然有少数读操作是从数据库读取的,例如缓存失效、实时数据等。
当有大量读写操作时,可以将数据库进行读写分离,例如 MySQL 的主从热备份,通过相关配置可以将主数据库服务器的数据同步到从数据库服务器,实现数据库的读写分离,改善数据库的负载能力。
单体应用架构优点:
- 所有的功能集成在一个项目工程中
- 项目架构简单,前期开发成本低,周期短,小型项目的首选
单体应用架构缺点:
- 全部功能集成在一个工程中,对于大型项目不易开发、扩展及维护
- 系统性能扩展只能通过扩展集群结点,成本高、有瓶颈
- 技术栈受限
垂直应用架构
当访问量逐渐增大,单一应用增加机器带来的加速度越来越小,将应用拆成互不相干的几个应用,以提升效率

垂直应用架构优点:
- 项目架构简单,前期开发成本低,周期短,小型项目的首选
- 通过垂直拆分,原来的单体项目不至于无限扩大
- 不同的项目可采用不同的技术
垂直应用架构缺点:
- 全部功能集成在一个工程中,对于大型项目不易开发、扩展及维护
- 系统性能扩展只能通过扩展集群结点,成本高、有瓶颈
面向服务的架构(SOA)
SOA 全称为 Service-Oriented Architecture,即面向服务的架构。它可以根据需求通过网络对松散耦合的粗粒度应用组件(服务)进行分布式部署、组合和使用。一个服务通常以独立的形式存在于操作系统进程中。

站在功能的角度,把业务逻辑抽象成可复用、可组装的服务,通过服务的编排实现业务的快速再生,其主要目的是把原先固有的业务功能转变为通用的业务服务,实现业务逻辑的快速复用。
SOA 架构特点:分布式、可重用、扩展灵活、松耦合。当垂直应用越来越多,应用之间交互不可避免,将核心业务抽取出来,作为独立的服务,逐渐形成稳定的服务中心,使前端应用能更快速的响应多变的市场需求。

SOA 架构优点:
- 抽取公共的功能为服务,提高开发效率
- 对不同的服务进行集群化部署解决系统压力
- 基于ESB/DUBBO减少系统耦合
SOA 架构缺点:
- 抽取服务的粒度较大
- 服务提供方与调用方接口耦合度较高
微服务架构(Microservices)
微服务架构(Microservices Architecture),简单的说就是将单体应用进一步拆分,拆分成更小的服务,每个服务都是可以独立运行、独立开发、独立部署、独立维护的服务或者应用的聚合,从而满足业务快速变化及分布式多团队并行开发的需求。
例如:

更多内容详见『微服务架构』章节
SOA 与微服务的关系
- SOA( Service Oriented Architecture )“面向服务的架构”:是一种设计方法,其中包含多个服务,服务之间通过相互依赖最终提供一系列的功能。一个服务通常以独立的形式存在与操作系统进程中。各个服务之间通过网络调用。
- 微服务架构:其实和 SOA 架构类似,微服务是在 SOA 上做的升华,微服务架构强调的一个重点是“业务需要彻底的组件化和服务化”,原有的单个业务系统会拆分为多个可以独立开发、设计、运行的小应用。这些小应用之间通过服务完成交互和集成。

微服务渐进式替代过程
微服务与微前端原理和软件工程,面向对象设计中的原理同样相通,都是遵循单一职责(Single Responsibility)、关注分离(Separation of Concerns)、模块化(Modularity)与分而治之(Divide & Conquer)等基本的原则。


云原生架构(Cloud Native)
云原生是通过构建团队、文化和技术,利用自动化和架构来管理系统的复杂性和解放生产力。

云原生应用架构的几个主要特征:符合 12 Factors 应用、面向微服务架构、自服务敏捷架构、基于 API 的协作以及抗脆弱性。2015 年 Google 主导成立了云原生计算基金会(CNCF),起初对云原生(Cloud Native)的定义包含三个方面:应用容器化、面向微服务架构、应用支持容器的编排调度。
云原生应用程序简单地定义为从头开始为云计算架构而构建应用程序;这意味着,如果将应用程序设计为预期将部署在分布式、可扩展的基础架构上,那么应用程序就是云原生的。随着公共云将承载越来越多的算力,未来云计算将是主流的 IT 能力交付方式,CNCF 也对云原生进行了重新定义:云原生的代表技术包括容器、服务网格、微服务、不可变基础设施和声明式 API。
- Codeless 对应的是服务开发,实现了源代码托管,只需要关注代码实现,而不需要关心代码在哪,因为在整个开发过程中都不会感受到代码库和代码分支的存在。
- Applicationless 对应的是服务发布,在服务化框架下,服务发布不再需要申请应用,也不需要关注应用部署的地方。
- Serverless 对应的则是服务运维,有了 Serverless 化能力,不再需要关注机器资源,Servlerless 会搞定机器资源的弹性扩缩容 这些技术组合搭配,能够构建容错性好、易于管理和便于观察的松耦合系统;再结合可靠的自动化手段,云原生技术能够使工程师轻松地对系统作出频繁和可预测的重大变更。由此可见,云原生是保障系统能力灵动性地有效抓手;云原生技术有利于各组织在公有云、私有云和混合云等新型动态环境中,构建和运行可弹性扩展的应用。微服务架构非常适合云原生应用程序;但是,云原生同样存在着一定的限制,如果云原生应用程序部署在 AWS 等公有云上,则云原生 API 不是跨云平台的。

云原生应用的关键属性包括了:使用轻量级的容器打包、使用最合适的语言和框架开发、以松耦合的微服务方式设计、以 API 为中心的交互和协作、无状态和有状态服务在架构上界限清晰、不依赖于底层操作系统和服务器、部署在自服务、弹性的云基础设施上、通过敏捷的 DevOps 流程管理、自动化能力、通过定义和策略驱动的资源分配。云原生是分布式应用当下重要的发展路径,其终态应当是 Distributionless,所有与分布式相关的问题由云平台解,分布式应用的开发会跟传统应用的开发一样方便,甚至更加便捷。
架构基础理论
架构的模式
网站架构模式即为了解决大型网站面临的高并发访问、海量数据、高可靠运行等一系列问题与挑战。在实践中提出了许多解决方案,以实现网站高性能、高可靠性、易伸缩、可扩展、安全等各种技术架构目标。
分层
分层是企业应用系统中最常见的一种架构模式,将系统在横向维度上切分成几个部分,每个部分负责一部分相对简单并比较单一的职责,然后通过上层对下层的依赖和调度组成一个完整的系统。常见的网站分层架构为3层:应用层、服务层、数据层。
- 应用层具体负责业务和视图的展示。
- 服务层为应用层提供服务支持。
- 数据库提供数据存储访问服务,如数据库、缓存、文件、搜索引擎等。
分层架构是逻辑上的,在物理部署上,三层架构可以部署在同一个物理机器上,但是随着网站业务的发展,必然需要对已经分层的模块分离部署,即三层结构分别部署在不同的服务器上,使网站拥有更多的计算资源以应对越来越多的用户访问。
虽然分层架构模式最初的目的是规划软件清晰的逻辑结构以便于开发维护,但在网站的发展过程中,分层结构对网站支持高并发向分布式方向的发展至关重要。
分隔
对于大型网站,分层和分隔的一个主要目的是为了切分后的模块便于分布式部署,即将不同模块部署在不同的服务器上,通过远程调用协同工作。分布式意味着可以使用更多的计算机完同样的工作,计算机越多,CPU、内存、存储资源就越多,能过处理的并发访问和数据量就越大,进而能够为更多的用户提供服务。常用的网站应用分布式方案有以下几种:
- 分布式应用和服务:将分层和分隔后的应用和服务模块分布式部署,可以改善网站性能和并发性、加快开发和发布速度、减少数据库连接资源消耗。
- 分布式静态资源:网站的静态资源如 JS、CSS、Logo 图片等资源对立分布式部署,并采用独立的域名,即常说的动静分离。静态资源分布式部署可以减轻应用服务器的负载压力;通过使用独立域名加快浏览器并发加载的速度。
- 分布式数据和存储:大型网站需要处理以 P 为单位的海量数据,单台计算机无法提供如此大的存储空间,这些数据库需要分布式存储。
- 分布式计算:目前网站普遍使用 Hadoop 和 MapReduce 分布式计算框架进行此类批处理计算,其特点是移动计算而不是移动数据,将计算程序分发到数据所在的位置以加速计算和分布式计算。
集群
对于用户访问集中的模块需要将独立部署的服务器集群化。即多台服务器部署相同的应用构成一个集群,通过负载均衡设备共同对外提供服务。
服务器集群能够为相同的服务提供更多的并发支持,因此当有更多的用户访问时,只需要向集群中加入新的机器即可;另外可以实现当其中的某台服务器发生故障时,可以通过负载均衡的失效转移机制将请求转移至集群中其他的服务器上,因此可以提高系统的可用性。
缓存
缓存目的就是减轻服务器的计算,使数据直接返回给用户。在软件设计中,具体实现有 CDN、反向代理、本地缓存、分布式缓存等。使用缓存有两个条件:
- 访问数据热点不均衡,即某些频繁访问的数据需要放在缓存中。
- 数据在某个时间段内有效,不过很快过期,否则会因为数据过期而脏读,影响数据的正确性。
异步
业务之间的消息传递不是同步调用,而是使用异步,将一个业务操作分成多个阶段,每个阶段之间通过共享数据的方法异步执行进行协作。
具体实现则在单一服务器内部可用通过多线程共享内存对了的方式处理;在分布式系统中可用通过分布式消息队列来实现异步。
异步架构的典型就是生产者消费者方式,两者不存在直接调用。
冗余
网站需要 7×24 小时连续运行,就会有相应的冗余机制,以防某台机器宕掉时无法访问,而冗余则可以通过部署至少两台服务器构成一个集群实现服务高可用。数据库除了定期备份还需要实现冷热备份。甚至可以在全球范围内部署灾备数据中心。
自动化
具体有自动化发布过程,自动化代码管理、自动化测试、自动化安全检测、自动化部署、自动化监控、自动化报警、自动化失效转移、自动化失效恢复等。
安全
网站在安全架构方面有许多模式:通过密码和手机校验码进行身份认证;登录、交易需要对网络通信进行加密;为了防止机器人程序滥用资源,需要使用验证码进行识别;对常见的 XSS 攻击、SQL 注入需要编码转换;垃圾信息需要过滤等。
敏捷性
积极接受需求变更,快速响应业务发展需求。
架构的核心要素
软件架构即“有关软件整体结构与组件的抽象描述,用于指导大型软件系统各方面的设计”。一般来说软件架构需要关注性能、可用性、伸缩性、扩展性和安全性这 5 个架构要素。
性能
性能是网站架构设计的一个重要方面,任何软件架构设计方案都必须考虑可能带来的性能问题。衡量网站性能有一系列重要指标,如:响应时间、TPS、系统性能计数器等,通过这些指标以确定系统设计是否达到目标。
通常优化网站性能的手段有:
- 浏览器端:可以通过浏览器缓存、页面压缩传输、合理布局页面、减少 Cookie 传输等手段,甚至可以使用 CDN 加速功能。
- 应用服务器端:可以使用服务器本地缓存和分布式缓存,也可以通过异步操作方式来加快响应,在高并发请求的情况下,可以将多台应用服务器组成一个集群共同对外服务,提高整体处理能力,改善性能。
- 数据库服务器端:可用使用索引、缓存、SQL 性能优化等手段,还可以使用 NoSQL 数据库来优化数据模型、存储结构等。
可用性
可用性即能够不间断提供服务的时间。几乎所有网站都承诺7×24小时可用,但事实上任何网站都不可能达到完全的7×24,总会有一些故障时间,扣除这些故障时间,就是网站的可用时间。一些大型网站可以做到4个9以上的可用性,也就是99.99%。
网站高可用的主要手段就是冗余,应用部署在多台服务器上同时提供服务,数据存储在多台服务器上相互备份,任何一台服务器都不会影响应用的整体可以,通常的实现手段即把多台服务器通过负载均衡设备组成一个集群。
衡量一个系统架构设计是否满足高可用的目标,就是假设系统中任何一台或者多台服务器宕机时,以及出现各种不可预期的问题时,系统整体是否依然可用。
伸缩性
大型网站需要面对大量用户的高并发访问和存储海量数据,网站通过集群的方式将多台服务器组成一个整体共同提供服务。所谓伸缩性是指通过不断向集群中加入服务器数量的手段,来缓解不断整体上升的用户并发访问压力和不断增长的数据存储需求。
衡量架构伸缩性的主要标准是:是否可用多台服务器构建集群,是否容易向集群中添加新的服务器。加入新的服务器后是否可以提供和原来的服务器无差别的服务。集群中可容纳的总服务器数量是否有限制。
扩展性
不同于其他架构要素主要关注非功能性需求,网站的扩展性架构直接关注网站的功能需求。网站快速发展,功能不断扩展,如何设计网站的架构使其能够快速响应需求变化,是网站可扩展架构的主要目标。
衡量网站架构扩展性好坏的主要标准是,在网站增加新的业务产品时,是否可以实现对现有产品透明无影响,不同产品之间是否很少耦合等。网站可扩展架构的主要手段是事件驱动架构和分布式服务。
- 事件驱动通常利用消息队列实现,通过这种方式将消息生产和处理逻辑分隔开。
- 分布式服务则是将业务和可复用服务分离开来,通过分布式服务框架调用。新增加产品可用通过调用可复用的服务来实现自身的业务逻辑,而对现有产品没有任何影响。
安全性
网站的安全架构就是保护网站不受恶意访问和攻击,保护网站的重要数据不被窃取。
衡量网站安全架构的标准是,针对现存和潜在的各种攻击和窃密手段,是否有可靠的应对策略。
分布式系统概述
分布式系统是一个硬件或软件组件分布在不同的网络计算机上,彼此之间仅仅通过消息传递进行通信和协调的系统。简单来说就是一群独立计算机集合共同对外提供服务,但是对于系统的用户来说,就像是一台计算机在提供服务一样。分布式意味着可以采用更多的普通计算机(相对于昂贵的大型机)组成分布式集群对外提供服务。计算机越多,CPU、内存、存储资源等也就越多,能够处理的并发访问量也就越大。
从分布式系统的概念中可知,各个主机之间通信和协调主要通过网络进行,所以分布式系统中的计算机在空间上几乎没有任何限制,这些计算机可能被放在不同的机柜上,也可能被部署在不同的机房中,还可能在不同的城市中,对于大型的网站甚至可能分布在不同的国家和地区。
分布式系统的主要特征
一个标准的分布式系统应该具有以下几个主要特征:
- 分布性:分布式系统中的多台计算机之间在空间位置上可以随意分布,同时,机器的分布情况也会随时变动。
- 对等性:分布式系统中的计算机没有主/从之分,即没有控制整个系统的主机,也没有被控制的从机,组成分布式系统的所有计算机节点都是对等的。副本(Replica)是分布式系统最常见的概念之一,指的是分布式系统对数据和服务提供的一种冗余方式。在常见的分布式系统中,为了对外提供高可用的服务,我们往往会对数据和服务进行副本处理。数据副本是指在不同节点上持久化同一份数据,当某一个节点上存储的数据丢失时,可以从副本上读取该数据,这是解决分布式系统数据丢失问题最为有效的手段。另一类副本是服务副本,指多个节点提供同样的服务,每个节点都有能力接收来自外部的请求并进行相应的处理。
- 自治性:分布式系统中的各个节点都包含自己的处理机和内存,各自具有独立的处理数据的功能。通常,彼此在地位上是平等的,无主次之分,既能自治地进行工作,又能利用共享的通信线路来传送信息,协调任务处理。
- 并发性:在一个计算机网络中,程序运行过程的并发性操作是非常常见的行为。例如同一个分布式系统中的多个节点,可能会并发地操作一些共享的资源,如何准确并高效地协调分布式并发操作也成为了分布式系统架构与设计中最大的挑战之一。
分布式系统面临的问题
- 缺乏全局时钟:在分布式系统中,很难定义两个事件究竟谁先谁后,原因就是因为分布式系统缺乏一个全局的时钟序列控制。
- 机器宕机:是最常见的异常之一。在大型集群中每日宕机发生的概率为千分之一左右,在实践中,一台宕机的机器恢复的时间通常认为是24 小时,一般需要人工介入重启机器。
- 网络异常:消息丢失,两片节点之间彼此完全无法通信,即出现了“网络分化”;消息乱序,有一定的概率不是按照发送时的顺序依次到达目的节点,考虑使用序列号等机制处理网络消息的乱序问题,使得无效的、过期的网络消息不影响系统的正确性;数据错误;不可靠的TCP,TCP 协议为应用层提供了可靠的、面向连接的传输服务,但在分布式系统的协议设计中不能认为所有网络通信都基于TCP 协议则通信就是可靠的。TCP协议只能保证同一个TCP 链接内的网络消息不乱序,TCP 链接之间的网络消息顺序则无法保证。
- 分布式三态:如果某个节点向另一个节点发起RPC(Remote procedure call)调用,即某个节点A 向另一个节点B 发送一个消息,节点B 根据收到的消息内容完成某些操作,并将操作的结果通过另一个消息返回给节点A,那么这个RPC 执行的结果有三种状态:“成功”、“失败”、“超时(未知)”,称之为分布式系统的三态。
- 存储数据丢失:对于有状态节点来说,数据丢失意味着状态丢失,通常只能从其他节点读取、恢复存储的状态。
被大量工程实践所检验过的异常处理黄金原则是,任何在设计阶段考虑到的异常情况一定会在系统实际运行中发生,但在系统实际运行遇到的异常却很有可能在设计时未能考虑,所以,除非需求指标允许,在系统设计时不能放过任何异常情况。
衡量分布式系统的指标
- 性能:系统的吞吐能力,指系统在某一时间可以处理的数据总量,通常可以用系统每秒处理的总的数据量来衡量;系统的响应延迟,指系统完成某一功能需要使用的时间;系统的并发能力,指系统可以同时完成某一功能的能力,通常也用 QPS(query per second)来衡量。上述三个性能指标往往会相互制约,追求高吞吐的系统,往往很难做到低延迟;系统平均响应时间较长时,也很难提高 QPS。
- 可用性(availability):指系统在面对各种异常时可以正确提供服务的能力。系统的可用性可以用系统停服务的时间与正常服务的时间的比例来衡量,也可以用某功能的失败次数与成功次数的比例来衡量。可用性是分布式的重要指标,衡量了系统的鲁棒性,是系统容错能力的体现。
- 可扩展性(scalability):指分布式系统通过扩展集群机器规模提高系统性能(吞吐、延迟、并发)、存储容量、计算能力的特性。好的分布式系统总在追求“线性扩展性”,也就是使得系统的某一指标可以随着集群中的机器数量线性增长。
- 一致性:分布式系统为了提高可用性,总是不可避免的使用副本的机制,从而引发副本一致性的问题。越是强的一致的性模型,对于用户使用来说使用起来越简单。
分布式系统基础理论
CAP 理论
CAP 是 Consistency(一致性)、Availiability(可用性)、Partition tolerance(分区容错性) 三个词语的缩写。CAP 理论告诉我们 C、A、P 三者不能同时满足,最多只能满足其中两个
[图片已失效:210753710255944.png]
业务场景
结合电商系统中的一些业务场景来理解 CAP 理论。业务背景:
- 每台数据库服务器有它的最大连接数、负载和吞吐量,若有一天无法再满足业务的需求,就需要横向去扩展几台 Slave(从数据库) 去分担 Master(主数据库) 的压力。
- 如果服务对数据库的需求是 IO 密集型的,那可能会经常遇到增删改影响到了查询效率。这就需要进行读写分离,由主数据库应付增删改操作,由从数据库应付查询操作,主从数据库的数据要进行同步。
[图片已失效:83162423244687.png]
上图商品信息管理的执行流程:
- 商品服务请求主数据库写入商品信息(添加商品、修改商品、删除商品)
- 主数据库向商品服务响应写入成功。
- 商品服务请求从数据库读取商品信息。
C - Consistency
一致性是指写操作后的读操作可以读取到最新的数据状态,当数据分布在多个节点上,从任意节点读取到的数据都是最新的状态。上图中,商品信息的读写要满足一致性就是要实现如下目标:
- 商品服务写入主数据库成功,则向从数据库查询新数据也成功。
- 商品服务写入主数据库失败,则向从数据库查询新数据也失败。
如何实现一致性?
- 写入主数据库后要将数据同步到从数据库。
- 写入主数据库后,在向从数据库同步期间要将从数据库锁定,待同步完成后再释放锁,以免在新数据写入成功后,向从数据库查询到旧的数据。
分布式系统一致性的特点:
- 由于存在数据同步的过程,写操作的响应会有一定的延迟。
- 为了保证数据一致性会对资源暂时锁定,待数据同步完成释放锁定资源。
- 如果请求数据同步失败的结点则会返回错误信息,一定不会返回旧数据。
A - Availability
可用性是指任何事务操作都可以得到响应结果,且不会出现响应超时或响应错误。上图中,商品信息读取满足可用性就是要实现如下目标:
- 从数据库接收到数据查询的请求则立即能够响应数据查询结果。
- 从数据库不允许出现响应超时或响应错误。
如何实现可用性?
- 写入主数据库后要将数据同步到从数据库。
- 由于要保证从数据库的可用性,不可将从数据库中的资源进行锁定。
- 即时数据还没有同步过来,从数据库也要返回要查询的数据,哪怕是旧数据,如果连旧数据也没有则可以按照约定返回一个默认信息,但不能返回错误或响应超时。
为了保证可用性,一般需要通过增加从数据库节点来实现。
分布式系统可用性的特点:
- 所有请求都有响应,且不会出现响应超时或响应错误。
P - Partition tolerance
通常分布式系统的各个节点部署在不同的子网,这就是网络分区,不可避免的会出现由于网络故障而导致节点之间通信失败。分布式系统在遇到某节点或网络分区故障的时候,仍然能够对外提供满足一致性和可用性的服务,这就是分区容忍性。分布式系统中有某一个或者几个机器宕掉了,其他剩下的机器还能够正常运转满足系统需求,或者是机器之间有网络异常,将分布式系统分隔未独立的几个部分,各个部分还能维持分布式系统的运作,这样就具有较好的分区容忍性。上图中,商品信息读写满足分区容忍性就是要实现如下目标:
- 主数据库向从数据库同步数据失败不影响读写操作。
- 其中一个节点挂掉不影响另一个节点对外提供服务。
如何实现分区容忍性?
- 尽量使用异步取代同步操作,例如使用异步方式将数据从主数据库同步到从数据,这样结点之间能有效的实现松耦合。
- 添加从数据库结点,其中一个从结点挂掉其它从结点提供服务。
分布式分区容忍性的特点:
- 分区容忍性分是布式系统具备的基本能力。
CAP 共存分析
[图片已失效:83162423244687.png]
以上面章节的“商品信息管理”为例,实现了分区容忍:
- 主数据库通过网络向从数据同步数据,可以认为主从数据库部署在不同的分区,通过网络进行交互。
- 当主数据库和从数据库之间的网络出现问题不影响主数据库和从数据库对外提供服务。
- 其一个结点挂掉不影响另一个结点对外提供服务。
如果要实现C则必须保证数据一致性,在数据同步的时候为防止向从数据库查询不一致的数据则需要将从数据库数据锁定,待同步完成后解锁,如果同步失败从数据库要返回错误信息或超时信息;如果要实现A则必须保证数据可用性,不管任何时候都可以向从数据查询数据,则不会响应超时或返回错误信息。
通过分析发现,在所有分布式事务场景中是不会同时具备 CAP 三个特性,因为在具备了 P 的前提下 C 和 A 是不能共存的
CAP 组合方式
在保证分区容忍性的前提下,一致性和可用性是无法兼顾,如果要提高系统的可用性就要增加多个节点,如果要保证数据的一致性就要实现每个节点的数据一致,节点越多可用性越好,但是数据一致性会越差。 CAP 的组合方式有如下几种:
- AP:放弃一致性,追求分区容忍性和可用性。这是很多分布式系统设计时的选择。
例如:上边的商品管理,完全可以实现AP,前提是只要用户可以接受所查询的到数据在一定时间内不是最新的即可。通常实现AP都会保证最终一致性,后面的 BASE 理论就是根据 AP 组合来扩展的,一些业务场景,比如,订单退款,今日退款成功,明日账户到账,只要用户可以接受在一定时间内到账即可。
- CP:放弃可用性,追求一致性和分区容错性。比如,zookeeper 其实就是追求的强一致;又比如跨行转账,一次转账请求要等待双方银行系统都完成整个事务才算完成。
- CA:放弃分区容忍性,即不进行分区,不考虑由于网络不通或节点挂掉的问题,则可以实现一致性和可用性。那么系统将不是一个标准的分布式系统,最常用的关系型数据库就满足了 CA 组合。
以上面商品管理为例,如果要实现 CA 则架构如下:
[图片已失效:510625810239393.png]
不再存在主从数据,单个数据库可以响应每次的查询请求,通过事务隔离级别实现每个查询请求都可以返回最新的数据。
总结
CAP 是一个已经被证实的理论:一个分布式系统最多只能同时满足一致性(Consistency)、可用性(Availability)和分区容忍性(Partition tolerance)这三项中的两项。它可以作为架构设计、技术选型的考量标准。对于多数大型互联网应用的场景,节点众多、部署分散,而且现在的集群规模越来越大,所以节点故障、网络故障是常态,而且要保证服务可用性达到 N个9(99.99..%),并要达到良好的响应性能来提高用户体验,因此一般都会做出如下选择:保证分区容忍性(P)和高可用性(A),舍弃强一致性(C),保证最终一致性。
BASE 理论
理解强一致性和最终一致性
从 CAP 理论可知,一个分布式系统最多只能同时满足一致性(Consistency)、可用性(Availability)和分区容忍性(Partition tolerance)这三项中的两项,其中 AP 在实际应用中较多,AP 即舍弃一致性,保证可用性和分区容忍性。
但是在实际生产中很多场景都要实现一致性,比如上面的例子,主数据库向从数据库同步数据,即使不要一致性,但是最终也要将数据同步成功来保证数据一致,这种一致性和 CAP 中的一致性不同,CAP 中的一致性要求在任何时间查询每个节点数据都必须一致,它强调的是强一致性,但是最终一致性是允许可以在一段时间内每个节点的数据不一致,但是经过一段时间每个节点的数据必须一致,它强调的是最终数据的一致性。
Base 理论简介
BASE 是 Basically Available(基本可用)、Soft state(软状态)和 Eventually consistent (最终一致性)三个短语的缩写。BASE 理论是对 CAP 中 AP 的一个扩展,通过牺牲强一致性来获得可用性,当出现故障允许部分不可用但要保证核心功能可用,允许数据在一段时间内是不一致的,但最终达到一致状态。满足 BASE 理论的事务,称之为『柔性事务』。
- 基本可用 (Basically Available) : 分布式系统在出现故障时,允许损失部分可用功能,保证核心功能可用。比如,电商网站交易付款出现问题了,商品依然可以正常浏览。
- 软状态 (Soft state) : 由于不要求强一致性,所以 BASE 允许系统中存在中间状态(也叫软状态),这个状态不影响系统可用性,如订单的"支付中"、“数据同步中”等状态,待数据最终一致后状态改为“成功”状态。
- 最终一致 (Eventually consistent) : 最终一致是指经过一段时间后,所有节点数据都将会达到一致。如订单的"支付中"状态,最终会变为“支付成功”或者"支付失败",使订单状态与实际交易结果达成一致,但需要一定时间的延迟、等待。
分布式一致性算法
一致性算法的目的是保证在分布式系统中,多数据副本节点数据一致性。主要包含一致性 Hash 算法,Paxos 算法,Raft 算法,ZAB 算法等。
一致性 Hash 算法
一致性Hash算法是个经典算法,Hash环的引入是为解决单调性(Monotonicity)的问题;虚拟节点的引入是为了解决平衡性(Balance)问题
Paxos 算法
Paxos 算法是 Lamport 宗师提出的一种基于消息传递的分布式一致性算法,使其获得 2013 年图灵奖。自 Paxos 问世以来就持续垄断了分布式一致性算法,Paxos 这个名词几乎等同于分布式一致性,很多分布式一致性算法都由 Paxos 演变而来。
Raft 算法
Raft 为了探索一种更易于理解的一致性算法而产生的。它的首要设计目的就是易于理解,所以在选主的冲突处理等方式上它都选择了非常简单明了的解决方案。
ZAB 算法
ZAB 协议全称:Zookeeper Atomic Broadcast(Zookeeper 原子广播协议),是为 Zookeeper 设计的分布式一致性协议,它应该是所有一致性协议中生产环境中应用最多的了。
微服务架构
微服务概念
以下是节选 spring 官网关于微服务介绍
Microservices
Microservice architectures are the ‘new normal’. Building small, self-contained, ready to run applications can bring great flexibility and added resilience to your code. Spring Boot’s many purpose-built features make it easy to build and run your microservices in production at scale. And don’t forget, no microservice architecture is complete without Spring Cloud ‒ easing administration and boosting your fault-tolerance.
翻译:微服务架构是一种 "新常态"。构建小型的、独立的、可随时运行的应用程序可以为您的代码带来极大的灵活性,并增加弹性。Spring Boot 的许多专用功能使其能够轻松地在生产中大规模地构建和运行你的微服务。别忘了,没有 Spring Cloud 的微服务架构是不完整的 -- 它可以减轻管理,提高容错能力。
微服务架构是一种架构模式、风格,它提倡将单一应用程序划分为一组小的服务,每个服务运行在其自己独立的进程中。服务之间采用轻量级的通信机制互相协调、配合(通常是基于 HTTP 的 RESTful API),每个服务都围绕着具体的业务进行构建,并且能够被独立的构建在生产环境、类生产环境等。
另外,应避免统一的、集中式的服务管理机制,可以有一个非常轻量级的集中式管理来协调这些服务。对具体的一个服务而言,应根据业务上下文,选择合适的语言、工具对其进行构建,各个微服务可以使用不同的语言来编写,也可以使用不同的数据存储。
微服务架构基础组件

- 客户端 – 来自不同设备的不同用户发送请求。
- 身份提供商 – 验证用户或客户身份并颁发安全令牌。
- API 网关 – 处理客户端请求。
- 静态内容 – 容纳系统的所有内容。
- 管理 – 在节点上平衡服务并识别故障。
- 服务发现 – 查找微服务之间通信路径的指南。
- 内容交付网络 – 代理服务器及其数据中心的分布式网络。
- 远程服务 – 启用驻留在 IT 设备网络上的远程访问信息。
常见微服务框架
Spring Cloud
Spring Cloud 是一系列框架的有序集合。它利用 Spring Boot 的开发便利性巧妙地简化了分布式系统基础设施的开发,如服务发现注册、配置中心、消息总线、负载均衡、断路器、数据监控等,都可以用 Spring Boot 的开发风格做到一键启动和部署。
Spring Cloud 并没有重复制造轮子,它只是将目前各家公司开发的比较成熟、经得起实际考验的服务框架组合起来,通过 Spring Boot 风格进行再封装屏蔽掉了复杂的配置和实现原理,最终给开发者留出了一套简单易懂、易部署和易维护的分布式系统开发工具包
官网:https://spring.io/projects/spring-cloud
Apache ServiceComb
Apache ServiceComb,前身是华为云的微服务引擎 CSE (Cloud Service Engine) 云服务,是业界第一个Apache微服务顶级项目,它提供了一站式的微服务开源解决方案,致力于帮助企业、用户和开发者将企业应用轻松微服务化上云,并实现对微服务应用的高效运维管理。其融合SDK框架级、零侵入ServiceMesh场景并支持多语言
官网:http://servicecomb.apache.org/cn/
ZeroC ICE
ZeroC IceGrid 是ZeroC公司的杰作,继承了CORBA的血统,是新一代的面向对象的分布式系统中间件。作为一种微服务架构,它基于RPC框架发展而来,具有良好的性能与分布式能力
官网:https://zeroc.com/products/ice
Spring Cloud Alibaba
Spring Cloud Alibaba 致力于提供微服务开发的一站式解决方案。此项目包含开发分布式应用微服务的必需组件,方便开发者通过 Spring Cloud 编程模型轻松使用这些组件来开发分布式应用服务。
官网:https://spring.io/projects/spring-cloud-alibaba#overview
微服务特点
- 解耦 – 系统内的服务很大程度上是分离的,按业务划分成一个独立运行的程序,即服务单元。因此,整个应用程序可以轻松构建,更改和扩展
- 微服务是一个分布式系统,具有极强的横向扩展能力,微服务可以集群化部署、集中化管理
- 组件化 – 微服务被视为可以轻松更换和升级的独立组件
- 业务能力 – 微服务非常简单,专注于单一功能
- 自治 – 开发人员和团队可以彼此独立工作,从而提高速度
- 持续交付 – 通过软件创建,测试和标准的系统自动化部署,允许频繁发布软件
- 责任 – 微服务不关注应用程序作为项目。相反,他们将应用程序视为他们负责的产品
- 分散治理 – 重点是使用正确的工具来做正确的工作。这意味着没有标准化模式或任何技术模式。开发人员可以自由选择不同的编程语言、最有用的工具来解决他们的问题
- 敏捷 – 微服务支持敏捷开发。任何新功能都可以快速开发并再次丢弃
- 数据存储 - 各个微服务可以使用不同的存储技术
- 服务之间通过 HTTP 协议相互通信
微服务通过 HTTP 相互通信
微服务架构中所有服务应该能够彼此交互以构建业务功能。因此,要实现这一点,每个微服务必须具有接口。这使得 Web API 成为微服务的一个非常重要的推动者。RESTful API 基于 Web 的开放网络原则,为构建微服务架构的各个组件之间的接口提供了最合理的模型。
- 微服务单元之间的通信一般使用 HTTP 的通信机制,更多的时候使用 RESTFUL api 的,可以跨平台与语言
- 服务与服务之间也可以通过轻量级的消息总线来通信,如 RabbitMQ,Kafaka 等
- 服务与服务之间的通信格式一般为 json、xml。这两种数据格式与平台、语言、通信协议无关
微服务的数据库独立
微服务都有自己独立的数据库,数据库之间没有任何联系。数据库的存储方式可以是关系型数据库,也可以是非关系数据库(如:MongoDB、Redis)
微服务的自动化部署
微服务架构有多少服务就需要部署多少次,所以微服务部署的核心是 Docker 容器技术,是微服务最佳部署的容器,需要使用 Docker 容器技术以及自动化部署工具(如:开源组件 Jenkins)。DevOps 是一种部署手段或理念。
微服务架构的常见问题
微服务的复杂度
服务与服务之间相互依赖,如果修改某个服务,会对另一个服务产生影响。比如修改一个比较基础的服务,可能需要重启所有的服务才能完成测试
分布式事务

分布式事务提交需要两个阶段
- 第1个阶段:Service-account发起一个分布式事务,交给事务协调器TC处理,事务协调器TC向所有参与的事务的节点发送处理事务操作的准备操作,将Undo和Redo信息写进日志,并向事务管理器返回准备操作是否成功。
- 第2个阶段:事务管理器收集的呢节点的准备操作是否成功,如果都成功,则通知所有的节点执行提交操作;如果有一个失败,则执行回滚操作。但如果第1阶段都成功,而执行第2阶段的某一个节点失败,仍然导致数据的不准确。如果分布式事务涉及的节点很多,某个节点的网络出现异常会导致整个事务处于阻塞状态,大大降低数据库的性能。所以一般情况下,尽量少用分布式事务。
微服务的优缺点
优点:
- 独立开发 – 所有微服务都可以根据各自的功能轻松开发
- 独立部署 – 通过服务的原子化拆分,基于其服务,可以在任何应用程序中单独打包、部署和升级,小团队的交付周期将缩短,运维成本也将大幅度下降。
- 故障隔离 – 即使应用程序的一项服务不起作用,系统仍可继续运行
- 混合技术堆栈 – 各个微服务可以使用不同的语言和技术来构建同一应用程序的不同服务,面向接口编程。
- 粒度缩放 – 单个组件可根据需要进行缩放,无需将所有组件缩放在一起
- 易于第三方集成。
- 数据可以灵活搭配,可存储公共库或者独立库。
- 微服务遵循单一原则。微服务之间采用 Restful 等轻量协议传输。
- 松耦合,功能细化。
缺点:
- 微服务过多,服务治理成本高,不利于系统维护。
- 分布式系统开发的技术成本高(负载平衡、容错、分布式事务、数据一致性、系统集成测试、性能监控等)。
- 性能问题。复杂性导致系统开销增加,包括网络问题,延迟开销,带宽问题,安全问题。
- 分布式系统中的冗余问题。
- 部署复杂性,对 Devops 技能的要求高。
微服务测试
不同类型的微服务测试
在微服务构架中,由于有多个微服务协同工作,测试变得非常复杂。因此,测试分为不同的级别:
- 底层级别:面向技术的测试,如单元测试和性能测试。这些是完全自动化的。
- 中间层面级别:进行诸如压力测试和可用性测试之类的探索性测试。
- 顶层级别:验收测试,有助于利益相关者理解和验证软件功能。
端到端微服务测试
端到端测试验证了工作流中的每个流程都正常运行。这可确保系统作为一个整体协同工作并满足所有要求。通俗地说,端到端测试是一种在特定时期后测试所有东西。

测试中消除非确定性
非确定性测试(NDT)基本上是不可靠的测试。即有时可能会发生它们通过,但有时它们也可能会失败。当它们失败时,它们会重新运行通过。从测试中删除非确定性的一些方法如下:
- 隔离
- 异步
- 远程服务
- 隔离
- 时间
- 资源泄漏
Mike Cohn 的测试金字塔
Mike Cohn 提供了一个名为 Test Pyramid 的模型。这描述了软件开发所需的自动化测试类型。根据金字塔,第一层的测试数量应该最高。在服务层,测试次数应小于单元测试级别,但应大于端到端级别。

服务治理(注册中心)
服务治理就是进行服务的自动化管理,其核心是服务的自动化注册与发现。
注册中心相当于微服务架构中的“通讯录”,它记录了服务和服务地址的映射关系。在分布式架构中,服务会注册到这里,当服务需要调用其它服务时,就这里找到服务的地址,进行调用。

更多内容详见《分布式服务注册中心概述》笔记
服务调用
在微服务架构中,通常存在多个服务之间的远程调用的需求。远程调用通常包含两个部分:序列化和通信协议。常见的序列化协议包括json、xml、hession、protobuf、thrift、text、bytes等,目前主流的远程调用技术有基于 HTTP 的 RESTful 接口以及基于 TCP 的 RPC 协议。
- RPC (Remote Promote Call):一种进程间通信方式。允许像调用本地服务一样调用远程服务。RPC框架的主要目标就是让远程服 务调用更简单、透明。RPC框架负责屏蔽底层的传输方式、序列化方式和通信细节。开发人员在使 用的时候只需要了解谁在什么位置提供了什么样的远程服务接口即可,并不需要关心底层通信细节 和调用过程。
HTTP 的 RESTfull 接口
REST(Representational State Transfer),这是一种HTTP调用的格式,更标准,更通用,无论哪种语言都支持http协议。如果一个架构符合REST原则,就称它为RESTful架构。
- 资源(Resources):就是网络上的一个实体,或者说是网络上的一个具体信息。可以用一个URI(统一资源定位符)指向它,每种资源对应一个特定的URI。要获取这个资源,访问它的URI就可以
- 表现层(Representation):把"资源"具体呈现出来的形式。
- 状态转化(State Transfer):访问一个网站,就代表了客户端和服务器的一个互动过程。在这个过程中,势必涉及到数据和状态的变化。如果客户端想要操作服务器,必须通过某种手段,让服务器端发生"状态转化"(State Transfer)。客户端用到的手段就是HTTP协议里面,四个表示操作方式的动词:GET、POST、PUT、DELETE。它们分别对应四种基本操作:GET用来获取资源,POST用来新建资源(也可以用于更新资源),PUT用来更新资源,DELETE用来删除资源。
RESTful架构总结:
- 每一个URI代表一种资源
- 客户端和服务器之间,传递这种资源的某种表现层
- 客户端通过四个HTTP动词,对服务器端资源进行操作,实现"表现层状态转化"
RPC 协议
RPC(Remote Procedure Call )一种进程间通信方式。允许像调用本地服务一样调用远程服务。RPC 框架的主要目标就是让远程服务调用更简单、透明。RPC框架负责屏蔽底层的传输方式(TCP或者UDP)、序列化方式(XML/JSON/二进制)和通信细节。开发人员在使用的时候只需要了解谁在什么位置提供了什么样的远程服务接口即可,并不需要关心底层通信细节和调用过程。

RESTful 与 RPC 的区别

- HTTP 相对更规范,更标准,更通用,无论哪种语言都支持http协议。如果对外开放API,例如开放平台,外部的编程语言多种多样,需要对每种语言的支持,现在开源中间件,基本最先支持的几个协议都包含 RESTful
- RPC 框架作为架构微服务化的基础组件,它能大大降低架构微服务化的成本,提高调用方与服务提供方的研发效率,屏蔽跨进程调用函数(服务)的各类复杂细节。让调用方感觉就像调用本地函数一样调用远端函数、让服务提供方感觉就像实现一个本地函数一样来实现服务
服务网关(API Gateway)
随着微服务的不断增多,不同的微服务一般会有不同的网络地址,而外部客户端可能需要调用多个服务的接口才能完成一个业务需求,如果让客户端直接与各个微服务通信可能出现以下问题:
- 客户端会请求多个不同的服务,需要维护不同的请求地址,增加开发难度
- 在某些场景下存在跨域请求的问题
- 加大身份认证的难度,每个微服务需要独立的身份认证
此时需要一个微服务网关,介于客户端与服务器之间的中间层,所有的外部请求都会先经过微服务网关。客户端只需要与网关交互,只知道一个网关地址即可。增加服务网关的有以下优点:
- 易于监控
- 易于认证
- 减少了客户端与各个微服务之间的交互次数

服务网关的概念
微服务系统中,API接口资源通常是由服务网关(也称API网关)统一暴露,由网关层统一接入和输出。API Gateway 是一个服务器,也可以说是进入系统的唯一节点。
API网关封装了系统内部架构,为每个客户端提供一个定制的API。API网关方式的核心要点是,所有的客户端和消费端都通过统一的网关接入微服务,在网关层处理所有的非业务功能。通常,网关也是提供REST/HTTP的访问API。服务端通过API-GW注册和管理服务。
作用和应用场景
API Gateway 封装内部系统的架构,并且提供 API 给各个客户端。一个网关的基本功能有:统一接入、安全防护、协议适配、流量管控、长短链接支持、容错能力。有了网关之后,各个API服务提供团队可以专注于自己的的业务逻辑处理,而API网关更专注于安全、流量、路由等问题。它还可以有其他功能,如授权、监控、负载均衡、缓存、请求分片和管理、静态响应处理等。网关层作用如下:
- 将所有服务的API接口资源统一暴露
- 实现用户身份认证、权限认证、防止非法请求操作API接口
- 实现监控功能,实时日志输出,对请求进行记录
- 做流量监控
- API接口从内部分离出来

API Gateway 负责请求转发、合成和协议转换。所有来自客户端的请求都要先经过 API Gateway,然后路由这些请求到对应的微服务。API Gateway 将经常通过调用多个微服务来处理一个请求以及聚合多个服务的结果。它可以在 web 协议与内部使用的非 Web 友好型协议间进行转换,如 HTTP 协议、WebSocket 协议。
常见的API网关实现方式
Kong
- 基于Nginx+Lua开发,性能高,稳定,有多个可用的插件(限流、鉴权等等)可以开箱即用。
- 问题:只支持Http协议;二次开发,自由扩展困难;提供管理API,缺乏更易用的管控、配置方式
Zuul
- Netflix开源,功能丰富,使用JAVA开发,易于二次开发;需要运行在web容器中,如Tomcat。
- 问题:缺乏管控,无法动态配置;依赖组件较多;处理Http请求依赖的是Web容器,性能不如Nginx
Traefik
- Go语言开发;轻量易用;提供大多数的功能:服务路由,负载均衡等等;提供WebUI
- 问题:二进制文件部署,二次开发难度大;UI更多的是监控,缺乏配置、管理能力;
Spring Cloud Gateway
- SpringCloud提供的网关服务
Nginx+lua实现
- 使用Nginx的反向代理和负载均衡可实现对api服务器的负载均衡及高可用。lua是一种脚本语言,可以来编写一些简单的逻辑, nginx支持lua脚本
- 问题:自注册的问题和网关本身的扩展性
基于 Nginx 的网关实现(扩展)
注:这里只是基础使用的介绍,具体使用详见 Nginx 的笔记
Nginx 介绍

正向/反向代理
正向代理
正向代理,"它代理的是客户端,代客户端发出请求",是一个位于客户端和原始服务器(origin server)之间的服务器,为了从原始服务器取得内容,客户端向代理发送一个请求并指定目标(原始服务器),然后代理向原始服务器转交请求并将获得的内容返回给客户端。客户端必须要进行一些特别的设置才能使用正向代理。
反向代理
多个客户端给服务器发送的请求,Nginx服务器接收到之后,按照一定的规则分发给了后端的业务处理服务器进行处理了。此时~请求的来源也就是客户端是明确的,但是请求具体由哪台服务器处理的并不明确了,Nginx扮演的就是一个反向代理角色。客户端是无感知代理的存在的,反向代理对外都是透明的,访问者并不知道自己访问的是一个代理。因为客户端不需要任何配置就可以访问。反向代理,"它代理的是服务端,代服务端接收请求",主要用于服务器集群分布式部署的情况下,反向代理隐藏了服务器的信息
如果只是单纯的需要一个最基础的具备转发功能的网关,那么使用Ngnix是一个不错的选择。
简单的使用示例
- 启动订单微服务,单独请求地址:http://127.0.0.1:9001/
- 启动商品微服务,单独请求地址:http://127.0.0.1:9002/
安装ngnix,找到根目录ngnix.exe双击运行即可。修改conf目录下的nginx.conf文件
server {
listen 80;
server_name 127.0.0.1;
ssi on;
ssi_silent_errors on;
# 订单服务
location /api-order {
proxy_pass http://127.0.0.1:9001/;
}
# 端口服务
location /api-product {
proxy_pass http://127.0.0.1:9002/;
}
}链路追踪
微服务架构下的问题
在大型系统的微服务化构建中,微服务按照不同的维度,一个系统会被拆分成许多模块。这些模块负责不同的功能,组合成系统,最终可以提供丰富的功能。在这种架构中,一次请求往往需要涉及到多个服务。互联网应用构建在不同的软件模块集上,这些软件模块,有可能是由不同的团队开发、可能使用不同的编程语言来实现、有可能布在了几千台服务器,横跨多个不同的数据中心,也就意味着这种架构形式也会存在一些问题:
- 如何快速发现问题?
- 如何判断故障影响范围?
- 如何梳理服务依赖以及依赖的合理性?
- 如何分析链路性能问题以及实时容量规划?

分布式链路追踪(Distributed Tracing)
分布式链路追踪(Distributed Tracing),就是将一次分布式请求还原成调用链路,进行日志记录,性能监控并将 一次分布式请求的调用情况集中展示。比如各个服务节点上的耗时、请求具体到达哪台机器上、每个服务节点的请求状态等等。

更多内容详见《分布式链路追踪综合概述》笔记
分布式中的 CAP 原理
对于多数大型互联网应用都是分页式系统(distributed system),分布式系统的最大难点,就是各个节点的状态如何同步。CAP 定理是这方面的基本定理,也是理解分布式系统的起点。
分布式系统的CAP理论,把分布式系统归纳成以下三个特性:
- Consistency(一致性):数据一致更新,所有数据的变化都是同步的
- Availability(可用性):在集群中一部分节点故障后,集群整体是否还能响应客户端的读写请求
- Partition tolerance(分区容忍性):某个节点的故障,并不影响整个系统的运行
注:通过学习CAP理论,得知任何分布式系统只可同时满足二点,没法三者兼顾,既然一个分布式系统无法同时满足一致性、可用性、分区容错性三个特点,所以就需要抛弃其中一点

| 选择 | 说明 |
|---|---|
| CA | 放弃分区容错性,加强一致性和可用性,其实就是传统的关系型数据库的选择 |
| AP | 放弃一致性(这里说的一致性是强一致性),追求分区容错性和可用性,这是很多分布式系统设计时的选择,例如很多NoSQL系统就是如此 |
| CP | 放弃可用性,追求一致性和分区容错性,基本不会选择,网络问题会直接让整个系统不可用 |
需要明确一点的是,在一个分布式系统当中,分区容忍性和可用性是最基本的需求,所以在分布是系统中最当关注的就是A(可用性)P(容忍性),通过补偿的机制寻求数据的一致性
分布式事务
事务概念回顾
事务指的就是一个操作单元,在这个操作单元中的所有操作最终要保持一致的行为,要么所有操作都成功,要么所有的操作都被撤销。
本地事务其实可以认为是数据库提供的事务机制。数据库事务中的四大特性:
- A:原子性(Atomicity),一个事务中的所有操作,要么全部完成,要么全部不完成
- C:一致性(Consistency),在一个事务执行之前和执行之后数据库都必须处于一致性状态
- I:隔离性(Isolation),在并发环境中,当不同的事务同时操作相同的数据时,事务之间互不影响
- D:持久性(Durability),指的是只要事务成功结束,它对数据库所做的更新就必须永久的保存下来
数据库事务在实现时会将一次事务涉及的所有操作全部纳入到一个不可分割的执行单元,该执行单元中的所有操作要么都成功,要么都失败,只要其中任一操作执行失败,都将导致整个事务的回滚
分布式事务概述
分布式事务指事务的参与者、支持事务的服务器、资源服务器以及事务管理器分别位于不同的分布式系统的不同节点之上。本质上来说,分布式事务就是为了保证不同数据库的数据一致性。
简单来说,就是一次大的操作由不同的小操作组成,这些小的操作分布在不同的服务器上,且属于不同的应用,分布式事务需要保证这些小操作要么全部成功,要么全部失败。
分布式事务的场景
- 单体系统访问多个数据库。一个服务需要调用多个数据库实例完成数据的增删改操作

- 多个微服务访问同一个数据库。多个服务需要调用一个数据库实例完成数据的增删改操作

- 多个微服务访问多个数据库。多个服务需要调用多个数据库实例完成数据的增删改操作

分布式事务解决方案
全局事务
全局事务基于DTP模型实现。DTP是由X/Open组织提出的一种分布式事务模型——X/Open Distributed Transaction Processing Reference Model。它规定了要实现分布式事务,需要三种角色:
- AP: Application 应用系统 (微服务)
- TM: Transaction Manager 事务管理器 (全局事务管理)
- RM: Resource Manager 资源管理器 (数据库)
整个事务分成两个阶段:
- 阶段一: 表决阶段,所有参与者都将本事务执行预提交,并将能否成功的信息反馈发给协调者。
- 阶段二: 执行阶段,协调者根据所有参与者的反馈,通知所有参与者,步调一致地执行提交或者回滚。

优点
- 提高了数据一致性的概率,实现成本较低
缺点
- 单点问题: 事务协调者宕机
- 同步阻塞: 延迟了提交时间,加长了资源阻塞时间
- 数据不一致: 提交第二阶段,依然存在commit结果未知的情况,有可能导致数据不一致
可靠消息服务
基于可靠消息服务的方案是通过消息中间件保证上、下游应用数据操作的一致性。假设有A和B两个系统,分别可以处理任务A和任务B。此时存在一个业务流程,需要将任务A和任务B在同一个事务中处理。就可以使用消息中间件来实现这种分布式事务。

第一步: 消息由系统A投递到中间件
- 在系统A处理任务A前,首先向消息中间件发送一条消息
- 消息中间件收到后将该条消息持久化,但并不投递。持久化成功后,向A回复一个确认应答
- 系统A收到确认应答后,则可以开始处理任务A
- 任务A处理完成后,向消息中间件发送Commit或者Rollback请求。该请求发送完成后,对系统A而言,该事务的处理过程就结束了
- 如果消息中间件收到Commit,则向B系统投递消息;如果收到Rollback,则直接丢弃消息。但是如果消息中间件收不到Commit和Rollback指令,那么就要依靠"超时询问机制"。
超时询问机制:系统A除了实现正常的业务流程外,还需提供一个事务询问的接口,供消息中间件调用。当消息中间件收到发布消息便开始计时,如果到了超时没收到确认指令,就会主动调用系统A提供的事务询问接口询问该系统目前的状态。该接口会返回三种结果,中间件根据三种结果做出不同反应:
- 提交:将该消息投递给系统B
- 回滚:直接将条消息丢弃
- 处理中:继续等待
第一步: 消息由系统A投递到中间件
消息中间件向下游系统投递完消息后便进入阻塞等待状态,下游系统便立即进行任务的处理,任务处理完成后便向消息中间件返回应答。
- 如果消息中间件收到确认应答后便认为该事务处理完毕
- 如果消息中间件在等待确认应答超时之后就会重新投递,直到下游消费者返回消费成功响应为止。一般消息中间件可以设置消息重试的次数和时间间隔,如果最终还是不能成功投递,则需要手工干预。这里之所以使用人工干预,而不是使用让A系统回滚,主要是考虑到整个系统设计的复杂度问题。
基于可靠消息服务的分布式事务,前半部分使用异步,注重性能;后半部分使用同步,注重开发成本。
最大努力通知
最大努力通知也被称为定期校对,其实是对第二种解决方案的进一步优化。它引入了本地消息表来记录错误消息,然后加入失败消息的定期校对功能,来进一步保证消息会被下游系统消费。

第一步: 消息由系统A投递到中间件
- 处理业务的同一事务中,向本地消息表中写入一条记录
- 准备专门的消息发送者不断地发送本地消息表中的消息到消息中间件,如果发送失败则重试
第二步: 消息由中间件投递到系统B
- 消息中间件收到消息后负责将该消息同步投递给相应的下游系统,并触发下游系统的任务执行
- 当下游系统处理成功后,向消息中间件反馈确认应答,消息中间件便可以将该条消息删除,从而该事务完成
- 对于投递失败的消息,利用重试机制进行重试,对于重试失败的,写入错误消息表
- 消息中间件需要提供失败消息的查询接口,下游系统会定期查询失败消息,并将其消费
最大努力通知的优缺点:
- 优点:一种非常经典的实现,实现了最终一致性。
- 缺点:消息表会耦合到业务系统中,如果没有封装好的解决方案,会有很多杂活需要处理。
TCC 事务
TCC(Try Confirm Cancel),它属于补偿型分布式事务。TCC 实现分布式事务一共有三个步骤:
- Try:尝试待执行的业务
这个过程并未执行业务,只是完成所有业务的一致性检查,并预留好执行所需的全部资源
- Confirm:确认执行业务
确认执行业务操作,不做任何业务检查, 只使用 Try 阶段预留的业务资源。通常情况下,采用 TCC 则认为 Confirm 阶段是不会出错的。即:只要 Try 成功,Confirm 一定成功。若 Confirm 阶段真的出错了,需引入重试机制或人工处理。
- Cancel:取消待执行的业务
取消 Try 阶段预留的业务资源。通常情况下,采用 TCC 则认为 Cancel 阶段也是一定成功的。若 Cancel 阶段真的出错了,需引入重试机制或人工处理。


TCC两阶段提交与XA两阶段提交的区别是:
- XA 是资源层面的分布式事务,强一致性,在两阶段提交的整个过程中,一直会持有资源的锁。
- TCC 是业务层面的分布式事务,最终一致性,不会一直持有资源的锁。
TCC事务的优缺点:
- 优点:把数据库层的二阶段提交上提到了应用层来实现,规避了数据库层的 2PC 性能低下问题。
- 缺点:TCC 的 Try、Confirm 和 Cancel 操作功能需业务提供,开发成本高。
分布式基础架构之部署容器编排化

虚拟机
虚拟机由某些特定的硬件和内核虚拟化组成,运行客户操作系统。称为管理程序的软件创建虚拟化硬件,其可以包括虚拟磁盘,虚拟网络接口,虚拟 CPU 等。虚拟机还包括可以与此虚拟硬件通信的客户端内核。管理程序可以托管,这意味着它是一些在主机操作系统(MacOS)上运行的软件,如示例中所示。它也可以是裸机,直接在机器硬件上运行(替换当前的操作系统)。无论哪种方式,管理程序方法都被认为是重量级的,因为它需要虚拟化多个部分(如果不是全部硬件和内核)。
VM 需要硬件虚拟化才能实现机器级隔离,而容器则只需要在同一操作系统内进行隔离操作。随着隔离空间数量的增加,开销差异变得非常明显。
容器
在过去几年里,云平台发展迅速,但其中困扰运维工程师最多的,是需要为各种迥异的开发语言安装相应的运行时环境。虽然自动化运维工具可以降低环境搭建的复杂度,但仍然不能从根本上解决环境的问题。

Docker 的出现成为了软件开发行业新的分水岭,容器技术的成熟也标志着技术新纪元的开启。Docker 提供了让开发工程师可以将应用和依赖封装到一个可移植的容器中的能力,这项举措使得 Docker 大有席卷整个软件行业并且进而改变行业游戏规则的趋势。Docker 通过集装箱式的封装方式,让开发工程师和运维工程师都能够以 Docker 所提供的镜像分发的标准化方式发布应用,使得异构语言不再是捆绑团队的枷锁。

容器是包含应用程序代码,配置和依赖关系的软件包,可提供运营效率和生产力。容器为我们提供了可预测的,可重复的和不可变的运行预期,容器的兴起是 DevOps 即服务的一个巨大推动因素,可以克服当今面临的最大安全障碍。容器化通过在操作系统级别进行虚拟化来使应用程序可移植,从而创建基于内核的隔离的封装系统。容器化的应用程序可以放在任何地方,无需依赖项运行或需要整个 VM,从而消除了依赖关系。
作为独立的单元,容器能够在任何主机操作系统,CentOS,Ubuntu,MacOS,甚至是像 Windows 这样的非 UNIX 系统中运行。容器还充当标准化的工作或计算单元。一个常见的范例是每个容器运行单个 Web 服务器,数据库的单个分片或单个 Spark 工作程序等,只需要扩展容器的数量就能够便捷地扩展应用。每个容器都有一个固定的资源配置(CPU,RAM,线程数等),并且扩展应用程序需要只扩展容器的数量而不是单个资源原语。当应用程序需要按比例放大或缩小时,这为工程师提供了更容易的抽象。容器也是实现微服务架构的一个很好的工具,每个微服务只是一组协作容器。例如,可以使用单个主容器和多个从容器来实现 Redis 微服务。
Kubernetes 与编排
随着虚拟化技术的成熟和分布式架构的普及,用来部署、管理和运行应用的云平台被越来越多地提及。IaaS、PaaS 和 SaaS 是云计算的三种基本服务类型,分别表示关注硬件基础设施的基础设施即服务、关注软件和中间件平台的平台即服务,以及关注业务应用的软件即服务。容器的出现,使原有的基于虚拟机的云主机应用,彻底转变为更加灵活和轻量的容器与编排调度的云平台应用。

然而容器单元越来越散落使得管理成本逐渐上升,大家对容器编排工具的需求前所未有的强烈,Kubernetes、Mesos、Swarm 等为云原生应用提供了强有力的编排和调度能力,它们是云平台上的分布式操作系统。容器编排是通常可以部署多个容器以通过自动化实现应用程序的过程。像 Kubernetes 和 Docker Swarm 这样的容器管理和容器编排引擎,使用户能够指导容器部署并自动执行更新,运行状况监视和故障转移过程。
Kubernetes 是目前世界范围内关注度最高的开源项目,它是一个出色的容器编排系统,用于提供一站式服务。Kubernetes 出身于互联网行业巨头 Google,它借鉴了由上百位工程师花费十多年时间打造的 Borg 系统的理念,安装极其简易,网络层对接方式十分灵活。Kubernetes 和 Mesos 的出色表现给行业中各类工程师的工作模式带来了颠覆性的改变。他们再也不用关注每一台服务器,当服务器出现问题时,只要将其换掉即可。业务开发工程师不必再过分关注非功能需求,只需专注自己的业务领域即可。而中间件开发工程师则需要开发出健壮的云原生中间件,用来连接业务应用与云平台。
Kubernetes、Service Mesh 和 Serverless 三者共同演绎不同层次的封装和向上屏蔽下面的细节。Kubernetes 引入了不同的设计模式,实现对各种云资源全新、有效和优雅的抽象和管理模式,让集群的管理和应用发布变成了件相当轻松且不易出错的事。被广泛采用的微服务软件架构将分布式应用的各种复杂度迁移到了服务之间,如何通过全局一致、体系化、规范化和无侵入的手段进行治理就变成了微服务软件架构下至关重要的内容。Kubernetes 细化的应用程序的分解粒度,同时将服务发现、配置管理、负载均衡和健康检查等作为基础设施的功能,简化了应用程序的开发。而 Kubernetes 这种声明式配置尤其适合 CI/CD 流程,况且现在还有如 Helm、Draft、Spinnaker、Skaffold 等开源工具可以帮助我们发布 Kuberentes 应用。

Service Mesh 通过将各服务所共用和与环境相关的内容剥离到部署于每个服务边上的 Sidecar 进程而轻松地做到了。这一剥离动作使得服务与平台能充分解耦而方便各自演进与发展,也使得服务变轻而有助于改善服务启停的及时性。Service Mesh 因为将那些服务治理相关的逻辑剥离到了 Sidecar 中且作为独立进程,所以 Sidecar 所实现的功能天然地支持多语言,为上面的服务采用多语言开发创造了更为有利的条件。通过 Service Mesh 对整个网络的服务流量进行技术收口,让异地多活这样涉及流量调度的系统工程实现起来更加优雅、简洁与有效,也能更加方便地实现服务版本升级时的灰度、回滚而改善安全生产质量。由于技术收口,给服务流量的治理和演进、排错、日志采集的经济性等疑难问题创造了新的发展空间。
架构设计(待整理)
架构模式(待整理)
技术架构图(待整理)
企业级微服务命名规则(待整理)
大型企业微服务(核心业务前端)
在大型微服务项目中,前端工程命名不应孤立设计,而要纳入整体代码库规范。按DDD 领域拆分 + 工程用途分类,微服务项目优先使用精准后缀,例如:
plaintext
<业务域>-<形态>可独立部署・业务应用类(核心业务前端)
| 后缀 | 适用场景 | 示例 |
|---|---|---|
-admin | B 端后台管理系统(中台 / ERP / 商户后台,企业最常用,首选替代 web) | order-admin订单管理前端、user-admin用户后台 |
-h5 / -mobile | 移动端 H5、微信网页、wap 用户端 | goods-h5商城移动端 |
-pc / -web | C 端 PC 用户官网、面向客户的 PC 站点 | mall-pc商城 PC 官网 |
-portal | 统一门户、单点登录首页、系统总入口 | base-portal平台统一门户 |
-mini/mp | 微信 / 支付宝小程序 | pay-mini支付小程序 |
-app | 若用 React Native / Flutter 等跨端技术,也可用 app |
依赖包・公共资源类(npm 私有包,不单独部署)
| 后缀 | 适用场景 | 示例 |
|---|---|---|
-ui | 全平台 / 业务域 UI 组件库 | base-ui全局基础组件库、crm-uiCRM 业务组件 |
-common | 纯工具库(常量、枚举、请求封装、工具函数,无 UI) | base-common前端公共工具 |
-theme | 全局样式、主题包 | base-theme统一主题样式 |
-icon | 图标资源分包 | base-icon项目图标库 |
-sdk | 前端埋点 SDK、三方对接 JS 包 | monitor-sdk监控埋点 SDK |