SOA、REST 和六边形架构

SOA、REST 和六边形架构

上一篇:《IDDD 实现领域驱动设计-架构之经典分层

阅读目录:

  1. SOA-面向服务架构
  2. REST 与 RESTful
    1. 资源(Resources)
    2. 状态(State)
  3. 六边形架构

DDD 的一大好处就是并不需要使用特定的架构,经典分层架构只是一种,由于核心域位于限界上下文中,我们可以使用多种风格的架构,既然如此,我们应该把眼界看的更宽广些,有意思的东西多着呢。

SOA 和 REST 这两个货,我们都比较熟悉,他俩并不是由 DDD 引入,但却可以适用于 DDD。我个人觉得,要想把他俩发挥好,最好结合六边形架构(也可以称之为端口和适配器),至于原因,请接着往下看。



很重要的一张图,摘自:《实现领域驱动设计 P111》

1. SOA-面向服务架构

SOA(Service-Oriented Architecture),我没用过这货,下面说一下自己对于它的认识,可能不是很准确。

Service 意为服务,面向服务,也就是在 SOA 架构中,服务是核心。业务系统中分布着大量的业务模块,这些业务模块进一步提炼就是服务,然后通过规定的服务契约发布出来,这些服务集合起来就是 SOA 的核心,服务调用者可以是多样的,Web 端、移动端、桌面端都可以,也就是说它是分布式的架构,这些服务调用者调用的时候,要遵守发布者规定的一些契约和协议,而在服务本身或者之间也需要一定的契约和协议用来约束,要不然整个服务集合就会乱套,比如服务发布协议要有统一的规范,不能说一个服务是一个规范,服务之间也需要进行抽象抽离,尽可能的做到重用性等等。

因为我没用过 SOA,所以有些东西表达不出来,我用另一种概念去试着理解它,那就是 OWIN,他们可能不是一个领域的概念,但我觉得有些东西都是共通的,我们都知道 OWIN 体系结构中,有四大模块:Host、Server、Middleware 和 Application,他们之间最重要的一点就是组件化,并且任何一种模块都不依赖于彼此的任何一方,这就是自治,一种模块也构建不成 OWIN 的概念,这就是模块组合,一种模块的任意实现,都可以组合成整个 OWIN,原因是什么?因为他们彼此都遵守 OWIN 请求处理管道的协议。

回到 SOA 上面,你会发现,他们的概念其实是共通的,夏天到了,出去游玩,走着走着口渴了,我们就在路边买一个巨大的椰子,然后蜂拥而至一大堆基友,他们人手拿着一个吸管,而且种类和颜色各不相同,然后你的椰子上插满了各种习惯,看起来就像一个刺猬一样,你最后的下场可能就只有用刀划开个口子喝了,不管是用吸管,还是用到划开个口子,我们最后的目的都是喝椰子汁,只是使用的工具不同,一个椰子可能里面的汁更好喝,外面的更难喝。在这个日常生活示例中,一个椰子可以看作是一个 SOA 架构,内部就是各种小的服务(可以看作是一块一块的椰子肉,里面的更好吃),各种各样的吸管和刀子可以看作是服务调用者,而椰子皮也可以看作是服务协议,因为椰子汁需要椰子皮的包裹才不会洒出来。

SOA 架构原则:

  • 服务封装
  • 服务松耦合(Loosely coupled)- 服务之间的关系最小化,只是互相知道。
  • 服务契约 - 服务按照服务描述文档所定义的服务契约行事。
  • 服务抽象 - 除了服务契约中所描述的内容,服务将对外部隐藏逻辑。
  • 服务的重用性 - 将逻辑分布在不同的服务中,以提高服务的重用性。
  • 服务的可组合性 - 一组服务可以协调工作并组合起来形成一个组合服务。
  • 服务自治 – 服务对所封装的逻辑具有控制权
  • 服务无状态 – 服务将一个活动所需保存的资讯最小化。
  • 服务的可被发现性 – 服务需要对外部提供描述资讯,这样可以通过现有的发现机制发现并访问这些服务。

SOA 相关资料:

2. REST 与 RESTful

RESTful 架构概念,是 Fielding 提出的,Fielding 这号人物就是 HTTP 协议的主要设计者之一。我们先看下 RESTful 这个词,ful 是跟在名词之后,表示程度,什么什么的,例如 helpful 乐于助人的,因此我们可以看出符合 REST 的架构就可以称为 RESTful,接着我们看下 REST,全称为“Representational State Transfer”,意为“表现层状态转化”。

