“纯天然”的微服务架构

从分层架构到六边形架构

在计算机领域很多概念都是抽象的,为了能够清晰地划分这些抽象的复杂概念,随处可见各种分层式的设计方式。比如计算网路的七层通信协议,把复杂的网络通信划分成更容易管理的层,明确定义各层的职责范围,各层都可以采用最合适的技术来实现。当任何一层发生变化时,只要层间接口关系保持不变,则在这层以上或以下各层均不受影响。

在常见的软件系统的架构中也有一种4层架构设计,通常从前到后会划成:用户接口层,应用层,领域层,基础设施层。


-w300
  • 用户接口层只需要关注如何同使用者打交道,不需要关注核心的业务逻辑,例如把用户提交的数据经过转码处理后提供给应用层。
  • 应用层的关注点是如何组装核心的领域层来提供复杂的组合服务,例如应用层可以从领域层的用户仓库获取用户信息,从领域层的订单仓库获取订单信息,然后在应用层把用户信息和订单信息组装在一起返回给用户接口层
  • 领域层处理的业务问题,是更加内聚的领域业务,不同业务之间要做到低耦合。例如在用户聚合中就只处理用户相关的逻辑,不应该包含订单,支付这些其它的业务逻辑。
  • 基础设施层是不包含任何业务逻辑的底层支持,例如生成pdf或者excel,或者把数据持久化到数据库的ORM框架

但是这样的分层架构会导致其他三层尤其是领域层对基础设施层产生依赖。这种依赖会导致当基础设施层发生变更的时候,会导致其它三层也要跟随变动,这是我们不希望放生的事情,尤其是涉及核心业务逻辑的领域层,我们不希望因为某种生成excel或者pdf的技术发生变化而要修改领域层。

那么如果考虑对基础设施进行解耦的方法,可供选择的的方式有依赖倒置,在每一层定义对应的技术接口,然后在基础设施层实现这个接口,再通过一些依赖注入框架在运行式把实现注入进来,这样就把原来其它三层依赖基础设施层的情况倒置成了基础设施层依赖其它三层了。

-w300

有趣的是,当我们在分层架构中采用依赖倒置原则时,我们会发现事实上已经不存在分层的概念了。无论高层还是低层,都只依赖于抽象的接口。如果我们这时把分层架构推平,这就是在微服务领域非常著名的六边形架构

六边形架构是Alistair Cockburn提出的,其实是把原来的分层架构转换了一下视角,从原来的上下结构变成了内外结构。六边形架构把原来一个系统的输入和输出都统一来处理,输入输出对接的都是外部系统,都需要一个适配器来进行转换。所以不论是处理输入的HTTP请求,还是处理输出的数据库存储都应该有一个适配器来负责接入。适配器会调用负责业务逻辑组合的应用层,而应用层负责调用核心的领域层。

相比于应用层,领域层通常更少变化。在这样的架构关系下,当需要修改一个负责连接数据库的ORM工具时,或者是应用层返回的订单信息需要增加物流状态时,都不需要去修改最核心的领域层。

图片来自:slideshare.net-w500

为什么是六边形

不知道大家在看到六边形架构这个名字的时候会不会产生一个疑问,就说是为什么是六边形,不是七边形,五边形。

这个问题其实困扰了我蛮久,但是当我在郑也夫老师的社会学专题50讲里面找到了答案。六边形这个概念源自于城市规划,有两个德国人,一个是克里斯塔勒,他的研究兴趣是人口密度和商品销售关系。他1933年写出一部书,叫做《德国南部中心地原理》。另外一个是廖什 ,他的兴趣在于研究空间秩序,他在1940年写出一部书叫做《经济空间秩序》。

这两个人各自独立的提出了六边形理论

每个商家销售的范围是一个圆。因为人们买东西有交通成本,所以导致着以一个卖点为中心,销售范围是围绕着这个中心画的一个圆。当人口越来越多的时候,商家也就越来越多,那个圆形越来越多,导致着一个圆形跟另一个圆形相互挤压,最后压成了一个蜂巢一样的紧密相连的正六边形的组合体。

-w400

最低级的销售点是集市,销售一些最通常的日用品,构成了最小的六边形拼凑出来的平面。稍大一点的城市会卖衣服、鞋等等中档的东西,它们就是中型的六边形。大的都市会卖一些很高档的东西,珠宝、珍贵的皮毛等等。这些大的正六边形拼凑出一个大的平面。并且在一个广大的地域中,大都市销售区是大六边形的对接,其中包含着中小六边形。

除了人类的集市,还有一种自然界的天然六边形就是蜂巢。但是你有想过这个问题吗,蜜蜂在搭建蜂巢的时候又没有测量工具,它们是怎么搭建出来比例那么标准的的六边形蜂巢的呢。
其实蜜蜂根本就不曾想过要搭建六边形,蜜蜂在搭建蜂巢的时候是按照记得身体的大小围出了圆形的一个个蜂巢,请看下图:


-w400

