为什么90%的开发者放弃传统的技术架构,而选择微服务?

2年前 (2022) 程序员胖胖胖虎阿
170 0 0

为什么90%的开发者放弃传统的技术架构,而选择微服务?

目录

  • 第一章 创建分布式架构的重要因素
    • 一、CDN加速静态文件访问
    • 二、分布式存储
      • 1、简介
      • 2、关键技术
      • 3、考虑因素
    • 三、分布式搜索引擎
    • 四、应用级容灾
    • 五、系统动态扩容
      • 1、FastDFS的扩容分为对group纵向扩容和横向扩容
  • 第二章 分布式架构设计原则
    • 一、主流架构模型-SOA架构和微服务架构
    • 二、领域驱动设计及业务驱动划分DDD
      • 1、什么是领域/子领域(Domain/Subdomain)
      • 2、设计(Design)和驱动(Driven)
      • 3、领域驱动设计中的领域模型
      • 4、从分层架构到六边形架构
    • 三、如何DDD
      • 1、界限上下文
      • 2、Repository
      • 3、DDD与微服务的关系
    • 四、分布式架构的基本理论CAP、BASE以及其应用
      • 1、CAP
      • 2、可用的选择
      • 3、与NoSQL的关系
      • 4、与BASE的关系
  • 第三章 漫谈微服务架构
    • 一、SOA架构和微服务架构之间的区别和联系
    • 二、如何设计微服务及其设计原则
      • 1、AKF拆分原则
      • 2、前后端分离
      • 3、无状态服务
      • 4、无状态通信原则(RESTful通信风格)
    • 云原生思维导图

第一章 创建分布式架构的重要因素

一、CDN加速静态文件访问

CDN是Content Delivery Network的简称,即“内容分发网络”的意思,一般是指网站加速或用户下载速度加速。

简单来说CDN相当于一个中间代理,原来我们请求百度时,请求会直接发送到百度的服务器,加入请求者在大连,但百度的服务器在北京,这样的话请求和响应都会受到距离的影响而变得慢一些,但有了CDN之后,请求先发到距离请求IP定位最近的CDN服务器上,该服务器缓存了百度页面的一些静态文件,比如CSS、JS、html、图片等,这样对用户来说,获取这些静态资源就比较近了,速度也就更快。至于动态的资源,因为是可变的,所以无法通过缓存的方式存储在CDN服务器上,仍然需要通过CDN去请求对应的服务器获取资源,所以CDN加速仅局限于静态资源。

在分布式系统中,CDN可以一定程度的减轻服务器的IO压力,提高响应速度,而且在使用CDN后用户的请求发送到CDN服务器上,可以避免用户直接访问源服务器,从而可以一定程度上提高系统的安全性,降低被黑客攻击的可能性,类似于保护代理。

但CDN的架设成本较高,如果需要提高服务效率和质量,需要在全国各地设有服务器,而且在人口密集的城市需要的网点更多,才能缓解单一网点的压力,这笔成本可以说非常高,所以一般CDN加速都是由专门的大公司来做,比如阿里爸爸,七牛云等。

二、分布式存储

1、简介

分布式存储是将数据分散存储在多台独立的设备上。

传统的网络存储系统采用集中的存储服务器存放所有数据,存储服务器成为系统性能的瓶颈,也是可靠性和安全性的焦点,不能满足大规模存储应用的需要。分布式网络存储系统采用可扩展的系统结构,利用多态存储服务器分担存储负荷,利用位置服务器定位存储信息,它不但提高了系统的可靠性、可用性和存取效率,还易于扩展。

2、关键技术

(1)元数据管理

元数据(metadata),为描述数据的数据,主要是描述数据属性的信息,用来支持如指示存储位置、历史数据、资源查找、文件记录等功能。元数据算是一种电子目录,为了达到编制目录的目的,必须在描述并收藏数据的内容或特色,从而达到协助数据检索的目的。

大数据环境下,元数据的体量也非常大,元数据的存储性能是整个分布式文件系统性能的关键。常见的元数据管理可分为集中式和分布式元数据管理架构。集中式元数据管理架构采用单一的元数据服务器,实现简单.但是存在单点故障等问题。分布式元数据管理架构则将元数据分散在多个结点上.进而解决了元数据服务器的性能瓶颈等问题.并提高了元数据管理架构的可扩展性,但实现较为复杂,并引入了元数据一致性的问题。另外,还有一种无元数据服务器的分布式架构,通过在线算法组织数据,不需要专用的元数据服务器。但是该架构对数据一致性的保障很困难.实现较为复杂。文件目录遍历操作效率低下,并且缺乏文件系统全局监控管理功能。

