api - REST 基础架构设计所需的建议
问题描述
这不是一个技术问题,而是更多关于如何设计几个 API 之间的通信。假设从基础设施的角度来看只有这4 个组件(微服务架构)
- 收集器 -> 从外部来源 1 获取数据,进行一些小的重新映射,仅此而已。
- 收集器 -> 从外部来源 2 获取数据,进行一些小的重新映射,仅此而已。
- 聚合器 -> 存储来自收集器 API 的数据,对数据进行适度的重新映射以使其按照我想要的方式结构化。
- Scheduler -> 负责定期触发从外部源获取数据。
我提出的想法:
方法一
- 调度程序调用聚合器端点。然后聚合器向收集器发出 HTTP 调用,接收响应并存储在数据库中。
方法二
- 调度程序调用收集器,获取数据,然后再次调用聚合器组件来存储数据。
方法 3
- 调度程序调用收集器并发送聚合器的回调 url(或聚合器 URL 已为收集器组件所知),收集器从外部源抓取数据,然后调用聚合器组件。
到目前为止我的实现:
方法一:
聚合器上的端点不是 RESTful。想象一下,您想获取 2020 年某个特定国家/地区的所有足球比赛数据。您会将国家和年份作为查询参数传递给聚合器组件上的 POST 端点,但这不是您最终将在您的数据库。这是一种简单的方法,但我不喜欢聚合器组件上的端点对它们在做什么不透明。
方法二:
这种方法允许正确的 RESTful API 设计,但它确实需要调度程序也充当代理。调度程序不会序列化然后反序列化数据。它只是从收集器的 GET 端点获取数据并将其转发到聚合器的 POST 端点,但它给这个组件增加了额外的复杂性。
方法3:
允许正确的 RESTful API 设计,但我不喜欢数据如何实际进入聚合器(以及因此数据库)的逻辑隐藏在收集器组件中。此外,对于每个新的收集器,都会重复相同的“逻辑”。
到目前为止,尽管使组件成为半调度器和半代理,但方法 2 似乎对我来说最有意义。此外,我可以引入一个新的代理组件。也许“代理”不是最好的措辞,但你明白了。
它会被调度程序调用,然后它会从收集器中获取数据并将其转发给聚合器,但是添加这个组件似乎会给整个系统带来更多的复杂性,我不确定它是否会带来任何真正的价值。
我对其他方法、建议等持开放态度:)
解决方案
我更喜欢你的方法2,但总的来说我的观点是:
所有的操作看起来都非常异步,因为收集器可能需要很多时间,而聚合器非常依赖它。
聚合器应该了解收集器,因为在系统之间(比如说聚合器和收集器)应该有一个可以由 CDC(消费者驱动的合同测试)维护的合同,因此消费者知道生产者正在生产什么以及如何生产。
方法 1 调度器可以直接调用聚合器,为收集器提供 URL(可以存储在调度器中,或者让聚合器知道它,最好是后者,因为调度器只会调度东西)。但是这里聚合器也需要等待收集器响应,因此可以避免等待部分(这是调度程序最擅长的)。链接 HTTP 调用也可能不是一个好主意。糟糕的设计。对于内部的多个 API 调用,我们使用事件驱动架构等异步设计。
方法 2 调度程序调用收集器开始收集。完成后,让调度程序知道。然后调度程序要求聚合器开始操作。一个。调度程序不应该将信息从收集器引导到聚合器,但聚合器可以直接执行 API 调用以直接从收集器获取数据。
一个。此外,您可以让收集器 API 在消息总线中将数据异步发送到聚合器,聚合器处理传入数据(或存储本地副本并稍后处理)。这使得系统更加解耦。所以调度器只调用收集器启动。
C。如果收集器出现故障,聚合器仍然可以用过时的数据进行响应。
方法 3 听起来消费者(收集器)知道如何调用生产者(聚合器),我认为这不是生产者不应该了解消费者的责任,它也将资源信息泄露给生产者。
推荐阅读
- c# - 在应用程序运行时安装字体
- reactjs - TypeError:无法读取反应应用程序中未定义的属性“推送”
- android - 运行应用程序时出现错误“$flutterSdkpath\packages\flutter_tools\gradle\app_plugin_loader.gradle”
- javascript - 在 vuejs 中页面刷新(shift+F5)期间调用了哪个生命周期方法?
- python-3.x - 从维基百科页面抓取所有图像
- c++ - 如何使用 spdlog 打印 std::map
- scala - 在 nullSafeJoin scala spark 之后避免重复库
- java - 在 N 个线程中并行运行相同的测试 M 次
- neo4j - 在 grafana 仪表板中动态更改 prometheus 中的指标名称
- node.js - 无法编译打字稿项目