假设有两个(或更多)RESTful微服务提供JSON。服务(A)存储用户信息(名称,登录名,密码等),服务(B)存储发往该用户的消息/来自该用户的消息(例如sender_id,主题,正文,rcpt_ids)。
/profile/{user_id}
上的服务(A)可能会回应:
{id: 1, name:'Bob'}
{id: 2, name:'Alice'}
{id: 3, name:'Sue'}
以此类推
在/user/{user_id}/messages
响应的服务(B)返回发往该{user_id}的消息列表,如下所示:
{id: 1, subj:'Hey', body:'Lorem ipsum', sender_id: 2, rcpt_ids: [1,3]},
{id: 2, subj:'Test', body:'blah blah', sender_id: 3, rcpt_ids: [1]}
使用这些服务的客户端应用程序如何处理将消息列表放在一起,以便显示名称而不是发件人/ rcpt id?
方法1 :提取消息列表,然后开始提取sender_id
和rcpt_ids
中列出的每个ID的个人资料信息?这可能需要100的请求,可能需要一段时间。相当幼稚和低效,可能无法与复杂的应用程序一起扩展?
方法2 :提取消息列表,提取所有用户ID,并分别对所有相关用户发出批量请求...这假定存在这样的服务端点。在获取消息列表,提取用户ID,发送对批量用户信息的请求以及等待批量用户信息响应之间仍然存在延迟。
理想情况下,我想一次性提供完整的响应集(消息和用户信息)。我的研究将我带到了服务层的响应合并……又称为方法3 :API网关技术。
但是如何实现呢?
我可以获取消息列表,提取用户ID,在后台进行调用并获取用户数据,合并结果集,然后将此最终结果提供...在后台使用2种服务都可以正常工作...但是,如果消息列表取决于更多服务,该怎么办...如果我需要在幕后查询多个服务,进一步解析这些响应,基于次要(三次)结果查询更多服务,然后最终合并...这种疯狂在哪里停止?这如何影响响应时间?
并且我现在已经有效地创建了另一个“客户端”,它将所有微服务响应组合成一个大型响应...与上面的方法1 ......在服务器级别上没有什么不同。
在“现实世界”中是这样吗?有什么见解吗?我可以检查基于此类API网关体系结构构建的任何开源项目吗?
答案 0 :(得分:0)
您可能要在API网关上执行响应聚合策略。我写了一篇有关如何在ASP.net Core和Ocelot上执行此操作的文章,但其他API网关技术应该有对应的内容:
https://www.pogsdotnet.com/2018/09/api-gateway-response-aggregation-with.html
答案 1 :(得分:0)
我们用于此类问题的解决方案是对数据和事件进行非规范化以进行更新。
基本上,微服务事先具有其他微服务所需的数据子集,因此它不必在运行时调用它们。该数据通过事件进行管理。其他微服务在更新时会触发一个以id为上下文的事件,任何对此感兴趣的微服务都可以使用它。这样,数据保持同步(当然,它需要某种形式的事件失败机制)。这似乎有很多工作要做,但可以帮助我们做出有关合并来自不同微服务的数据的任何未来决策。我们的微服务将始终在本地提供所有可用数据,以处理任何请求,而无需同步依赖其他服务
在您的情况下,即为了显示带有消息的名称,您可以在Service(B)中保留名称的额外属性。因此,每当Service(A)中的名称更新时,它将触发一个ID为该更新名称的更新事件。然后,服务(B)获取该事件,从服务(A)获取相关数据并更新其数据库。这样,即使Service(A)关闭,Service(B)仍将起作用,尽管它具有一些过时的数据,这些数据最终将在Service(A)出现时保持一致,并且您将始终在UI上显示一些名称。
答案 2 :(得分:0)
您需要编写另一个名为 Aggregator 的服务,该服务将在内部调用这两个服务并获取响应并合并/过滤它们并返回所需的结果。在Spring Reactive中使用Mono / Flux在非阻塞状态下可以轻松实现。
API网关经常进行API组合。
但是,这是一个典型的工程问题,其中您具有微服务,该微服务正在按服务模式实现数据库。
API组成和命令查询责任隔离(CQRS)模式是实现查询的有用方法。
答案 3 :(得分:-2)
理想情况下,我希望一次性提供完整的响应集 (消息和用户信息)。
您所描述的问题是Facebook在多年前意识到的,他们决定通过创建名为GraphQL的开源规范来解决这个问题。
但是如何实现呢?
它已经以各种流行的编程语言实现,也许您可以尝试使用自己选择的编程语言。