(2)系统弹性扩展技术

在大数据环境下,数据规模和复杂度的增加往往非常迅速,对系统的扩展性能要求较高。实现存储系统的高可扩展性首先要解决两个方面的重要问题,包含元数据的分配和数据的透明迁移。元数据的分配主要通过静态子树划分技术实现,后者则侧重数据迁移算法的优化。此外,大数据存储体系规模庞大.结点失效率高,因此还需要完成一定的自适应管理功能。系统必须能够根据数据量和计算的工作量估算所需要的结点个数,并动态地将数据在结点间迁移。以实现负载均衡;同时.结点失效时,数据必须可以通过副本等机制进行恢复,不能对上层应用产生影响。

(3)存储层级内的优化技术

构建存储系统时.需要基于成本和性能来考虑,因此存储系统通常采用多层不同性价比的存储器件组成存储层次结构。大数据的规模大,因此构建高效合理的存储层次结构,可以在保证系统性能的前提下,降低系统能耗和构建成本,利用数据访问局部性原理.可以从两个方面对存储层次结构进行优化。从提高性能的角度,可以通过分析应用特征,识别热点数据并对其进行缓存或预取,通过高效的缓存预取算法和合理的缓存容量配比,以提高访问性能。从降低成本的角度,采用信息生命周期管理方法,将访问频率低的冷数据迁移到低速廉价存储设备上,可以在小幅牺牲系统整体性能的基础上,大幅降低系统的构建成本和能耗。

(4)针对应用和负载的存储优化技术

传统数据存储模型需要支持尽可能多的应用,因此需要具备较好的通用性。大数据具有大规模、高动态及快速处理等特性,通用的数据存储模型通常并不是最能提高应用性能的模型.而大数据存储系统对上层应用性能的关注远远超过对通用性的追求。针对应用和负载来优化存储,就是将数据存储与应用耦合。简化或扩展分布式文件系统的功能,根据特定应用、特定负载、特定的计算模型对文件系统进行定制和深度优化,使应用达到最佳性能。这类优化技术在谷歌、FaceBook等互联网公司的内部存储系统上,管理超过千万亿字节级别的大数据,能够达到非常高的性能。

3、考虑因素

一致性
可用性
分区容错性

三、分布式搜索引擎

分布式搜索引擎是根据地域、主题、IP地址及其它的划分标准,将全网分成若干个自治区域,在每个自治区域内设立一个检索服务器。

四、应用级容灾

应用级容灾即应用级容灾备份,是指在本地或异地建立一套完整的与本地生产系统相当的备份应用系统。在本地数据出现灾难时,备份中心可以接管本地生产系统的业务,并在本地生产系统正常使用后,恢复100%数据,保证恢复数据可用。

五、系统动态扩容

当用户量越来越大,则集群中某个group总会到达其极限,这时就得扩展集群的容量了。

1、FastDFS的扩容分为对group纵向扩容和横向扩容

(1)纵向扩容 指在同一个group组中增加服务器,实现数据冗余,数据备份。同一个group中最大容量取决于最小的storage的存储容量。因此如果还想继续使用此group,则需要对此group对应的所有服务器挂载同样容量的磁盘,指定store_path1……,但这样做的话成本相当的高,不推荐。

(2)横向扩容是通过集群实现,指新增一个group,增加整个FastDFS的存储空间。fastDFS的存储空间指的是所有group加起来的存储容量。

第二章 分布式架构设计原则

一、主流架构模型-SOA架构和微服务架构

微服务与SOA架构

二、领域驱动设计及业务驱动划分DDD

