QCon北京「鸿蒙专场」火热来袭!即刻报名,与创新同行~ 了解详情
写点什么

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

  • 2019-12-31
  • 本文字数:3589 字

    阅读完需:约 12 分钟

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

在某些时候,工程师必须绘制一些方框和箭头来描述软件系统的顶层设计。但是,这些方框和箭头叫什么?我们经常使用诸如微服务,实体,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 控制台)进行交互,或者根本不进行交互(对于静态文档而言)。客户背后的主要限制是,除了服务描述所包含的信息外,他们还应该对目标服务的实施细节一无所知。连接器的定义非常宽松,因为我们对信息的传输方式没有任何限制。


2019-12-31 09:402910

评论 1 条评论

发布
用户头像
这是翻译过来的吗?读起来很拗口,很多概念不明白写的是啥?样式?
2019-12-31 16:01
回复
没有更多了
发现更多内容

2013年,我有点喜欢编程了

勇哥java实战分享

前端 “一键换色“ 的几种方案

CRMEB

大数据培训MySQL 索引B+Tree

@零度

大数据

python进阶-装饰器

AIWeker

Python 人工智能 5月月更

北明软件加入昇腾万里伙伴计划,与华为共建昇腾AI生态,共同推动人工智能产业繁荣发展

科技热闻

石油储运生产 2D 可视化,组态应用赋能工业智慧发展

一只数据鲸鱼

数据可视化 数字孪生 组态 石油开采

Open Harmony移植:build lite配置目录全梳理

华为云开发者联盟

HarmonyOS Open Harmony移植 Open Harmony build lite配置

边缘工业协议网关软件Neuron正式开源,连接海量异构工业设备

EMQ映云科技

开源 物联网 IoT mqtt emq

SpringBoot集成开源IM框架MobileIMSDK,实现即时通讯IM聊天功能

JackJiang

网络编程 即时通讯 IM TCP协议

2022年医疗+AI,将会如何蓄力发展?

易观分析

医疗AI

云天励飞与华为签署合作协议,共同推进昇腾AI产业持续发展

科技热闻

浅析分布式系统之体系结构 - 事务与隔离级别(多对象、多操作)上篇

snlfsnef

数据库 架构 设计原则 一致性 事务隔离

百亿级数据同步,如何基于 SeaTunnel 的 ClickHouse 实现?

Apache SeaTunnel

Apache 大数据 开源 DolphinScheduler workflow

阿里大牛两万字总结+40张图文详解,不信你还参透不了并发编程

Java架构追梦

高并发 java面试 后端开发

构建面向特征工程的数据生态 ——拥抱开源生态,OpenMLDB全面打通MLOps生态工具链

第四范式开发者社区

人工智能 机器学习 数据库 特征平台 特征工程

全面解析企评家网站功能

企评家

企业评价 企评家 企业成长性评价 企业查询

到底什么是企业应用现代化?

Daocloud 道客

云原生 应用现代化

如何基于盘古开发框架开发Dubbo微服务网关

码农大熊

微服务架构 网关

比心云平台基于阿里云容器服务 ACK 的弹性架构实践

阿里巴巴云原生

阿里云 容器 云原生 客户案例 阿里云容器服务ACK

“操作系统的「冷板凳」要坐多久?”万字长文解读16年开源人的坚持

OpenAnolis小助手

Linux 开源 操作系统 坚持 龙蜥社区

Kubernetes 1.24 - 走向成熟的 Kubernetes

Daocloud 道客

Kubernetes 云原生 容器编排

PingCode Flow技术架构揭秘

PingCode研发中心

WordPress 如何重置密码

海拥(haiyong.site)

5月月更

恭喜 Kvrocks 加入 Apache 软件基金会孵化器

Kvrocks

redis 开源 apache 社区

web前端培训interface和type的区别分析

@零度

typescript 前端开发

Apache ShardingSphere 企业行|走进携程

SphereEx

Apache 数据库 ShardingSphere SphereEx 企业行

Git 常用命令

平凡人生

Alluxio 2.8版本重磅发布!3大提升抢先打开数据新世界

Alluxio

分布式缓存 数据管理 Alluxio 大数据 开源

社交电商如何规避传销风险

源字节1号

软件开发

【Python】此集合非彼集合

謓泽

5月月更

看 Amazon 如何通过 Nitro System 构建技术优势

亚马逊云科技 (Amazon Web Services)

Builder 专栏

工程师每天都在研究的软件架构是什么?_架构_Ignacio Piantanida_InfoQ精选文章