11 月 19 - 20 日 Apache Pulsar 社区年度盛会来啦,立即报名! 了解详情
写点什么

服务的技术架构之争

  • 2016-08-30
  • 本文字数:5329 字

    阅读完需:约 17 分钟

上一篇文章中,我引入了一个新的概念S++,按说我应该继续下去,但是我觉得在这之前还是要先谈谈架构,因为服务化意味着大的系统被拆小,一个人可以没有组织,但是一群人没有组织就是乌合之众了,所以服务化和架构有着密不可分的联系。本文会有三次谈架构,这次会从架构的一般逻辑来谈起,估计会有些枯燥。

架构是一种平衡手段,架构为特定的目标服务,通过平衡资源的分配从而达成有限的资源下实现特定的目标。

通常,我们做架构设计的目标是平衡空间、时间、可靠性、复杂度、可维护性、易用性、成本等等指标,选择应用更迫切需要满足的指标优先满足,同时尽可能的减少对其他指标的影响。简单说,架构就是要明确取舍。而且,我们选择的架构不能够影响应用本身的业务逻辑,也就是说架构对应用来说应该是透明的。

以上是我对架构的一些基本看法,关于架构是什么很多人都有独到的见解,我就不多谈了,另外我很喜欢郭蕾推荐给我的 Kevin 老师执笔的《架构漫谈》。本章主要探讨在面向服务的发展历程中曾经被广泛使用的几种架构的对比和特点,以便于我们去理解未来章节中我们对架构取舍的一些基本出发点。

去中心化和集中架构

SOA 发展过程中既有无中心架构,也有集中架构,前者用于互联网企业间的交互,后者在企业内部使用。

确切的讲 SOA 没有“去中心化”架构,只有“无中心化”架构。我们前面讨论了,架构是为了实现特定的目标的,而这目标源于需求和现实,那么“无中心化”架构就是 SOA 在互联网环境下的必然的架构选择。其实也没得可选,因为 SOA 要解决企业间的通过互联网相互访问的需求,而互联网是一个自由的无政府环境,根本就不存在一个共同认可的架构中心节点。两者对比如下:

其实无论是去中心还是集中架构,都是组织需要而非技术需要,需求决定技术架构。在企业内部,无论任何架构都要满足组织对管控的需求,而这种需求必须由一个统一的中心节点来提供,所以 SOA 化在组织内部大多数是以 ESB 作为基础来实现的。

架构的统一和转换

现实社会中,纯粹的自由和绝对的集权都是无法做到的,任何组织也是这样。所以绝对的去中心和绝对的集中模式都是极端架构,并不可取(只有在解决极端需求的时候才会被用到)。

事实上,分布式多中心的架构是现实社会中最为常见的,比如物流行业,没可能每个人的包裹都能从寄件人那里直接送给收件人(去中心成本不可接受),但也不可能全国只有一个物流集散中心,所以大多采用按区域分布式部署物流集散中心。同样的,比如电信、连锁、企业管理机构等等,只要是我们能想的到的协作型组织,大多都是分布式多中心架构的。

下图是一个单一中心的示意图,图中显示的是一个多语种信息交流中心的基本结构,他的作用就是帮助每一个需要交流的人,在一个平台上可以通过任意的语言和任意的通讯方式进行无障碍的交流(当然,这是一个为了方便的说明问题而虚构出来的平台,虽然目前有些社交平台提供了类似的功能)。

这样一个中心,可以是自发的产物,因为有需求,人们需要交流、需要交换物品等等。人是社会化的动物,集市这样的东西是必然的产物。那么,自然的各地都会出现这样那样的集市,多中心的架构就自然形成了,如下图每一个区域中心都具备单一中心的功能。多中心的架构是自然社会发展过程中,人们自发的一种对功能和效率平衡的一种架构。

下图是多中心架构被极端化后形成的去中心架构,去中心架构并非没有中心,因为中心节点需要完成的功能都是必须的,所以如果在不降低功能需求的情况下,去中心架构事实上是把中心的功能融合到每一个终端节点上了。对于集成架构而言,去中心架构几乎没有任何优势而言。

在我看来,在企业内部实施去中心架构,实质上去掉的不仅仅是中心,更重要的是弱化甚至去掉了企业的管控需求。在一个非极端环境下将架构极端化,那么还要架构干什么?架构还怎么起到平衡资源的作用?

剖析微服务架构