领域驱动设计(Domain-Driven Design,DDD )是由Eric Evans最先提出,目的是对软件所涉及到的领域进行建模,以应对系统规模过大时引起的软件复杂性的问题。整个过程大概是这样的,开发团队和领域专家一起通过 通用语言(Ubiquitous Language)去理解和消化领域知识,从领域知识中提取和划分为一个一个的子领域(核心子域,通用子域,支撑子域),并在子领域上建立模型,再重复以上步骤,这样周而复始,构建出一套符合当前领域的模型。与现在的分布式、微服务相比,绝对是即将步入中年的“老家伙”了。直到近些年微服务理论被提出、被互联网行业广泛使用,人们似乎又重新发现了领域驱动设计的价值。所以看起来也确实是因为微服务,领域驱动设计才迎来了第二春。

1、什么是领域/子领域(Domain/Subdomain)

领域是与某个特定问题相关的知识和行为。比如支付平台就属于特定的领域,只要是这个领域,都会有账户、会记、收款、付款、风控等核心环节。所以,同一个领域的系统都具有相同的核心业务,他们要解决的问题的本质是一致的。一个领域本质上可以理解为就是一个问题域,只要是同一个领域,那问题域就相同。所以,只要我们确定了系统所属的领域,那这个系统的核心业务,即要解决的关键问题、问题的范围边界就基本确定了。

在日常开发中,我们通常会将一个大型的软件系统拆分成若干个子系统。这种划分有可能是基于架构方面的考虑,也有可能是基于基础设施的。在DDD中,我们对系统的划分是基于领域(基于业务)的。比如上文提到支付平台是一个领域,而账户、会记、收款、付款等则为子领域。一个领域由众多子领域聚集而形成。

2、设计(Design)和驱动(Driven)

DDD中的设计主要指领域模型的设计。DDD是一种基于模型驱动开发的软件开发思想,强调领域模型是整个系统的核心,领域模型也是整个平台的核心价值。每一个领域都有一个对应的领域模型,领域模型能够很好的解决负责的业务问题。所以领域模型的设计和架构设计同等重要。

DDD中,总是以领域为边界,分析领域中的核心问题。然后设计对应的领域模型,通过领域模型驱动代码的实现。而数据库设计、持久化设计这些都不是DDD的核心,属于外围的东西。与数据库驱动开发的思路形成对比,驱动中需要记住两个原则:领域驱动领域模型设计,领域模型驱动代码实现。

3、领域驱动设计中的领域模型

回想日常的开发过程,日常建表,然后写CRUD,因此也有一句很真实的话“面试造火箭,工作拧螺丝”。其根本原因在于表驱动思想,而不是领域驱动设计。

前者是能增加数据库的表数量,而后者才能形成长期的、具有业务意义的模型,这样的系统生命力才更加长久。我们也才能用工程的方法来编码,从编码转身为业务领域的开发专家。有很多关于领域驱动设计的论述中都未明确我们如何得到“领域”,只有合理的领域模型才能有效驱动设计开发。所以建好领域模型是关键,对于领域模型的思考与技术框架升级同样重要。

4、从分层架构到六边形架构

【Spring Cloud 2】软件架构设计

三、如何DDD

1、界限上下文

领域中还同时存在问题空间(problem space)和解决方案空间(solution space)。在问题空间中,我们思考的是业务所面临的挑战,而在解决方案空间中,我们思考如何实现软件以解决这些业务挑战。

问题空间是领域的一部分,对问题空间的开发将产生一个新的核心域。对问题空间的评估应该同时考虑已有子域和额外所需子域。因此,问题空间是核心域和其他子域的组合。问题空间中的子域通常随着项目的不同而不同,他们各自关注于当前的业务问题,这使得子域对于问题空间的评估非常有用。子域允许我们快速地浏览领域中的各个方面,这些方面对于解决特定的问题是必要的。
解决方案空间包含一个或多个界限上下文,即一组特定的软件模型。这是因为界限上下文是一个特定的解决方案,用以解决问题。
通常,我们希望将子域一对一地对应到限界上下文。这种做法显式地将领域模型分离到不同的业务板块中,并将问题空间和解决方案空间融合在一起。

但是在实践中,这种做法并不总是可能的,想像一下,谁没有维护过“毛线团”系统,现在我们就要借助界限上下文来安全的、合理的、快速的理顺这堆交织不清的关系。

电子商务系统是个典型的“大线团”,我们按照经验将其在逻辑上拆解为:产品目录子域、订单子域、发票子域,当然你也可以拆解出更多的子域,甚至将产品目录子域继续向下分解为类目子域、商品子域(虚线是逻辑子域)。另外还有一个专门用于库存管理的库存系统、以及用于销售预测的预测系统。

