工程师每天都在研究的软件架构是什么?

在某些时候,工程师必须绘制一些方框和箭头来描述软件系统的顶层设计。但是,这些方框和箭头叫什么?我们经常使用诸如微服务,实体,REST 或事件驱动之类的术语,这些又是什么?

作为研究论文的一部分,我一直在阅读有关软件体系结构概念和定义的知识,并且在整篇文章中,我将解释其中的一些概念,这些概念适用于我在研究生期间也一直在从事的项目:JSON- RPC Playground 控制台。

软件架构是什么?

我将使用 Roy Fielding(HTTP 规范的主要作者之一和 REST 风格的创建者)在其博士学位论文中给出的定义(如果您对 Software Architecture 感兴趣,我推荐您看看这篇论文)。

软件体系结构是软件系统在其操作的某个阶段的运行时元素的抽象。一个系统可能由许多抽象级别和许多操作组成,每个阶段都有自己的软件体系结构。

架构是抽象的

在描述体系结构时,可以对实现细节进行抽象,以简化设计。如用 Elixir 或 Java 编写身份验证服务有关系吗,显然这不是在架构层面要考虑的事情?还是它在系统中扮演的角色 - 验证用户 - 我们应该关注什么?

架构与运行时有关

源代码结构不是系统的体系结构。当系统处于活动状态时,不同的应用程序可以共享公共库或模块,但彼此之间完全断开连接,这个是低耦合的设计。我们专注于处理数据以及如何移动数据。软件架构一般用高内聚、低耦合方式构建。

架构专注于特定的阶段

并非每个组件都会始终发挥作用或成为各个流程的一部分。系统关闭时涉及的组件及其配置可能与系统正常操作模式中涉及的组件及其配置完全不同。

架构是嵌套的

在抽象元素实现时,我们将忽略与当前架构无关的细节。如果我们将重点转移到更深层次,则将出现具有其自身的元素和配置集的新体系结构。我们将找到许多嵌套的体系结构,直到元素足够简单以至于无法分解为止,实现原子性构建。

一系列决策的结果是创建了一个软件体系结构,每个决策都带来了一组属性和约束。无论它们在图表中是明确指出的,还是仅存在于架构师和开发人员的思想中,对于这些决定和约束应该都有一种理解或意图。随着系统的发展,这些最初的决定很可能与架构的实际情况不符。如果这些差异是不希望的或偶然的,那么我们说该体系结构已被侵蚀,造成了体系结构的“技术负债”。

案例研究:JSON-RPC 控制台

我们的客户平台之一是由数十个 JVM 微服务组成,它们使用 JSON-RPC 2.0 协议相互通信。每个服务使用一组 Java 接口声明其 RPC API,这些 Java 接口作为“ Service-API”库(JAR)发布在公共存储库中。想要与服务进行交互的客户端只需将其 API JAR 声明为项目依赖项即可。平台库将生成实现此类接口的对象,并通过依赖注入提供实现代码类。从代码角度来看,您只是在调用常规方法,但是在后台,平台库正在执行 RPC 调用并为您处理所有涉及的管道。这在编写代码时极大地提高了工作效率!

但是,要手动测试所有这些 RPC 方法(例如,使用诸如 Postman 或 curl 的工具),就必须找到正确的代码库,手动检查服务接口,其方法和参数(可能具有许多嵌套对象级别) ),然后手动构建所需的 JSON payout 以执行 API 调用。一般而言,API 文档有帮助,但是很难保持最新,这是一个问题。

这里,我创建一个 GUI 应用程序,该应用程序会自动生成可轻松填充的表单,以调用服务公开的任何 RPC 方法。这些表单是通过与 JSON-RPC 2.0 兼容的服务描述文件生成的,该文件是通过分析 Service-API JAR 库创建的。通过使用与生产中运行的实际代码相同的源,可以确保它们保持最新。

工程师每天都在研究的软件架构是什么?

架构元素

构架系统意味着要做出一系列决定,这些决定可以塑造构成系统的不同元素(组件,连接器和数据)的配置。

组件(Components)

组件是软件指令和内部状态的抽象单元,它通过接口提供转换或执行数据计算。组件是由它们向其他组件提供的服务定义的,而不是由它们的界面后面的实现定义的。如果其他组件无法识别某些行为,则该行为不是体系结构的一部分。

示例

  • RPC 控制台:将服务描述转换为一组表单,捕获用户输入,执行 RPC 调用并显示其结果。
  • RPC 服务器:接收 RPC 请求,对其进行计算,然后返回结果。
  • 分析器:将 Service-API JAR 转换为服务描述。
  • JAR 存储库:存储并提供 Service-API JAR。
  • 服务说明存储库:存储并提供服务说明。

请注意,就此体系结构的观点而言,在定义 RPC Server 组件时,我们对 RPC Server 提供的特定功能不感兴趣,因为它与其余组件无关。我们甚至将这个组件的许多不同实例均等地分组,即使实际上它们在功能上会有很大不同。如,一个可能是 Users 服务,而另一个可能是 Books 服务。