在此引用一篇文章> ,我觉得写的挺好,基本上不需要我去讲解什么是微服务了。 在此借用两幅图简单说明一下。

第一幅图展现了传统“大”服务架构下应用的开发部署模式,应用作为一个整体存在,业务对象作为应用内部的不同功能模块,不同业务对象之间通过应用内部的流程进行拼接。

微服务架构通过将原业务系统按业务对象作为基本单元进行纵向拆分,以交互层次作为标准进行横向拆分,从而形成多应用交互的微应用架构体系。

那么,其实微服务并不是什么新鲜事,至少SOA 理念中几乎包含了所有微服务的理念。本质上说,微服务“微“的并不是服务,而是应用,其实SOA 也是倡导服务系统走专业化的道路的,这我们在最开始做ESB 的时候就在推销这个概念,比如将传统核心按业务条线拆分成不同的专业系统等。相对应的,为了方便起见我们将WebServices 时代的SOA 称为“大服务”以示区别。

上述引用的文章中微服务架构推荐一个服务一个系统,事实上我们看到的是一个业务实体一个系统,这符合我们对业务系统内部用面向对象的方式进行建模的传统。当然,也是因为传统的“服务“的概念和我们的提出的服务不是相同的,这一点上微服务和大服务对服务的概念是相同的,比如引用中的”行程管理服务“其实是由针对一个业务实体的多种操作来组成的。

如果服务依然是对对象实体的抽象,那么SOA 所有这些概念不过都是在炒作,和面向对象没有任何实质上的进展和差异。事实上,我们知道WebServices 本质上就是一种远程对象,与我们熟知的Corba、COM、EJB 等几乎没有任何本质差异。如果说SOA 已死,对大服务来说SOA 就从来没活过,那不过是远程对象穿了个马甲而已;如果说微服务当立,我看不出与大服务有什么本质的差异,倒不如说微应用当立更好。

其实,当系统架构演化为微服务架构以后,系统所面临的新问题变得和微服务解决掉的问题几乎一样多:

1. “轻量化”解决方案

(纯吐槽:越来越多的人标榜自己的东西是轻量级的,我不得不吐槽一下,在我看来轻量级就是简单甚至粗糙的代名词。如果是完成同样的功能,我不相信你的能比别人的东西轻量,除非别人是傻子,你用一行代码能完成的他要用十行代码。你比他轻量,正常情况下意味着你的东西比他的功能少。)

传统 SOA 架构下,解决企业内部系统间应用交互问题主要的方式就是采用 ESB 进行连接。但在微服务架构下,由于 ESB“过重”,会导致频繁的系统间交互效率大大降低,所以微服务架构回归了去中心化的点对点调用方式。但是系统拆分带来的问题,是不是能简单的用轻量点对点通讯就能解决了呢?这个觉得这个想法有点儿朴素了。下面我们看看 ESB 为什么会这么“重”,微服务架构能否安全的绕开这些“重”的东西。

2. 安全性问题

在“大”应用拆分之前,应用的安全性是整个大应用统一考虑的,比如身份认证、权限、防篡改、防抵赖、加密等等。之所以有这些诸多的安全措施,是因为企业应用环境并非一个安全可靠的环境,内部的外部的黑客都有可能进入网络对内部系统进行攻击,尤其是内部黑客更是畅通无阻。

那么,是不是大服务拆成微服务之后,这些黑客就消失了呢?这个想法显然是无法接受的,事实上被拆分后的微服务由于维护能力和专业能力不够,使用技术杂乱等等原因,使得黑客更容易得手。

一个不设防的微服务,对于内部黑客来说,只要从浏览器模拟一个服务请求,就可以轻松的进行危险的操作。这种“轻量”我认为无异于掩耳盗铃。

3. 系统间耦合问题

“系统之间的耦合,从来没有像今天一样多”。对于微服务架构而言,原本系统内部对象之间的交互行为,被简单粗暴的暴露到系统之间来。

“我原来的代码是这样的:t.open();a.calculate(b);b.save();t.close(); 现在 a 和 b 在两个系统里面,谁能告诉我现在这段代码归谁管?”

“我这里会出错的,你们谁 call 我的,自己注意回滚操作!”

“我这个技术参数是必要的,因为我后面要调用 C 系统,这个技术参数是他要的,不要问我为什么,因为我也不知道!”