然后这一个个小圆经过蜂巢自己本身的拉伸和风化,就变成了六边形。蜜蜂本来就是要造圆形巢的,但是由于自然界本身的趋于稳定的焓变规则,软的圆形巢就拉成六边形了。
[图片上传失败...(image-750f2e-1541523534115)]

那么为什么圆形会被拉伸成六边形呢?阿尔法小分队有一个视频专门介绍了这个问题的数学原理(视频传送门)。在视频中用小时候经常玩的泡泡做了一个简单的实验,当四个泡泡凑仔一起的的时候,在泡泡边界上出现的所有夹角都是120度。所以当很多个泡泡挤在一起的时候,由于在拉扯力的作用下边界夹角都是120度,所以一个个泡泡就“天然的”变成了六边形。而蜂巢,人类集市是遵循这个自然规律。

-w400

回到微服务架构,虽然“六边形架构”这个概念是Alistair Cockburn创造出来的,但是由于六边形代表了自然规律,所以我认为六边形架构是“纯天然”的。而且如果我们把创建的微服务看成一个个小泡泡,那么把这些小泡泡排列在一起以后,自然法则会让他们变成一个个六边形。而不可能是五变形或者七边形。

介绍完了六边形的故事,让我们进入六边形架构的微服务内部,看看里面的代码是什么样子的。

一个六边形架构的代码结构示例

首先在一个微服务的根目录上应该只有3个包,adapter,application和domain。而且还要严格限制依赖关系:

  • domain中不可以依赖任何application和adapter中的代码
  • application中不可以依赖任何adapter中的代码
-w400

假设一个简单的场景:用户从界面提交一个支付请求,最终这个支付请求的相关信息会被存入数据库中。

接受请求这段很好实现,在adapter层里有一个controller来处理请求,把请转换成领域模型payment,然后调用application层SubmitPaymentApplication的submit方法来提交payment。然后SubmitPaymentApplication会调用domain层的PaymentRepository. 这时候会有一个麻烦的问题,通常来说Repository里面都会依赖具体的ORM工具,比如hibernate或者Mybatis。但是前面说过我们希望Domain层是不要有任何外部依赖的,所以解决这个问题的方法就是在只在domain层定义PaymentRepository的接口,然后在Adapter层使用ORM工具实现这个接口。

-w400

ORM工具是在面向对象程序中进行数据库持久化的好用工具,而且现在流行的ORM工具都提供了从数据库表到实体类的自动生成功能,让开发者尽可能的减少机械化的工作。但是这些好用的工具带来的一个问题就是实体越来越贫血,实体里面只是有一堆属性和对应的get/set方法而已。但是在六边形架构里面,由于domain层的实体不需要由ORM生成,数据库持久化相关的工作都在外面的adapter层中完成,所以开发者就可以放心的在domain中使用枚举等各种编程语言的特性,还可以在实体中放心的实现各种本来就属于实体的行为。

思辨小结

这几年由于微服务的原因六边形架构也变得热了起来。但是要真的用好六边形架构,我们需要对这个概念有一个更深入的理解:知道它是怎么提出来的?它解决的是什么问题?为什么是六条边?弄清楚了这些,在应用六边形架构的时候才能清楚地知道什么逻辑只能属于哪一层,哪一层不能依赖哪一层。坚持这些原则的价值是:当有新需求或者需求发生变更时,重用代码和修改代码都是让人愉悦的事情。

把使用ORM的数据库持久化实现放在adapter的一个可能问题是,由于domain层的实体更贴近业务,所以这些实体模型无法直接给ORM使用,这就需要在adapter里面再实现一套专门对应数据库表的对象模型出来,并在adapter里面吧domain的实体转换成这些模型再进行数据库操作。这样看起来好像会有两套冗余的业务模型,一个在domain中,一个在adapter里面。但其实只有domain中的才是真正的业务模型,adapter里面的模型只是数据库表的一个映射对象而已。这种方式很好地把领域模型和持久化相关实现进行了解耦,我们可以完全抛开数据库或者ORM的技术限制,去设计能够真正和业务对应的领域模型。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,080评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,422评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,630评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,554评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,662评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,856评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,014评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,752评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,212评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,541评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,687评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,347评论 4 331
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,973评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,777评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,006评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,406评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,576评论 2 349

推荐阅读更多精彩内容

  • 本文来自作者 未闻 在 GitChat 分享的{基于 Docker 的微服务架构实践} 前言 基于 Docker ...
    AI乔治阅读 7,264评论 0 71
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,800评论 25 707
  • 用两张图告诉你,为什么你的 App 会卡顿? - Android - 掘金 Cover 有什么料? 从这篇文章中你...
    hw1212阅读 12,699评论 2 59
  • 引言 在讨论DDD分层架构的模式之前,我们先一起回顾一下DDD和分层架构的相关知识。 DDD DDD(Domain...
    _张晓龙_阅读 160,433评论 16 193
  • 从去年开始,重新读起村上春树的作品,真的是经常心生欢喜,幸福满溢。 欢喜和幸福是因为读他的文章特别有意思,好像是一...
    安姐儿阅读 154评论 0 0