电商系统里面也存在物流相关的业务逻辑,同时物流又不可避免的作用于库存逻辑之上。而往往最难以把握的就是这部分相交的地方,这才是实际的项目场景,我们通常做法是将其归并为一个新的履约系统,作为一个支撑子域去辅助主要的电商系统。

当然,随着业务不断发展,我们的履约模式(比如支持同城当日达、商家仓储发货、电商集货仓发货、退货等等)、库存类型(调拨库存、越库操作、临期库存、残次库存等等)越来越复杂,我们考虑将其再向下分解为履约系统2.0、库存系统2.0。

核心就是我们可以在概念上使用多个子域来分解较大的界限上下文,也可以将多个分散的界限上下文包含在同一个新的子域当中,最终做到“子域和界限上下文一一对应”。我个人觉得,这个过程是最考验内功心法的地方。

上面我们已经说了会拆解出来新的子域,目的使“整洁干净”的界限上下文能够一对一的解决这个子域对应的问题空间,但是随着拆解就必然导致“关联关系”。因为要解决问题空间,必须使用对应的子域,你可以把它拆解出去,但是它始终存在于依赖网中。

我们通用的做法是在相交的地方,定义接口。由支撑的界限上下文去实现,可以做到支撑上下文的插拔式切换。这里仍然是我们强调的“依赖抽象”“解耦”。

2、Repository

“对于每种需要进行全局访问的对象,我们都应该创建另一个对象来作为这些对象的提供方,就像是在内存中访问这些对象的集合一样。为这些对象创建一个全局接口以供客户端访问。为这些对象创建添加和删除方法……

此外,我们还应该提供能够按照某种指定条件来查询这些对象的方法……只为聚合创建资源库”引用自《领域驱动设计》。大家和我的疑问一样,Repository是什么?DAO与Repository什么区别?为什么需要Repository?

首先,Repository是一个独立的层,介于领域层与数据映射层之间。

它的存在让领域层感觉不到数据访问层的存在,它提供一个类似集合的接口提供给领域层进行领域对象的访问。Repository 是仓库管理员,领域层需要什么东西只需告诉仓库管理员,由仓库管理员把东西拿给它,并不需要知道东西实际放在哪。其核心还是“解耦”,所以我们应该明确领域层只应该使用Repository获取对象。

接下来,看看DAO与Repository什么区别。

我的理解是这样,你可以将Repository当做dao来看待,但是请注意一点,在设计Repository时,我们采用面向集合的方式,而不是面向数据访问的方式。这有助于你将自己的领域当做模型来看待,而不是CRUD操作;Repository是面向领域的,Repository定义的目的不是DB驱动的,Repository管理的数据的最小粒度是聚合根,这两点和dao有很大不同。

通常我们建议把Repository定义为一个集合并且只提供类似集合的接口,比如add、remove,get这种操作。一言以蔽之,我们要用集合的思想来操作聚合根,而不是传动的面向DB的CRUD方法。

最后来看看为什么需要Repository,我理解还是“解耦”。当我们把Repository想象成一个资源库,也不关心背后的持久化,这些也不是DDD该思考的东西,我们可以用mysql来实现,也可以用MongoDB,甚至是Redis。尤其是当我们在更换底层存储的时候,领域层以及相关的服务并无任何影响。

3、DDD与微服务的关系

那么微服务和DDD是什么关系呢?其实在2015年的一次演讲中,DDD的提出者Eric Evans表达了对微服务技术的热爱与支持,认为微服务是让DDD落地的好工具。因为DDD和微服务其本质是降低软件项目的复杂性,而DDD是一种设计理念/设计方法,DDD需要有强制性的原则做保障,否则不同的领域对象终究会混在一起。而微服务本身的一些限制,以及大家都能理解微服务的实施前提和首要条件,会在实现上给DDD增加了一些原则限制。DDD和微服务的不一定要同时使用落地,但是如果将DDD和微服务结合一起,效果是非常不错的。

四、分布式架构的基本理论CAP、BASE以及其应用

1、CAP

CAP原则又称CAP定理,指的是在一个分布式系统中,Consistency(一致性)、Availability(可用性)、Partition tolerance(分区容错性),三者不可兼得。

