0

我正在寻求一个设计问题的答案,我在这个问题上没有找到任何文献的答案。请允许我解释用例,我的解决方案,并征求您作为主题专家的意见。在微服务之间共享数据

用例: 我们有几个微服务,都返回来自不同业务领域的某种形式的内容。我们使用Spring Cloud Netflix,因此网关服务将流量路由到内容服务。这些服务中的一部分(如果不是全部)需要从请求派生的数据,并且是不可变的。一个简单的例子是语言环境,但也有其他专有信息。

解决方案: 我目前获得的共享数据的网关服务,并在NoSQL的数据库具有独特的键作为持续JSON。然后,我在将请求路由之前将该密钥添加为请求标头。我有一个内容服务在构建时包含的共享库,它包含一个Spring bean,它从请求头中读取密钥,使用密钥读取存储的数据并初始化它自己。这使得内容服务可以在不知道底层机制的情况下访问共享数据(通过简单地注入前面提到的bean)。 如果内容服务调用另一个内容服务,它负责将唯一密钥添加为请求标头。

辩论: 我与同事们的辩论是,为此目的使用共享数据存储是否合适。我认为服务将域特定的数据泄漏给其他服务是不好的,但是所讨论的数据并不是域特定的,所以拥有共享数据库并传递密钥没有任何问题。另一种方法是通过所有我认为是多余的共享数据。

你的想法是什么?

编辑:我看到有人投来关闭的问题。除非他们能够指出我讨论微服务之间数据共享的参考,否则这种警务是妨碍有意义讨论的障碍。并非每个问题都是布尔型的是/否答案,有些则需要更深入的思考。

+3

我想说一个服务应该拥有和管理数据存储。数据存储本身不应该共享。 – duffymo

+0

@duffymo数据认证的结果呢?你认为每个服务应该解析一个JWT令牌来提取相同的信息,或者它应该被完成一次并存储以备后用?我为共享数据创建抽象没有任何问题,这就是我的问题中的Spring bean正在做的事情。 –

+0

