我正在寻找一个设计问题的答案,我在这个问题的任何文献中都找不到答案。请允许我解释用例,我的解决方案,并作为主题专家征求您的意见。
使用案例: 我们有几个微服务都返回来自不同业务领域的某种形式的内容。我们正在使用Spring Cloud Netflix,因此网关服务将流量路由到内容服务。这些服务中的一些(如果不是全部)需要从请求派生的数据,并且是不可变的。一个简单的例子是locale,尽管还有其他专有信息。
解决方案: 我目前正在网关服务中派生共享数据,并在具有唯一密钥的NoSQL数据库中作为JSON持久化。然后我在路由请求之前将密钥添加为请求标头。我有一个内容服务在构建时包含的共享库,并包含一个Spring bean,它从请求头中读取密钥,使用密钥获取存储的数据并初始化自身。这使得内容服务可以在不知道底层机制的情况下访问共享数据(通过简单地注入前面提到的bean)。 如果内容服务调用另一个内容服务,则它负责将唯一密钥添加为请求标头。
辩论: 我与同事们的争论是,为此目的使用共享数据存储是否合适。我认为服务将其域特定数据泄露给其他人是不好的,但是有问题的数据不是特定于域的,因此拥有共享数据库并传递密钥没有任何问题。另一种方法是传递我认为多余的所有共享数据。
你的想法是什么?
编辑:我看到有人投票结束了这个问题。除非他们能够指出我讨论微服务之间数据共享的参考,否则这种警务是有意义讨论的障碍。不是每个问题都是布尔是/否答案,有些问题需要更深入的思考。
答案 0 :(得分:2)
在第一个答案激烈辩论之后,让我借一些看法:
经常出现的一个用例是如何在请求到达第一个服务之后处理例如身份验证信息,然后第一个服务又调用其他服务。现在的问题通常是:我是否交出身份验证信息(如用户名和组等),或者我只是移交令牌,客户端发送并让下一个服务再次查询身份验证信息。
据我所知,微服务社区尚未就“惯用”问题达成一致意见。解决这个问题的方法。我认为这是有充分理由的,它涵盖了各种应用在这个主题中提出的不同要求。有时,只有在第一个受到外部请求命中的服务时才需要进行身份验证 - 然后不要在认证过程中投入太多工作。我所知道的大多数系统都有更高的要求,因此在认证方面需要另外一定程度的复杂性。
让我向您介绍如何解决此问题:最简单的方法是交出客户端在后端服务之间发送的访问令牌。是的 - 这种方法要求每个服务在每次被请求命中时重新查询用户信息。如果(并且我的系统中没有发生这种情况),每个请求有25个跨服务调用 - 这很可能意味着在某种身份验证服务上有25次点击。大多数人现在都会惊恐地发现这种可怕的重复 - 但让我们想到另一种方式:如果同一系统是一个结构良好的巨型单元,你仍然可以进行这些调用(可能每个单独调用一个数据库)时间)在你的过程中的不同地方。在微服务架构中关于这些调用的重要事项是网络开销,这是真的 - 如果做错了会杀了你!我将为您提供我们采取的解决方案,并且在重负荷下为我们提供了良好的解决方案:
我们开发了令牌服务(我们很快就会开源)。除了存储令牌,它的到期日期和一些无架构JSON内容的组合之外,此服务不会执行任何其他操作。它有一个非常简单的REST接口,可以让您创建,无效,扩展和读取令牌及其内容。此服务具有多个后端,可根据其运行环境进行配置。出于开发目的,它具有简单的内存存储,不会以任何方式同步,保留或复制。对于生产环境,我们编写了一个后端,用于在多个实例之间同步这些令牌(包括仲裁,异步持久等所有内容)。这个后端使我们能够很好地扩展这项服务;这是我提出的解决方案的前提:如果每个服务节点每次收到请求时都必须获取与令牌相关的信息 - 提供它的服务必须非常快!我们的实施在不到5毫秒的时间内返回令牌及其信息,我们相信我们可以进一步降低这一指标。
我们的另一个策略是编排对令牌服务进行更严格查询的服务(与仅仅检查令牌有效性/存在相比,接收内容的价格昂贵),以便它们位于相同的物理节点上或靠近将网络延迟降至最低。
更普遍的消息是什么:只要数量或这些呼叫与处理的内容数量保持不相关,就不要害怕跨服务呼叫(错误示例here)。更频繁地调用的服务需要更加谨慎地设计,并且需要对其性能进行非常优化以使其具有最后可能的毫秒级。 DB-Hits在这种系统关键服务中就是绝对的Nogo - 但是有一些设计模式和架构可以帮助你避免它们!
您可能已经检测到我没有直接回答您的问题进行辩论。为什么?我强烈反对在服务之间共享数据库。即使这些数据库是无模式的,您也可以将两个服务结合在一起,而不会看到这种依赖关系。一旦你决定在令牌服务中重新构建你的数据,并且还有另一项服务,甚至只是阅读这个数据库 - 你只是搞砸了两个服务,你可能会意识到它已经太晚,因为依赖是不透明的。服务中的状态/数据只能通过定义良好的接口访问,因此可以很好地抽象,开发和独立测试。在我看来,改变一个服务中的持久性技术或结构不应该搞砸,甚至不需要改变另一个服务。通过它独家访问服务使您可以重构,重建甚至完全重写服务,而不必破坏依赖它的其他服务。它被称为脱钩!
让我知道这是否有用!
答案 1 :(得分:0)
在大多数情况下,复制的成本会被便利性所抵消,但您始终可以将共享数据视为另一项服务所拥有的。
如果只有一位作家参与"分享"数据和您以允许客户端独立版本化的方式访问它,然后您可以将共享数据视为非常规公开服务。
示例:
在传统布局中,服务B将通过调用服务A来访问A1。
Service B --HTTP--> Service A --SQL--> A1
或者,服务A可以创建一个允许服务B直接访问A1的视图。
Service B --SQL--> vwA1_version1 --SQL--> A1
当服务A更改字段布局时,服务A更新vwA1_version1
以允许向后兼容旧客户端,并为新客户端定义vwA1_version2
。