一致性C:在分布式系统中的所有数据备份,在同一时刻是否同样的值。
可用性A:保证每个请求不管成功或失败都应该有响应。
分区容忍性P:系统中任意信息的丢失或失败不会影响系统的继续运作。
CAP原则的精髓就是要么AP,要么CP,要么AC,但是不存在CAP。如果在某个分布式系统中数据无副本, 那么系统必然满足强一致性条件, 因为只有独一数据,不会出现数据不一致的情况,此时C和P两要素具备,但是如果系统发生了网络分区状况或者宕机,必然导致某些数据不可以访问,此时可用性条件就不能被满足,即在此情况下获得了CP系统,但是CAP不可同时满足。

因此在进行分布式架构设计时,必须做出取舍。当前一般是通过分布式缓存中各节点的最终一致性来提高系统的性能,通过使用多节点之间的数据异步复制技术来实现集群化的数据一致性。通常使用类似memcached之类的MOSQL作为实现手段。虽然memcached也可以是分布式集群环境的,但是对于一份数据来说,它总是存储在某一台memcached 服务器上。如果发生网络故障或服务器死机,则存储在这台服务器上的所有数据都将不可访问。由于数据是存储在内存中,重启服务器,将导致数据全部丢失。当然也可以自己实现一套机制,用来在分布式memcached之间进行数据的同步和持久化,但是实现难度非常的。

2、可用的选择

CAP理论就是说在分布式存储系统中,最多只能实现上面的两点。由于网络硬件肯定会出现延迟丢包的问题,所以分区容错性是我们必须需要实现的。所以我们只能在一致性和可用性之间进行权衡,没有NOSQL系统能同时保证这三点。对于web2.0网站来说,关系数据库的很多主要特性却往往无用武之地。

(1)、数据库事务一致性需求

很多web实时系统并不要求严格的数据库事务,对读一致性的要求很低,有些场合对写一致性要求并不高。允许实现最终一致性。

(2)、数据库的写实时性和读实时性需求

对关系数据库来说,插入一条数据之后立刻查询,是肯定可以读出来这条数据的,但是对于很多web应用来说,并不要求这么高的实时性,比方说发一条消息之 后,过几秒乃至十几秒之后,我的订阅者才看到这条动态是完全可以接受的。

(3)、对复杂的SQL查询,特别是多表关联查询的需求

任何大数据量的web系统,都非常忌讳大表的关联查询,以及复杂的复杂数据分析类型的报表查询,特别是SNS类型的网站,从需求以及产品设计角度就避免了这种情况的产生。往往更多的只是单表的主键查询,以及单表的简单条件分页查询,SQL的功能被极大的弱化了。

3、与NoSQL的关系

传统的关系型数据库在功能支持上通常很宽泛,从简单的键值查询,到复杂的多表联合查询再到事务机制的支持。而与之不同的是,NoSQL系统通常注重性能和扩展性,而非事务机制(事务就是强一致性的体现)。

传统的SQL数据库的事务通常都是支持ACID的强事务机制。A代表原子性,即在事务中执行多个操作是原子性的,要么事务中的操作全部执行,要么一个都不执行;C代表一致性,即保证进行事务的过程中整个数据库的状态是一致的,不会出现数据花掉的情况;I代表隔离性,即两个事务不会相互影响,覆盖彼此数据等;D表示持久化,即事务一旦完成,那么数据应该是被写到安全的,持久化存储的设备上(比如磁盘)。

NoSQL系统仅提供对行级别的原子性保证,也就是说同时对同一个Key下的数据进行的两个操作,在实际执行的时候是会串行的执行,保证了每一个Key-Value对不会被破坏。

4、与BASE的关系

BASE是Basically Available(基本可用)、Soft state(软状态)和Eventually consistent(最终一致性)三个短语的简写。

BASE是对CAP中一致性和可用性权衡的结果,其来源于对大规模互联网系统分布式实践的结论,是基于CAP定理逐步演化而来的,其核心思想是即使无法做到强一致性(Strong consistency),但每个应用都可以根据自身的业务特点,采用适当的方式来使系统达到最终一致性(Eventual consistency)。接下来我们着重对BASE中的三要素进行详细讲解。基本可用:指分布式系统在出现不可预知故障的时候,允许损失部分可用性。

