干货速来!透彻剖析微服务架构设计模式,深入开发Java有奇效

什么是微服务模式随着网络基础设施的高速发展 , 以及越来越多的个体接入互联网 , 在考虑构建支持海量请求以及多变业务的软件平台时 , 微服务架构成为多数人的首选 。 微服务架构的出现时服务事物发展规律的:当问题足够大 , 有足够多的的不确定因素时 , 人们习惯于把大的问题拆分成小的问题 。 通过分割 , 抽象和重用小而可靠的功能模块来构建整体方案 。 但是当这些小的 , 可重用的部分多来越多的时候 , 又会出现新的问题 。 再相似的阶段 , 人们遇到的问题也是相似的 , 这个时候人们需要一些共识 , 需要用一些通用的词汇来描述问题以及解决方案 , 这也是人们知识的总结 , 微服务模式就是这样的总结和概括 , 是一种可以通用的共识 , 用于描述微服务领域的中的问题及解决方案 。
单体结构的历程在企业发展的初期 , 应用程序相对较小 , 所有的代码运行在一个应用程序中有以下好处
应用的开发很简单:IDE和其他开发工具只需要构建这一个单独的应用程序 。 易于对应用程序进行大规模的更改:可以更改代码和数据库模式 , 然后构建和部署 。 测试相对简单直观:开发者只需要写几个端到端的测试 , 启动应用程序 , 调用RESTAPI , 然后使用Selenium这样的工具测试用户界面 。 部署简单明了:开发者唯一需要做的 , 就是把WAR文件复制到安装了Tomcat的服务器上 。 横向扩展不费吹灰之力:FTGO可以运行多个实例 , 由一个负载均衡器进行调度 。不幸的是 , 开发人员已经意识到的 , 单体架构存在着巨大的局限性 。 每一次开发冲刺(Sprint) , 开发团队就会实现更多的功能 , 显然这会导致代码库膨胀 。 而且 , 随着公司的成功 , 研发团队的规模不断壮大 。 代码库规模变大的同时 , 团队的管理成本也不断提高 。
今天 , 针对大型复杂应用的开发 , 越来越多的共识趋向于考虑使用微服务架构 。 但微服务到底是什么?不幸的是 , 微服务这个叫法本身暗示和强调了尺寸 。 针对微服务架构有多种定义 。 有些仅仅是在字面意义上做了定义:服务应该是微小的不超过100行代码 , 等等 。 另外有些定义要求服务的开发周期必须被限制在两周之内 。 曾在Netflix工作的著名架构师AdrianCockcroft把微服务架构定义为面向服务的架构 , 它们由松耦合和具有边界上下文的元素组成 。 这个定义不错 , 但仍旧有些复杂难懂 。 立方体模型会是更好的定义 。
扩展立方体和服务 微服务架构的好处和弊端优点大型的复杂应用程序可以持续交付和持续部署拥有持续交付和持续部署所需要的可测试性 。 自动化测试是持续交付和持续部署的一个重要环节 。 因为每一个服务都相对较小 , 编写和执行自动化测试变得很容易 。 因此 , 应用程序的bug也就更少 。 拥有持续交付和持续部署所需要的可部署性 。 每个服务都可以独立于其他服务进行部署 。 如果负责服务的开发人员需要部署对该服务的更改 , 他们不需要与其他开发人员协调就可以进行 。 因此 , 将更改频繁部署到生产中要容易得多使开发团队能够自主且松散耦合 。 你可以将工程组织构建为一个小型(例如 , 两个比萨)团队的集合 。 每个团队全权负责一个或多个相关服务的开发和部署 。 每个团队可以独立于所有其他团队开发、部署和扩展他们的服务 。 结果 , 开发的速度变得更快每个服务都相对较小并容易维护微服务架构的另一个好处在于:相比之下每个服务都比较小 。 开发者更容易理解服务中的代码 。 较小规模的代码库不会把IDE等开发工具拖慢 , 这样可以提升开发者的工作效率 。 服务的启动速度也比大型的单体应用快得多 , 千万别小看这一点 , 快速启动的服务会提高效率 , 加速研发(提高调试、部署等环节的效率) 。
更好的容错性微服务架构也可以实现更好的故障隔离 。 例如 , 某个服务中的内存泄漏不会影响其他服务 。 其他服务仍旧可以正常地响应请求 。 相比之下 , 单体架构中的一个故障组件往往会拖垮整个系统
更容易实验和采纳新的技术原则上 , 当开发一个新的服务时 , 开发者可以自由选择适用于这个服务的任何语言和框架 。 当然 , 很多公司对此往往有各种限制和规范 , 但重要的是团队有了选择的权利 , 而不是被之前选定的技术绑架 。 更进一步 , 因为服务都相对比较小 , 使用更好的编程语言和技术来重写一项服务变得有可能 。 这也意味着 , 如果对一项新技术的尝试以失败而告终 , 我们可以直接丢弃这部分工作而不至于给整个应用带来失败的风险 。 这跟单体架构是完全不同的 , 单体架构之下的技术选型会严重限制后期新技术的尝试
弊端当然 , 没有一项技术可以被称为“银弹” 。 微服务架构也存在一些显著的弊端和问题微服务架构的主要弊端和问题如下:
服务的拆分和定义是一项挑战采用微服务架构首当其冲的问题 , 就是根本没有一个具体的、良好定义的算法可以完成服务的拆分工作 。 与软件开发一样 , 服务的拆分和定义更像是一门艺术 。 更糟糕的是 , 如果对系统的服务拆分出现了偏差 , 你很有可能会构建出一个分布式的单体应用:一个包含了一大堆互相之间紧耦合的服务 , 却又必须部署在一起的所谓分布式系统 。 这将会把单体架构和微服务架构两者的弊端集于一身 。
分布式系统带来的各种复杂性使用微服务架构的另一个问题是开发人员必须处理创建分布式系统的额外复杂性 。 服务必须使用进程间通信机制 。 这比简单的方法调用更复杂 。 此外 , 必须设计服务来处理局部故障 , 并处理远程服务不可用或出现高延迟的各种情况 。
开发者需要思考到底应该在应用的什么阶段使用微服务架构使用微服务架构的另一个问题是决定在应用程序生命周期的哪个阶段开始使用这种架构 。 在开发应用程序的第一个版本时 , 你通常不会遇到需要微服务架构才能解决的问题 。 此外 , 使用精心设计的分布式架构将减缓开发速度 。 这对初创公司来说可能是得不偿失的 , 其中最大的问题通常是在快速发展业务模型和维护一个优雅的应用架构之间的取舍 。 微服务架构使得项目开始阶段的快速迭代变得非常困难 。 初创公司几乎肯定应该从单体的应用程序开始 。 但是稍后 , 当问题变为如何处理复杂性时 , 那就是将应用程序功能性地分解为一组服务的时候了 。 由于盘根错节的依赖关系 , 你会发现重构很困难
服务的拆分策略如何定义一个微服务架构呢?跟所有的软件开发过程一样 , 一开始我们需要拿到领域专家或者现有应用的需求文档 。 跟所有的软件开发一样 , 定义架构也是一项艺术而非技术 。 本节我们将介绍一种定义应用程序架构的三步式流程
定义其架构的第一步是将应用程序的需求提炼为各种关键请求 。 但是 , 不是根据特定的进程间通信技术(如REST或消息)来描述这些请求 , 而是使用更抽象的系统操作这个概念 。 系统操作(systemoperation)是应用程序必须处理的请求的一种抽象描述 。 它既可以是更新数据的命令 , 也可以是检索数据的查询 。 每个命令的行为都是根据抽象领域模型定义的 , 抽象领域模型也是从需求中派生出来的 。 系统操作是描述服务之间协作方式的架构场景
GivenaconsumerAndarestaurantAndadeliveryaddress/timethatcanbeservedbythatrestaurantAndanordertotalthatmeetstherestaurant'sorderminimumWhentheconsumerplacesanorderfortherestaurantThenconsumer'screditcardisauthorizedAndanorderiscreatedinthePENDING_ACCEPTANCEstateAndtheorderisassociatedwiththeconsumerAndtheorderisassociatedwiththerestaurant在这个用户场景中的名词 , 如Consumer、Order、Restaurant和CreditCard , 暗示了这些类都是需要的
【干货速来!透彻剖析微服务架构设计模式,深入开发Java有奇效】同样 , AcceptOrder用户故事也可以分解为多个场景 , 如下
GivenanorderthatisinthePENDING_ACCEPTANCEstateandacourierthatisavailabletodelivertheorderWhenarestaurantacceptsanorderwithapromisetopreparebyaparticulartimeThenthestateoftheorderischangedtoACCEPTEDAndtheorder'spromiseByTimeisupdatedtothepromisedtimeAndthecourierisassignedtodelivertheorder经过分析最终我们可以得出如下的类图结构
Consumer:下订单的用户 。 Order:用户下的订单 , 它用来描述订单并跟踪状态 。 OrderLineItem:Order中的一个条目 。 DeliveryInfo:送餐的时间和地址 。 Restaurant:为用户准备生产订单的餐馆 , 同时也要发起送货 。 MenuItem:餐馆菜单上的一个条目 。 Courier:送餐员负责把订单送到用户手里 。 可跟踪送餐员的可用性和他们的位置 。 Address:Consumer或Restaurant的地址 。 Location:Courier当前的位置 , 用经纬度表示定义系统操作当定义了抽象的领域模型之后 , 接下来就要识别系统必须处理的各种请求 。 我们并不讨论具体的用户界面 , 但是你能够想象在每一个用户场景下 , 前端的用户界面向后端的业务逻辑发出请求 , 后端的业务逻辑进行数据的获取和处理
识别系统指令的切入点是分析用户故事和场景中的动词 。 例如PlaceOrder用户故事 , 它非常明确地告诉我们 , 这个系统必须提供一个CreateOrder操作 。 很多用户故事都会直接对应或映射为系统命令 。 表2-1列出了一些关键的系统命令
抽象的领域模型和系统操作能够回答这个应用“做什么”这一问题 。 这有助于推动应用程序的架构设计 。 每一个系统操作的行为都通过领域模型的方式来描述 。 每一个重要的系统操作都对应着架构层面的一个重大场景 , 是架构中需要详细描述和特别考虑的地方 。 现在我们来看看如何定义应用程序的微服务架构
系统操作被定义后 , 下一步就是完成应用服务的识别 。 如之前提到的 , 这并不是一个机械化的流程 , 相反 , 有多种拆分策略可供选择 。 每一种都是从一个侧面来解决问题 , 并且使用它们独有的一些术语 。 但是殊途同归 , 这些策略的结果都是一样的:一个包含若干服务的架构 , 这样的架构是以业务而不是技术概念为中心
根据业务能力进行服务拆分创建微服务架构的策略之一就是采用业务能力进行服务拆分 。 业务能力是一个来自于业务架构建模的术语 。 业务能力是指一些能够为公司(或组织)产生价值的商业活动 。 特定业务的业务能力取决于这个业务的类型 。 例如 , 保险公司业务能力通常包括承保、理赔管理、账务和合规等 。 在线商店的业务能力包括:订单管理、库存管理和发货组织的业务能力通常是指这个组织的业务是做什么 , 它们通常都是稳定的 。 与之相反 , 组织采用何种方式来实现它的业务能力 , 是随着时间不断变化的 。 这个准则在今天尤其明显 , 很多新技术在被快速采用 , 商业流程的自动化程度越来越高 。 例如 , 不久之前你还通过把支票交给银行柜员的方式来兑现支票 , 现在很多ATM机都支持直接兑现支票 , 而今 , 人们甚至可以使用智能手机拍照的方式来兑现支票 。 正如你所见 , “兑现支票”这个业务能力是稳定不变的 , 但是这个能力的实现方式正在发生戏剧性的变化
从业务能力到服务一旦确定了业务能力 , 就可以为每个能力或相关能力组定义服务 。 下图显示了FTGO应用程序从能力到服务的映射 。 某些顶级能力(如会计记账能力)将映射到服务 。 在其他情况下 , 子能力映射到服务
根据子域进行服务拆分领域驱动设计是构建复杂软件的方法论 , 这些软件通常都以面向对象和领域模型为核心 。 领域模型以解决具体问题的方式包含了一个领域内的知识 。 它定义了当前领域相关团队的词汇表 , DDD也称之为通用语言(Ubiquitouslanguage) 。 领域模型会被紧密地映射到应用的设计和实现环节 。 在微服务架构的设计层面 , DDD有两个特别重要的概念 , 子域和限界上下文领域驱动为每一个子域定义单独的领域模型 。 子域是领域的一部分 , 领域是DDD中用来描述应用程序问题域的一个术语 。 识别子域的方式跟识别业务能力一样:分析业务并识别业务的不同专业领域 , 分析产出的子域定义结果也会跟业务能力非常接近 。 FTGO的子域包括:订单获取、订单管理、餐馆管理、送餐和会计 。 正如你所见:这些子域跟我们之前定义的业务能力非常接近 。 DDD把领域模型的边界称为限界上下文(boundedcontext) 。 限界上下文包括实现这个模型的代码集合 。 当使用微服务架构时 , 每一个限界上下文对应一个或者一组服务 。 换一种说法 , 我们可以通过DDD的方式定义子域 , 并把子域对应为每一个服务 , 这样就完成了微服务架构的设计工作 。 图2-9展示了子域和服务之间的映射 , 每一个子域都有属于它们自己的领域模型 。
上帝类的处理上帝类是在整个应用程序中使用的全局类 。 上帝类通常为应用程序的许多不同方面实现业务逻辑 。 它有大量字段映射到具有许多列的数据库表 。 大多数应用程序至少有一个这样的上帝类 。 Order类是FTGO应用程序中上帝类的一个很好的例子 。 这并不奇怪:毕竟FTGO的目的是向客户提供食品订单 。 系统的大多数部分都涉及订单 。 如果FTGO应用程序具有单个领域模型 , 则Order类将是一个非常大的类 。 它将具有与应用程序的许多不同部分相对应的状态和行为 。 下图显示了使用传统建模技术创建的Order类的结构
一种解决方案是将Order类打包到库中并创建一个中央Order数据库 。 处理订单的所有服务都使用此库并访问访问数据库 。 这种方法的问题在于它违反了微服务架构的一个关键原则 , 并导致我们特别不愿意看到的紧耦合 。 例如 , 对Order模式的任何更改都要求其他开发团队同步更新和重新编译他们的代码 。
另一种解决方案是将Order数据库封装在OrderService中 , 该服务由其他服务调用以检索和更新订单 。 该设计的问题在于这样的一个OrderService将成为一个纯数据服务 , 成为包含很少或没有业务逻辑的贫血领域模型(anemicdomainmodel) 。 这两种解决方案都没有吸引力 , 但幸运的是 , DDD提供了一个好的解决方案 。
更好的方法是应用DDD并将每个服务视为具有自己的领域模型的单独子域 。 这意味着FTGO应用程序中与订单有关的每个服务都有自己的领域模型及其对应的Order类的版本 。 DeliveryService是多领域模型的一个很好的例子 。 如图2-11所示为Order , 它非常简单:取餐地址、取餐时间、送餐地址和送餐时间 。 此外 , DeliveryService使用更合适的Delivery名称 , 而不是称之为Order 。 DeliveryService对订单的任何其他属性不感兴趣
以上就是小编整理的微服务架构设计模式 , 有哪里不准确的 , 请各位朋友多多指出 , 小编和大家一起共同学习进步~~~
喜欢请点赞评论转发 , 关注小编 , 后续小编会带来更丰富的学习内容更新~~~


    推荐阅读