在符合架构原理的前提下,理解和评估以网络为基础的应用软件的架构设计,得到一个功能强、性能好、适宜通信的架构。  -Fielding

这是 Fielding 在论文中所提到的,对于 REST 虽说是架构,但如果深入一点,就像是 HTTP 协议一样,可以看成一种规则或是协议。我们从一个地点到另一个地点,可以坐汽车、高铁、飞机等,对于 REST 就像是其中的一种交通方式,但 REST 的根本是 HTTP 协议,也就是说 REST 是基于 HTTP 协议的,这点就像坐汽车必须要有公路,坐高铁必须要有铁路是一样的道理,有时候为什么选用 REST,就像我们从南京到徐州,选择坐高铁而不选择坐飞机一样。

“Representational State Transfer”我们分解下:

  • Representational 表现层:表现层表现什么,应该呈现资源(Resources),一个图片、一段文字、一个文件都成为资源,每个资源都用一个 URI(统一资源定位符)指向它,表现层就是调用 URI 把资源呈现出来,而且只是呈现,不做其他操作。举个例子:有些网址最后的".html"后缀名是不必要的,因为这个后缀名表示格式,属于"表现层"范畴,而 URI 应该只代表"资源"的位置。它的具体表现形式,应该在 HTTP 请求的头信息中用 Accept 和 Content-Type 字段指定,这两个字段才是对"表现层"的描述。
  • State Transfer 状态转化:访问一个网站,就表示客户端和服务器发生一次交互行为,在这个过程中,就不发生数据和状态的转化,上面说到 HTTP 协议具有无状态性,如果客户端操作服务器,必须要状态转化,这个体现在表现层上,所以叫“表现层状态转化”。

通过上面的理解,可以总结下什么是 RESTful 架构:

  • 每一个 URI 代表一种资源。
  • 客户端和服务器之间,传递这种资源的某种表现层。
  • 客户端通过四个 HTTP 动词(PUT、GET、POST 和 DELETE),对服务器端资源进行操作,实现"表现层状态转化"。


上面 REST 和 RESTful 的概念,摘自很久之前的一篇博文:初试ASP.NET Web API/MVC API(附Demo),并做了部分修改。

我再来说一下自己现在的理解,首先,REST 是一种架构风格,而不是一种架构,一种架构风格可以用多种架构进行实现,一个架构中也可能包含多种架构风格,这两者的关系,你可以理解为抽象和实现的区别,另外,REST 严格来说,应该属于 Web 架构的一种架构风格,因为它离不开 HTTP 协议。

REST 架构风格的两个关键:

2.1 资源(Resources)

Web 资源的表述是 URI,一个规范的 URI 就是开放出来的一个资源,它是唯一并具有一定的规范,对资源的操作方式就是 HTTP 提供的方法(PUT、GET、POST 和 DELETE),资源的表现形式是多样的,比如:JSON、XML、YAML 等。

我们看一下常用的 URI:

  • GET: cnblogs.com/getUser/1
  • POST: cnblogs.com/createUser
  • PUT: cnblogs.com/updateUser/1
  • DELETE: cnblogs.com/deleteUser/1

很显然,这种 URI 不符合 REST 对资源的定义,我们尝试修改一下:

  • GET: cnblogs.com/user/1
  • POST: cnblogs.com/user
  • PUT: cnblogs.com/user/1
  • DELETE: cnblogs.com/user/1

cnblogs.com/user/1,这个 URI 一般表述的含义是:Id 为 1 的 User 资源,这个仅仅是表述,URI 并不包含对这个资源的任何操作,所以,像 getUser、createUser 这类操作就不合适,资源的操作是通过 HTTP 提供的方法,还有一点是,比如 POST 中的cnblogs.com/user 和 cnblogs.com/user/1 有什么不同?第一种 POST,一般是创建一个新的 User 资源,创建完成后,一般会返回这样的一个 URI:cnblogs.com/user/1,第二种 POST,不是说创建一个 Id 为 1 的 User 资源,而是在 Id 为 1 的 User 资源下创建某种资源,你会发现,好的 URI 设计应该不包含动词。

2.2 状态(State)