注意,这绝不等价于系统不可用,以下两个就是“基本可用”的典型例子:

响应时间上的损失:正常情况下,一个在线搜索引擎需要0.5秒内返回给用户相应的查询结果,但由于出现异常(比如系统部分机房发生断电或断网故障),查询结果的响应时间增加到了1~2秒。

功能上的损失:正常情况下,在一个电子商务网站上进行购物,消费者几乎能够顺利地完成每一笔订单,但是在一些节日大促购物高峰的时候,由于消费者的购物行为激增,为了保护购物系统的稳定性,部分消费者可能会被引导到一个降级页面。

弱状态:也称为软状态,和硬状态相对,是指允许系统中的数据存在中间状态,并认为该中间状态的存在不会影响系统的整体可用性,即允许系统在不同节点的数据副本之间进行数据同步的过程存在延时。

最终一致性:强调的是系统中所有的数据副本,在经过一段时间的同步后,最终能够达到一个一致的状态。因此,最终一致性的本质是需要系统保证最终数据能够达到一致,而不需要实时保证系统数据的强一致性。

第三章 漫谈微服务架构

一、SOA架构和微服务架构之间的区别和联系

【Spring Cloud 5】SOA架构和微服务架构之间的关系

二、如何设计微服务及其设计原则

1、AKF拆分原则

AKF扩展立方体(参考《The Art of Scalability》),是一个叫AKF的公司的技术专家抽象总结的应用扩展的三个维度。理论上按照这三个扩展模式,可以将一个单体系统,进行无限扩展。

X 轴 :指的是水平复制,很好理解,就是讲单体系统多运行几个实例,做个集群加负载均衡的模式。

Z 轴 :是基于类似的数据分区,比如一个互联网打车应用突然或了,用户量激增,集群模式撑不住了,那就按照用户请求的地区进行数据分区,北京、上海、四川等多建几个集群。

Y 轴 :就是我们所说的微服务的拆分模式,就是基于不同的业务拆分。

场景说明:比如打车应用,一个集群撑不住时,分了多个集群,后来用户激增还是不够用,经过分析发现是乘客和车主访问量很大,就将打车应用拆成了三个乘客服务、车主服务、支付服务。三个服务的业务特点各不相同,独立维护,各自都可以再次按需扩展。

也就是说Y轴代表了系统功能上的划分方向,X轴代表了功能或数据上的复制方向,Z轴代表了按照一定条件进行优先级划分:比如,同样是扩展系统能力,按照地域优先级来进行数据分区。

2、前后端分离

前后端分离,不仅要做到技术代码的分离,还要做到物理分离的部署方式,不要使用之前的服务端模板技术,如JSP。

分离模式下,前后端交互界面更清晰,就剩下接口和模型,后端的接口简洁明了,更容易维护。

前端多渠道应用场景更容易实现,后端无需变更,采用统一的数据和模型,即可支撑PC前端、移动APP等访问。

3、无状态服务

状态:如果一个数据需要被多个服务共享,则这个数据就是状态。

有状态服务: 依赖于状态数据的服务称为有状态服务。

无状态服务: 不依赖状态数据的服务成为无状态服务。

这里提到的无状态服务原则,并不是说在微服务中不允许存在状态,而是将有状态的业务服务改为无状态的计算服务,把“状态”数据迁移到对应的“有状态服务”中。

eg:本地内存中建立的数据缓存、Session缓存,到现在的微服务架构中就应该把这些数据迁移到分布式缓存中存储,让业务服务变成一个无状态的计算节点。

迁移后,就可以做到按需动态伸缩,微服务应用在运行时动态增删节点,就不再需要考虑缓存数据如何同步的问题。

4、无状态通信原则(RESTful通信风格)

无状态通信:每次通信都是独立的,不存在共用的数据(状态),不相互依赖某一数据。

无状态通信的最佳实践就是RESTful通信风格,RESTful具有如下优势:

天生适合无状态的HTTP协议,具有很强的扩展能力;

JSON报文序列化,轻量简单,人机均可读,学习成本低,对搜索引擎友好;

RESTful具有语言无关性,各大热门语言都有成熟的API框架。

云原生思维导图

为什么90%的开发者放弃传统的技术架构,而选择微服务?

相关文章

暂无评论

暂无评论...