连接器(Connectors)

连接器可实现不同组件之间的通信和数据传输。他们不转换数据,而是通过界面在不同组件之间对数据进行移动。但是在内部,当查看一个特定连接器的体系结构时,我们可能会发现它实际上是由一个子系统组成的,这些子系统接收数据,将其转换为更好的格式以进行传输,将其发送到另一端,然后反转转换,然后再传递给系统的其余部分。由于这些转换对系统的其余部分不可见,因此我们可以将它们抽象化为更高的层次。

在示例中:

  • RPC 客户端:开始 RPC 调用。
  • RPC 服务器:接收 RPC 请求并返回 RPC 响应。
  • HTTP 客户端:启动 HTTP 连接以获取服务描述。
  • AWS 库:将服务描述从分析器传输到服务描述存储库。
  • Gradle 库:将 Service-API JAR 依赖项从 JAR 存储库传输到分析器。

对于 AWS Library 和 Gradle Library 而言,我们不直接负责这些数据传输的方式。然后,我们可以使用连接器的视图,而忽略其实现的细节。

数据 (data)

许多软件体系结构定义没有将数据作为核心概念提及,我认为这并不完整。数据是系统存在的原因,有时甚至是驱动系统配置的主要因素。数据定义为通过连接器从一个组件传输到另一组件的信息。

在示例中:

  • 服务描述:以 JSON-RPC 2.0 兼容结构描述服务公开的可用 RPC 方法。它包括服务器 URL,方法名称,参数和类型之类的信息。
  • RPC 请求:包括 RPC 方法名称及其参数。
  • RPC 结果:RPC 调用执行的结果。
  • Service-API JAR:包含 RPC 服务的 Java 接口的 JAR 文件。

架构风格

架构风格是架构设计决策的命名集合,当在特定上下文中应用时对应不同的系统元素,它们的配置以及它们之间的关联方式施加约束,进而生成具有众所周知架构解决方案。

样式是一种用于对体系结构进行分类并定义其共同特征的机制。每种样式都为组件的交互提供了抽象,通过忽略架构其余部分的细节来捕获交互模式的本质。样式可以仅关注体系结构的某些方面,甚至可以将它们组合以生成更复杂的样式或混合样式。

客户端 - 服务器,微服务,Monolithic 甚至是 REST 都是不同的体系结构样式,您很可能已将其应用于数十种异构系统。

创造自己的风格

如果您熟悉诸如 Swagger 的 REST API 之类的工具,您可能会注意到我的 JSON-RPC 项目与之相似。虽然我的控制台使用了针对基于 JSON-RPC 的服务量身定制的服务描述作为输入,但是 REST API 具有OpenAPI 标准。从服务的源代码生成规范格式是一种强大的模式,可用于创建许多不同的使用者工具:文档导航器,客户端代码生成器,模拟服务器等。

让我们尝试为该工具系列定义通用的体系结构样式,该样式可以应用于任何其他协议以获得相同的好处:我将其称为“服务描述”样式。

服务风格描述

让我们开始定义架构的不同元素

数据元素:

  • 目标源代码:目标服务接口的源代码。
  • 服务描述:特定于协议的格式,遵循协议标准,可以描述任何目标服务的接口。

组件:

  • 生成器:自动从目标源代码创建服务描述,并将其发布到提供者。
  • 存储库:存储并提供服务说明。
  • 客户端:使用存储库中的服务描述,并将其用作提供针对目标服务动态定制功能的唯一来源。

连接器 (connectors):

  • 生成器 -> 存储库:将服务描述从生成器传输到存储库。
  • 存储库 -> 客户端:将服务描述从存储库传输到客户端。

必须从源代码创建服务描述。客户端需要始终保持最新的服务说明才能正常运行,因为除非服务说明中包含客户信息,否则他们对目标服务的具体情况一无所知。主要来源是代码,如果流程不是自动化的,则很可能会出现服务描述过时且客户端损坏的风险。这并不意味着不能手动构建服务描述。这样做有很多有效的用例,例如,如果您想在实际实现之前拥有一个模拟服务器。但是,依赖于手动任务的系统将不被视为该体系结构样式的实现。

请注意,我们对生成器如何使用源代码没有任何限制。实际上,生成器甚至可以作为目标构建过程中的一个步骤来实现(例如,使用 Maven 插件)。服务描述应遵循协议标准。该体系结构的主要优点之一是客户端可针对使用同一协议的许多不同目标服务进行重用,因此,服务描述无法了解仅适用于一项特定服务的特定实现细节。客户端提供的功能不属于体系结构的一部分:客户端可以与目标服务(例如,用于 Playground 控制台)进行交互,或者根本不进行交互(对于静态文档而言)。客户背后的主要限制是,除了服务描述所包含的信息外,他们还应该对目标服务的实施细节一无所知。连接器的定义非常宽松,因为我们对信息的传输方式没有任何限制。

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

推荐阅读更多精彩内容