这些问题相信大家都遇到过,如果只是简单的把系统拆开,那么原本存在于系统内部的强耦合性会更加突出的表现出来,这导致微服务的应用开发并不比传统应用更简单,相反的还会引入诸如事务一致性等原来不存在的问题。

4. 系统可靠性问题

微服务架构引入了一个新的可靠性问题,当一个传统大应用的复杂业务逻辑出现问题的时候,比如一个业务 X 需要调用 A,B,C,D 四个模块的方法,由于这个业务逻辑 X 是在系统内部通过同步的 API 进行调用的,任何一个模块的错误会直接导致整个业务 X 出错,从而直接反馈给 ESB,对于 ESB 而言最简单的保证可靠性的方法就是隔离掉错误的服务 X。

但是当大服务被拆分成 4 个微应用之后,如果业务 X 的入口在 A 系统,而出错点在 D 系统,由于各系统都是独立的 A 并不知道 D 出了问题(即便知道也不知道怎么处理),对于管理者来说简单的隔离 D 可能是唯一能够做到的,于是会造成一连串的连锁反应,而且系统间访问都是异步的,这会在最终问题被处理之前引发大规模的错误和回滚请求。

这种强耦合导致的系统间不可靠性,其实 SOA 的解决方案就是将业务 X 从系统中剥离出来,将 X 放到 ESB 上来进行调度(理论上应该如此,先不说 ESB 能否胜任)。

5. 全局事务一致性问题

对于这样一段传统的业务代码:

复制代码
try{
t.open();
a.calculate(b);
b.save();
c.mark(b);
}catch(Exception e){
t.roolback();
// 出错处理和业务逻辑是分离的
}finally{
t.close();
}

我们通过传统的编程方式,可以方便的将错误处理和业务逻辑进行分离。但是,一旦将 a,b,c 拆成三个系统,问题就变得非常复杂了。首先,我们无法在传统的编程语言中支持异步调用,比如调用 b.save() 如果是异步的那么上面的这段代码根本就不能工作;第二,即便解决了异步问题,也就是说 b.save() 返回后还能成功的将程序调用堆栈恢复到 c.mark() 之前,你依然需要在业务代码中加入错误处理的分支,也就是说 b.save 出错了应该回滚之前的操作。

所以,如果用传统语言来实现这样的业务逻辑,大多数的选择是这样的: a 系统:

复制代码
func calculate(b){
try{
t.open();
……
b.remotecall("save",b);
// 同步调用,在 b.save 中去调用
//c.mark();
if(isError(b.return))
throw new Exception("b.save error");
}catch(Exception e){
t.rollback();
}finally{
t.close();
}
}

我们可以看到,即便是同步调用也大大增大了代码的复杂度,如果是异步调用,就需要一个框架来实现,业务逻辑会被拆的七零八落难以理解和维护。而且,这段代码实在是太丑陋了,为什么要在 calculate 中去调用 save 呢?为什么要在 save 中调用 mark 呢?显然应该有更加优雅的方法来实现。

6. 异构系统问题

“我们刚刚花了几年把所有系统都改成 WebServices 接口了,你们又要改 JSON,能不能告诉我什么时候能稳定下来?”技术总是不断地进步,应用总是不断地在落后,这是一个必然趋势。我们今天用业界先进的技术来搭建新的应用系统,两年之后这个昔日先进的系统就变成落后的存量系统了。所以,异构存量系统的集成问题是永恒的话题和需求,那么互联网模式这种统一技术架构,统一接口规范的大一统想法是不切实际的,除非你肯花大量的资源去不断的跟踪技术的变化,不断的投入去改造老系统的技术平台。

微服务架构适合于利用统一的技术平台新建系统,但是随着系统的发展,系统之间的异构化逐步的成主要的矛盾,这种去中心架构也将不再能够满足系统间交互的需求。

7. 组织需求与架构选择

前面分析我们看到,架构是组织需求决定的。组织需要精细的成熟的管理,就偏向权力密集的集中架构多一些;组织需要创新和快速迭代多一些,就偏向更自由的去中心架构多一些。但是,一种非黑即白的架构选择显然是不合理的,大多数的组织既需要精细成熟的管理,也需要自由奔放的创新,所以就需要一种架构能够支撑更复杂的混合需求。