首先,REST 是无状态的(Statelessness),我之前是一直不理解状态的含义,好像还把状态和资源格式(XML、JSON)混为一谈,现在想想确实太荒谬了,关于状态的几个要点:

  • 状态分为:应用状态(Application State)和资源状态(Resource State)。
  • 应用状态:与某一特定请求相关的状态信息。
  • 资源状态:反映了某一存储在服务器端资源在某一时刻的特定状态。
  • 客户端负责维护应用状态,而服务端维护资源状态。
  • 服务器端不保有任何与特定 HTTP 请求相关的资源。

REST 中的无状态其实指的是应用状态,无状态的表现是服务端不保存应用状态,也就是客户端发起与请求相关的状态,应用状态是客户端在发起请求时提供的,那状态转化是什么意思?其实指的是服务端资源状态的转化,表现在客户端中,也就是上面所说的“表现状态转化”。

在 ASP.NET 应用程序中,我们都知道 Session 的概念,意为会话,也就是有关用户请求的会话,应该划分为应用状态,这个会话状态是保存在服务端的,从这一点上来说,这种设计就是 unRESTful 风格,REST 中的无状态,是客户端和服务端交互中所表达的一种概念,有时候,虽然应用状态可能不保存在服务端,但客户端发起的某些请求所表达的含义不恰当,也可以认为是不符合 RESTful 风格,比如客户端发起的请求中包含 Session ID,在服务端看来,客户端发起的这个请求,所表达的含义是要获取某个 Session,具体来说就是会话状态保存在服务端,这个虽然只是一个客户端请求的概念,但也可以认为这种设计是 unRESTful 风格。

总的来说,架构风格不是某一种具体架构,它是一种风格。

REST 参考资料:

3. 六边形架构

上面有关 SOA、REST 的讲述,丝毫没有 DDD 的半点影子,它们并不是为 DDD 而生,在架构设计的时候,你也可以单独使用它们,但对于整体 DDD 架构设计来说,总觉得会有些不对劲,这时候,就需要了解下六边形架构。

六边形架构(Hexagonal Architecture),又称为端口和适配器架构风格,其中的“六”具体数字没有特殊的含义,仅仅表示一个“量级”的意思,六边形的定义只是方便更加形象的理解。

我们知道分层架构的重要作用就是避免耦合的出现,经典分层架构和六边形架构都是分层架构的一种,但是所发挥的作用会有些不同,经典分层架构更多的精力放在抽象的分离上,每个层的职责分的很明确,各个层的依赖关系更加抽象化,从而避免耦合的出现,而在六边形架构中,是用“组件化”的形式来避免耦合的出现,每个业务单元尽可能的最小化,然后把这些业务组件集合起来,用一个锤子把他们都拍扁,所以,在整个集合中,这些小的业务单元都是“平等的”,这种方式用一个词来概括,那就是“扁平化”。

在博文一开始的时候,说过这样一句话:由于核心域位于限界上下文中,我们可以使用多种风格的架构。

那为什么核心域位于限界上下文中,DDD 就可以使用多种风格的架构?我们来分析一下,核心域指的是业务系统中的核心业务逻辑,这个通常用通用语言表述,限界上下文是一种边界,它包裹的是核心域,也就是说,核心域并不是组件化的形式表现,你可以把它看作是一种聚合概念,用限界上下文来进行限定,这个概念在之前的博文中有说明。对于业务系统来说,核心域毫无疑问是核心概念,DDD 的专注点也就是它,开发人员和领域专家会花大量的时间去探讨它,但对于架构设计来说,核心域只是业务上的专注点,并非是架构设计上的核心点,所以,也可以这样说,DDD 和架构设计,其实严格来说应该是两个领域方面的概念,他们的结合才真正构成整体的业务系统,换句话说,最烂的架构设计配上最好的 DDD(业务上的),这也是可以的,因为 DDD 专注的是业务实现,而并非是技术实现。

我们知道,经典分层架构分为四层,而对于六边形架构,一般会分成三层:

  • 领域层(Domain Layer):最里面,纯粹的核心业务逻辑,一般不包含任何技术实现或引用。
  • 端口层(Ports Layer):领域层之外,负责接收与用例相关的所有请求,这些请求负责在领域层中协调工作。端口层在端口内部作为领域层的边界,在端口外部则扮演了外部实体的角色。
  • 适配器层(Adapters Layer):端口层之外,负责以某种格式接收输入、及产生输出。比如,对于 HTTP 用户请求,适配器会将转换为对领域层的调用,并将领域层传回的响应进行封送,通过 HTTP 传回调用客户端。在适配器层不存在领域逻辑,它的唯一职责就是在外部世界与领域层之间进行技术性的转换。适配器能够与端口的某个协议相关联并使用该端口,多个适配器可以使用同一个端口,在切换到某种新的用户界面时,可以让新界面与老界面同时使用相同的端口。

