我有一个实现消息传递系统的微服务架构。一切安排如下:
- IdentityService 是一个单独的微服务,用于存储用户全名。
- MailboxService 是一种管理邮箱和消息的服务。这里存储了消息、发件人和收件人 ID 以及电子邮件地址(电子邮件是邮箱的一部分)。
- GatewayService 是一个充当服务之间协调器的 API 层。
每条消息都包含一个senderId和recipientId,以及这些用户的名称(senderName,recipientName)。问题在于名称仅存在于 IdentityService 中,而消息是在 MailboxService 中创建和存储的。
我不明白在哪里插入全名更正确,以及存在哪些架构上的妥协。我了解这是微服务的典型痛点,所以我对社区的意见很感兴趣。以下是我正在考虑的选项:
⸻
选项 1:在 GatewayService 中创建消息时获取名称
GatewayService 不创建电子邮件,而是调用 MailboxService。此时,它从 IdentityService 请求名称并将它们与其余数据一起传递给 MailboxService。 MailboxService将senderName、recipientName直接存储在Message中。
优点:
- MailboxService 对 IdentityService 一无所知。
- 消息中的数据是自给自足的;客户端不需要上传任何额外的东西。
缺点:
- 数据重复(名称既存储在身份中,也存储在每条消息中)。
- 当用户更改其姓名时,旧消息仍保留旧姓名。
- GatewayService 变得“胖”,从两个服务中提取逻辑。
⸻
选项 2:将所有者姓名存储在邮箱中
创建邮箱时,用户的全名将与用户 ID 一起保存在其中。创建消息时,发件人姓名从邮箱中获取,收件人姓名通过外部调用或从缓存中获取。
优点:
- 集中化:邮箱了解其所有者的一切信息。
- MailboxService 可以自行创建消息,无需 GatewayService 的帮助。
缺点:
- 名称改变时,数据可能会重复并过时。
- MailboxService 开始存储语义上的身份 - SRP 违规。
⸻
选项 3:根本不存储姓名,在检索消息时替换
MailboxService 仅存储发件人和收件人 ID。当通过 GatewayService 检索消息时,它会收集一堆 ID,并向 IdentityService 发出请求以填写全名。
优点:
- 清晰的架构:每个服务只知道它应该做什么。
- 名字总是相关的。
缺点:
- 提取逻辑的复杂性(需要进行类似连接的查询)。
- 性能——当消息和用户数量众多时,身份查询可能会成为瓶颈。幸运的是,这并不意味着高负载(封闭的网络,低流量,只有几千个用户)
⸻
问题:
当使用来自另一个服务(如全名)的不涉及业务逻辑但仅需要显示的“次要”数据时,哪种方法在微服务架构中更正确和更容易被接受?