那么我们前面讨论的自然进化来的多中心架构就成为一种合适的选择,事实上我们观察现实中稍微复杂一点儿的企业,无一例外都是多中心结构的。后面我们先深入理解 S++ 的特性,然后再来详细探讨 S++ 与各种架构的关系。另外,我相信很多朋友会困惑多中心架构如何解决淘宝级的访问压力,后面我会逐步的提出解决方案或解释。架构是用来平衡资源的,它并不能改变资源的多少,想提高性能还是要在算法上下功夫。

作者介绍

李东,14 岁开始学习计算机语言,作为课外兴趣自学了 BASIC 和汇编,利用放假期间编写了贪吃蛇、打飞碟等游戏。高中、大学期间继续自学软件编程,曾将 C 和汇编结合使得从高级语言中能够调用绘图功能,并模仿 Borland C++ 开发了一套适合学校机器的图形化开发环境的原型。

93 年大学毕业后在西门子合资公司作为交换机软件安装人员工作两年,然后来到 JInfonet 公司先后参与 4GL 的研发和 JReport 的研发。作为 JReport 的第一代主要研发人员,编写了从原型一直到 3.0 版本的核心引擎部分。2000 年与合伙人一起创建了 Bi-Soft 公司,主营业务是商业智能软件 Bi-Pilot,负责整个产品的研发及管理工作,从最基本的查询一直到多维分析模型和引擎都是产品的涵盖范围。

2007 年 Bi-Pilot 被神州信息收购合并,李东开始在神州信息研发 SmartESB 产品,用 SOA 的方法论为客户提供底层产品服务。


感谢郭蕾对本文的审校。

给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家通过新浪微博( @InfoQ @丁晓昀),微信(微信号: InfoQChina )关注我们。

2016-08-30 18:474004

评论

发布
暂无评论
发现更多内容

从技术到管理,我在极客时间的成长历程

邓建春

你不知道的SSD那些事

焱融科技

分布式 存储 SSD nvme

原创 | 使用JUnit、AssertJ和Mockito编写单元测试和实践TDD (十三)编写测试-生命周期方法

编程道与术

Java 编程 TDD 单元测试 JUnit

匆忙的一周 ARTS第二周

困到清醒

ARTS - Week Two

shepherd

js algorithm

机器学习算法评估指标——2D目标检测

做技术BP的文案Gou

这是一个测试文档

Geek_073cad

我的 windows 利器

玄兴梦影

工具 Win

patroni 通过服务启动报错

hobson

数据库 高可用 AntDB

情绪的力量:如何使用情绪来达成目标

董一凡

情绪

Vue生态篇(二)

shirley

Vue

从 0 到 1 搭建技术中台之发布系统实践:集泳道、灰度、四端和多区域于一体的设计与权衡

伴鱼技术团队

架构 系统设计 系统架构 系统性思考 架构设计

这些Java8官方挖的坑,你踩过几个?

牧码哥

Java 踩坑 加密 「Java 25周年」

【Java 25周年有奖征文获奖名单公布!!!】关于Java,你最想赞扬、吐槽、期待的变化是什么?

InfoQ写作社区官方

写作平台 Java25周年 热门活动

Go语言分布式系统配置治理

田晓亮

微服务

Python 自动化办公之"你还在手动操作“文件”或“文件夹”吗?"

JackTian

Python 自动化

杂谈-JSONP探索

卡尔

Java jsonp

互联网时代的界限管理

非著名程序员

程序员 职场 提升认知 界限管理

程序员修炼的务实哲学

博文视点Broadview

程序员 软件 编程思维 工程师 编程之路

架构学习历程

# LeetCode 215. Kth Largest Element in an Array

liu_liu

算法 LeetCode

奈学:传授“带权重的负载均衡实现算法”独家设计思路

奈学教育

分布式

ARTS 第二周打卡

陈文昕

关于区块链的“去中心化”,90% 的人都搞错了

CECBC

CECBC 区块链技术 去中心化 专制

MySQL的各种日志

超超不会飞

MySQL

一个人,沿着童年的路究竟可以走多远?

zhoo299

童年 NASA 航天

Redis持久化了解一波!

不才陈某

redis 程序员 后端

我常用的浏览器插件

彭宏豪95

chrome 效率工具 浏览器 插件

知识也会生宝宝?

史方远

个人成长 随笔杂谈

# LeetCode 863. All Nodes Distance K in Binary Tree

liu_liu

算法 LeetCode

开源分布式文件系统大检阅

焱融科技

开源 sds 存储 焱融科技 文件存储

服务的技术架构之争_架构_李东_InfoQ精选文章