29

考虑在线商店项目的以下微服务:
用户服务保存有关商店用户的帐户数据(包括名字、姓氏、电子邮件地址等)

购买服务跟踪有关用户购买的详细信息。

每个服务都提供了一个用于查看和管理其相关实体的 UI。购买服务索引页面列出了购买。每个采购项目应包含以下字段:
id、采购用户全名、采购项目名称和价格。
此外,作为索引页面的一部分,我想要一个搜索框,让商店经理通过购买用户名搜索购买。

我不清楚如何取回购买服务不保存的数据 - 例如:用户的全名。当尝试通过购买用户名进行搜索购买等更复杂的事情时,问题会变得更糟。

我想我显然可以通过在用户创建时广播某种事件来在两个服务之间同步用户来解决这个问题(并且只在购买服务端保存相关的用户属性)。在我看来,这远非理想。当您拥有数百万用户时,您如何处理这个问题?您会在每个使用用户数据的服务中创建数百万条记录吗?

另一个明显的选择是在用户服务端公开一个 API,它会根据给定的 id 返回用户详细信息。这意味着在购买服务中加载每个页面时,我都必须调用用户服务以获取正确的用户名。不理想,但我可以忍受。

那么如何实现基于用户名的购买搜索呢?好吧,我总是可以在接收查询词的用户服务端公开另一个 API 端点,对用户服务中的用户名执行文本搜索,然后返回所有符合条件的用户详细信息。在购买服务中,将相关 ID 映射回正确的名称并在页面中显示它们。这种方法也不理想。

我错过了什么吗?是否有另一种实现上述方法的方法?也许我面临这个问题的事实有点代码味道?很想听听其他解决方案。

4

4 回答 4

17

在进入微服务时,这似乎是一个非常常见和核心的问题。我希望有一个好的答案:-)

关于这里已经提到的建议模式,我将使用术语数据非规范化而不是多语言持久性,因为它不一定需要使用不同的持久性技术。关键是每个服务都处理自己的数据。是的,你有数据重复,你通常需要某种事件总线来跨服务共享数据。

还有另一种选择,这是第一种选择——将搜索本身作为一项单独的服务。

因此,在您的示例中,您拥有用于管理用户的用户服务。采购服务管理采购。每个都处理自己的数据并且只处理它需要的数据(例如,Purchase 服务实际上并不需要用户名,只需要 ID)。您还有第三个服务——搜索服务——它使用其他服务产生的数据,并从组合数据中创建一个搜索“视图”。

于 2015-04-12T21:04:33.920 回答
4

将适当的数据保存在不同的数据库中是完全可以的,这称为Polyglot Persistence。是的,您希望单独保存用户数据和购买数据,并使用消息队列进行同步。数百万用户对我来说似乎很好,这是可扩展性,而不是设计问题 ;-)

在搜索的情况下 - 您可能想要搜索的不仅仅是用户名,对吧?因此,如果您使用消息队列来更新服务之间的数据,您还可以轻松地将这些数据路由到 ElasticSearch,例如。从 ElasticSearch 的角度来看,索引哪个字段并不重要——用户名或产品标题。

于 2015-04-05T19:55:14.387 回答
1

我通常使用这两种方法。有时我有另一个服务位于 x 其他服务之上并组合数据。我不太喜欢这种方法,因为它会导致服务之间的依赖和耦合。所以总的来说,在我最近的项目中,我们试图坚持多语言持久性。

还想一想,如果您需要在某种中间件服务中进行 x 次 http 请求来组合数据,这将导致您的延迟更高。我们总是试图减少一项任务的请求数量,并通过异步队列处理所有可能的事情。(尤其是数据同步)

于 2016-04-22T13:22:26.027 回答
0

如果您将模块概念化为它们处理的数据的所有者和控制器,那么您的模型还必须将该模块中的数据传递给其他人。相比之下,制造过程中的模块可以访问更改数据,而无需拥有和控制它。

微服务是一种分布式处理架构,就像大多数代码一样,模块在其中传递数据以对其进行处理。从哈佛商业评论和麦肯锡关于拥有供应链成员的经典文章中,我发现了这种模型产生的复杂性,并写了一篇文章教程序员你需要知道什么:http ://www.powersemantics.com/p .html

制造是一种用于集成处理的架构,其中模块处理数据而无需点对点传递。这可以通过将模块配置为访问相同的内存、文件或数据库表来实现。我的架构展示了如何通过引用属性在内存上实现这一点。

当您考虑“在用户服务端公开一个基于给定 id 带回用户详细信息的 API”时,您需要注意这会产生 HBR 所谓的“不可逆”复杂性,我称之为中心化复杂性。不要构建 A->B(分布式)系统,因为您无法在未能分离需求后将它们分散。生产过程中的需求代表了用户的指令,集中的模块只能让你改变错误的用户的过程。换句话说,集中式模块不会记录用户组或将它们与派生产品用户区分开来。

于 2020-04-17T13:29:41.223 回答