在六边形架构中,领域层和技术没半毛钱关系,可以看作是业务的技术实现,端口层包裹在领域层在外,外部要向和领域层“交流”,则必须通过端口层的“首肯”,反过来,领域层向外面“交流”也是一样,但这种方式一般是技术上的,比如领域对象的管理:

领域层想要获取某一个领域对象,来进行业务操作实现,然后告诉端口层说:“端口小弟,哥需要一个 XXX Domain Model,立马去叫人搞!”,端口小弟心想,老大发话了,得赶紧的啊,然后就在自己胸前,贴出了这样一段告示:能逮到 XXX Domain Model 的适配器杀手们,请速速到俺这里,必有重赏!告示一贴出,适配器杀手们蜂拥而至,然后根据自己的能力来进行判断,毕竟 XXX Domain Model 也不是那么容易擒服,也不是随便一个适配器杀手就能搞定的,这需要一定的能力,最后能做的适配器杀手进行揭此告示。

以上是即兴想到的一个情节,其实就是六边形架构,从内到外的一个过程体现,反过来,从适配器层到领域层也一样,这种方式一般是接受用户请求处理开始。其实,从某种意义上来说,端口层有点像应用层,只不过是拍扁之后的应用层,而适配器层有点像基础设施层,只不过是全能型的基础设施层,六边形是环形结构,所以表述起来更加形象。

还有一点是,端口层的存在,还有利于测试的进行,这些测试不是在领域层进行的,所以它丝毫不会影响领域层的进度,对于端口层的测试,一般是测试领域层中业务的正确性。

以上是六边形架构的一些概念,那再结合 SOA 和 REST,该如何实现呢?因为在六边形架构中,适配器层是以组件性质的方式提供服务,他和领域层进行联系要通过端口层,这个端口层可以看作是服务的一种协议或规范,这就是 SOA 和 REST 的用武之地,来扮演适配器层和端口层的角色。还有一个概念不同点是,服务交互分为服务端和客户端,对于 SOA 和 REST 本身来说,他们的实现就是服务端,但在六边形架构中,他们更像是一个客户端,并且表现形式是组件化的服务,而领域层是服务端,通过端口协议来调用组件服务提供一些操作实现。

SOA、REST 和六边形架构的结合,可以和一开始的那张图进行对比:

说明:本图摘自:《实现领域驱动设计 P115》

参考资料:



距离上一篇有很长的一段时间了,经典分层架构我是用过的,所以会有很多的感触,也有很多的文字需要表达,但对于 SOA、REST 和六边形架构,我并没有真正实质性的用过,所以,对于一个你不曾接触的概念,要把一些东西写出来是很难的,写不出来,那就看书、看文章、找资料,把有些有感触的文字记录下来,然后通过自己的理解再表达出来,这种方式过程虽然很慢,但还是有一定的效果。

关于 DDD 架构设计,还有很多很多的内容,比如 CQRS、事件驱动架构、网格分布式计算等等,这个需要时间来消化。

因为没有实践过,所以难免会有一些问题,还请大家斧正!!!

时间: 2024-11-18 13:45:10

SOA、REST 和六边形架构的相关文章

SOA和微服务架构的区别?

知乎用户 289 人赞同了该回答 谢多人邀请,其实前面几位的回答已经差不多了,在这里仅谈下自己的简单总结. 微服务架构强调的第一个重点就是业务系统需要彻底的组件化和服务化,原有的单个业务系统会拆分为多个可以独立开发,设计,运行和运维的小应用.这些小应用之间通过服务完成交互和集成.每个小应用从前端web ui,到控制层,逻辑层,数据库访问,数据库都完全是独立的一套.在这里我们不用组件而用小应用这个词更加合适,每个小应用除了完成自身本身的业务功能外,重点就是还需要消费外部其它应用暴露的服务,同时自身

SOA和微服务架构的区别