我相信VTC与这张贴在StackOverflow上相关。 [Programmers SE]的设计参数[更适合](http://meta.stackexchange.com/questions/124867/where-should-i-ask-software-architecture-design-questions)(http://程序员.stackexchange.com /)。 – Mitch

回答

0

在大多数情况下,复制的成本被方便所抵消,但您始终可以将共享数据视为其他服务所拥有。

如果只有一个作家的“共享”数据,你访问它的方式,允许客户端的独立版本,那么你可以作为一个非传统的公开的服务查看共享数据。

实施例:

  • 服务A拥有实体A1,存储在SQL Server作为表A1
  • 服务B拥有实体B1,这就需要数据从A1实体

在经典服务B将通过对服务A的呼叫访问A1。

Service B --HTTP--> Service A --SQL--> A1 

Alt事实上,服务A可以创建一个视图,允许服务B直接访问A1。

Service B --SQL--> vwA1_version1 --SQL--> A1 

当服务中的变化领域的布局,服务A更新vwA1_version1允许与老客户的向后兼容性和新的客户定义vwA1_version2

+0

请将您的答案改为特定于我的问题。关于共享数据存储的一般性讨论没有帮助。 –

+0

@AhhijitSarkar,你没有问一个具体的问题,你问了一个普通的问题。对于“您可以在SOA中共享数据存储”这个问题,我的回答就是。如果您希望得到“我应该通过JWT还是用户ID”的特定答案,我会强烈支持令牌。 AAA已经足够普遍,大多数服务将不得不访问数据。验证签名比DB调用便宜得多。 – Mitch

2

的第一个答案的激烈辩论后,让我借一些观点:

,往往出现是如何处理的,例如身份验证信息的请求碰到的第一个服务之后,再依次调用一个用例其他服务。现在的问题通常是:我是否交出认证信息(如用户名和组等),还是只交出令牌,客户端发送并让下一个服务再次查询认证信息。

据我所知,微服务社区尚未就解决此问题的“惯用”方式达成一致。我认为这是一个很好的理由,它在各种应用程序中提出了不同的要求。有时候,只有在第一个服务中需要进行身份验证才会受到外部请求的影响 - 那么请不要将太多的工作放在身份验证中。我认识的大多数系统仍然有更高的要求,因此需要在认证方面进一步的复杂程度。

让我来看看如何解决这个问题:最简单的方法是将客户端在后端服务之间发送的访问令牌交给他人。是的 - 这种方法要求每次服务在每次遇到请求时都要重新查询用户信息。如果(并且我认为这不会在您的系统中发生这种情况)每个请求有25个跨服务呼叫 - 这很可能意味着在某种认证服务中有25个呼叫。大多数人现在会开始尖叫恐怖的重复 - 但让我们换个角度来看:如果同一个系统是一个结构良好的庞然大物,你仍然可以在不同的地方进行这些调用(可能每次打一个数据库)你的过程。微服务体系结构中的这些调用的重大问题是网络开销,这是事实 - 如果做错了,它会杀了你!我会给你我们所采取的解决方案,并在我们的重负载下运行良好:

我们开发了一个令牌服务(我们将很快开放采购)。除了存储令牌,过期日期和一些无模式JSON内容的组合外,此服务不做任何其他事情。它有一个非常简单的REST界面,可以让你创建,无效,扩展和读取令牌及其内容。该服务具有多个后端,可根据其运行环境进行配置。出于开发目的,它有一个简单的内存中存储,不会以任何方式同步,保留或复制。对于生产环境,我们编写了一个后端,用于在多个实例之间同步这些令牌(包括所有诸如仲裁,异步持久等等)。这个后端使我们能够很好地扩展这项服务;这是我提出的解决方案的前提:如果每次服务节点在每次收到请求时都必须获取与令牌相关的信息,则提供它的服务必须非常快!我们的实现返回令牌及其信息的时间远远少于5毫秒,我们相信我们可以进一步降低这一指标。

我们的另一个策略是编排对令牌服务产生较重查询的服务(与仅检查令牌有效性/存在相比,接收内容比较昂贵),以使它们位于相同的物理节点上或靠近将网络延迟降至最低。

什么是更一般的消息:只要数量或这些调用与处理的内容量保持不耦合,就不要害怕跨服务调用(不好的示例here)。被更频繁地调用的服务需要更加仔细地设计,并且他们的性能需要经过非常优化以具有最后的毫秒。这种系统关键服务中的DB-Hits例如是绝对的Nogo,但有些设计模式和体系结构可以帮助您避免它们!

您可能已经检测到我没有直接回答您的问题进行辩论。为什么?我强烈反对在服务之间共享数据库。即使这些数据库是无模式的,您也会将两个服务结合在一起,而不会显示这种依赖关系。一旦你决定重新构造一个令牌服务中的数据,并且即使只是阅读这个数据库,还有另外一个服务 - 你只是搞砸了两个服务,你可能会意识到它太迟了,因为依赖不透明。服务中的状态/数据只能通过定义良好的接口来访问,以便可以很好地抽象,开发和独立测试。在我看来,改变一个服务中的持久化技术或结构不应该搞砸,甚至不需要改变其他服务。通过它的API独立访问服务,可以重构,重建甚至完全重写服务,而不必依赖其他服务。这就是所谓的解耦!

让我知道这是否有帮助!

+0

你提出了一些我基本同意的观点。诀窍是如何给猫耳鸣。您可以拥有定义良好的界面的服务,但为了调用它,您需要输入参数。 在我的问题中,定义良好的接口是Spring bean(没有说所有接口都必须是HTTP),它从共享数据库中提取数据。它需要密钥才能这样做,并且使用请求头将密钥从服务传递到服务。 –