微服务架构强调的第一个重点就是业务系统需要彻底的组件化和服务化,原有的单个业务系统会拆分为多个可以独立开发,设计,运行和运维的小应用.这些小应用之间通过服务完成交互和集成.每个小应用从前端web ui,到控制层,逻辑层,数据库访问,数据库都完全是独立的一套.在这里我们不用组件而用小应用这个词更加合适,每个小应用除了完成自身本身的业务功能外,重点就是还需要消费外部其它应用暴露的服务,同时自身也将自身的能力朝外部发布为服务. 如果一句话来谈SOA和微服务的区别,即微服务不再强调传统SOA架构里面比较

六边形架构设计

分层架构是运用最为广泛的架构模式,把一个软件系统进行分层,是我们目前做工程项目的一个共识,我们最初学习的分层架构就是经典的三层架构了.它自顶向下分成三层: 用户界面层(User Interface Layer) 业务逻辑层(Business Logic Layer) 数据访问层(Data Access Layer) 在传统的单体应用中,因为业务不算复杂,这种分层并没有什么问题,把数据的渲染交给用户界面层,把核心业务逻辑放到业务逻辑层,然后将数据库的访问交给数据访问层. 但是随着业务越来越复杂,问

MVC、RPC、SOA、微服务架构之间的区别

MVC.RPC.SOA.微服务架构之间的区别 一.MVC架构 其实MVC架构就是一个单体架构. 代表技术:Struts2.springMVC.Spring.Mybatis 等等. 二.RPC架构 RPC(Remote Procedure Call)远程过程调用,他是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议. 代表技术:Thrift.Hessian等等. 三.SOA架构 SOA(Service Oriented Architecture)面向服务架构. ESB(Ent

SOA 面向服务的架构

定义 面向服务的架构(SOA,Service-Oriented Architecture)是一个组件“模式” (或 “思想”,它不是一种“技术”),它将应用程序的不同功能单元(称为服务)进行拆分,并通过这些服务之间定义良好的接口和协议联系起来.接口是采用中立的方式进行定义的,它应该独立于实现服务的硬件平台.操作系统和编程语言.这使得构件在各种各样的系统中的服务可以以一种统一和通用的方式进行交互. SOA vs Web服务 在理解SOA和Web服务的关系上,经常发生混淆.根据2003年4月的Gar

IDDD 实现领域驱动设计-SOA、REST 和六边形架构

http://www.italki.com/question/293028http://www.italki.com/question/293027http://www.italki.com/question/293026http://www.italki.com/question/293025http://www.italki.com/question/293024http://www.italki.com/question/293023http://www.italki.com/questi

SOA面向服务的架构理解

?  单一应用架构 ·当网站流量很小时,只需一个应用,将所有功能都部署在一起,以减少部署节点和成本. ?  垂直应用架构 当访问量逐渐增大,单一应用增加机器带来的加速度越来越小,将应用拆成互不相干的几个应用,以提升效率. ?  分布式服务架构 ·当垂直应用越来越多,应用之间交互不可避免,将核心业务抽取出来,作为独立的服务,逐渐形成稳定的服务中心,使前端应用能更快速的响应多变的市场需求. ?  流动计算架构 当服务越来越多,容量的评估,小服务资源的浪费等问题逐渐显现,此时需增加一个调度中心基于访问

SOA: UBER工程代码架构的拓展和演变SERVICE-ORIENTED ARCHITECTURE: SCALING THE UBER ENGINEERING CODEBASE AS WE GROW

像很多初创型公司一样,Uber的架构一开始也是一整块的,或者说是整体的.不可分割的,服务端部署在一个城市,对外整体上是单个节点.这个也迎合了当时服务范围和功能选项有限的业务场景.可执行代码部署在单个节点,对于这种场景下,可以说是简洁.易管理的,而且直接上来说,满足了我们的业务需求:简单的连接司机和乘客,出账单,支付.在这种"小而美"的场景下,将Uber的这些简单的业务逻辑放在一起,也是很有道理.很有实际操作性.很有性价比的:).但是,当我们的业务迅速拓展到多个城市,并且产品也不再那么单

SOA面向服务化编程架构(dubbo)

  dubbo 是阿里系的技术.并非淘宝系的技术啦,淘宝系的分布式服务治理框架式HSF啦 ,只闻其声,不能见其物.而dubbo是阿里开源的一个SOA服务治理解决方案,dubbo本身 集成了监控中心,注册中心,负载集群...等等.代码和整体的框架还是很优雅滴呀! github地址 https://github.com/alibaba/dubbo 文档地址:http://alibaba.github.io/dubbo-doc-static/Developer+Guide-zh.htm 目前发布的版本