如何处理微服务架构中的共享状态?

时间:2015-02-27 14:44:20

标签: deployment architecture integration-testing microservices test-environments

在我们公司,我们正在从庞大的单片应用程序转变为微服务架构。这个决定的主要技术驱动因素是需要能够独立扩展服务和开发的可扩展性 - 我们有十个Scrum团队在不同的项目(或者微服务')中工作。

转型过程非常顺利,我们已经开始受益于这种新技术和组织结构的优势。另一方面,现在,我们正在努力解决一个主要的痛点:如何管理“状态”。这些微服务之间的依赖关系

让我们举一个例子:其中一项微服务涉及用户和注册。这项服务(让我们称之为X)负责维护身份信息,因此是用户“#”的主要提供者。其余的微服务都非常依赖于这一点。例如,有一些服务负责依赖于这些用户ID的用户配置文件信息(A),用户权限(B),用户组(C)等,因此需要在这些服务之间维护一些数据同步(即服务A不应该具有未在服务X中注册的userId的信息)。我们目前通过使用RabbitMQ通知状态更改(例如,新注册)来维持此同步。

你可以想象,有许多 Xs:很多'主要'服务和它们之间更复杂的依赖关系。

管理不同的开发/测试环境时出现了主要问题。每个团队(以及每个服务)都需要经历多个环境才能实现一些代码:持续集成,团队集成,验收测试和实时环境。

显然,我们需要在所有这些环境中工作的所有服务来检查系统是否正在整体运行。现在,这意味着为了测试依赖服务(A,B,C,...),我们不仅要依赖服务X,还要依赖服务状态。 因此,我们需要以某种方式维护系统完整性并存储全局&连贯状态

我们当前的方法是从实时环境获取所有数据库的快照,进行一些转换以缩小和保护数据隐私,并在特定环境中进行测试之前将其传播到所有环境。在组织和计算资源方面,这显然是一个巨大的开销:我们有十个持续集成环境,十个集成环境和一个验收测试环境,所有这些都需要进行更新。经常使用来自实时和最新版本代码的共享数据。

我们正在努力寻找一种更好的方法来缓解这种痛苦。目前我们正在评估两个选项:

  1. 使用类似Docker的容器进行所有这些服务
  2. 每个服务有两个版本(一个用于开发该服务,另一个用作沙箱,供其他团队在开发和集成测试中使用)
  3. 这些解决方案都不会减轻服务之间共享数据的痛苦。我们想知道其他一些公司/开发人员如何解决这个问题,因为我们认为这在微服务架构中必然是常见的。

    你们是怎么做到的?你也有这个问题吗?有什么建议吗?

    很抱歉很长的解释,非常感谢!

3 个答案:

答案 0 :(得分:7)

这次我从不同的角度阅读了你的问题,所以这里有一个“不同意见”。我知道这可能为时已晚,但希望它有助于进一步发展。

看起来shared state是错误解耦的结果。在“正确”的微服务架构中,所有微服务都必须在功能上而不是逻辑上进行隔离。我的意思是所有三个user profile information (A), user permissions (B), user groups (C)在功能上看起来都相同,或多或少在功能上是连贯的。它们似乎是一个具有连贯存储的user microservice。我没有看到任何解耦的原因(或者至少你没有告诉他们)。

所以真正的问题与微服务隔离有关。理想情况下,每个微服务都可以作为完整的独立产品生效,并提供明确定义的业务价值。在详细阐述系统架构时,我们将其分解为微小的逻辑单元(在您的情况下为A,B,C等,甚至更小),然后定义功能相干的子组。我不能告诉你如何做到这一点的确切规则,也许是一些例子。单元之间复杂的通信/依赖关系,无处不在的语言中有许多常用术语,因此看起来这些单元属于同一个功能组,因而属于微服务。

所以从你的例子来看,由于只有一个存储,你只能像你一样管理它的一致性。

BTW我想知道你解决问题的实际方法是什么?如果你喜欢我的想法也可以接受它。

答案 1 :(得分:1)

让我试着重新解决这个问题:

<强>行动者:

  • X:UserIds(帐户状态)
    • 提供服务以获取ID(基于凭据)和帐户状态
  • A:UserProfile
    • 使用X检查用户帐户的状态。存储名称以及帐户链接
    • 提供基于ID
    • 获取/编辑名称的服务
  • B:UserBlogs
    • 以相同方式使用X.当用户写一个
    • 时,存储博客文章以及指向帐户的链接
    • 使用A根据用户名搜索博客帖子
    • 根据ID
    • 提供博客条目的服务获取/编辑列表
    • 提供服务以根据名称搜索博客帖子(依赖于A)
  • C:MobileApp
    • 将X,A,B的功能包装到移动应用
    • 提供上述所有服务,依赖与所有其他人明确定义的沟通合同(遵循@neleus声明)

<强>要求:

  1. X,A,B,C队的工作需要解耦
  2. X,A,B,C的集成环境需要使用最新功能进行更新(以便执行集成测试)
  3. X,A,B,C的集成环境需要有足够的&#39;数据集(为了执行负载测试,以及查找边缘情况)
  4. 遵循@eugene的想法:对每个团队提供的每项服务进行模拟将允许1)和2)

    • 费用是团队的更多发展
    • 还要维护模拟以及主要功能
    • 阻碍事实是你有一个单片系统(你还没有一套干净的定义好/隔离的服务)

    建议的解决方案:

    如何使用要解析的主数据集共享环境3)?每个提供的服务都是&#39; (即在生产中运行)将是可用的。每个团队都可以选择他们将从这里使用哪些服务以及他们将从自己的环境中使用哪些服务

    我可以看到的一个直接缺点是共享状态和数据的一致性。

    让我们考虑针对主数据运行自动化测试,例如:

    • B更改名称(由A拥有)以便处理其博客服务
      • 可能会破坏A或C
    • A更改帐户的状态,以便处理某些权限方案
      • 可能会破坏X,B
    • C会在同一帐户中更改所有内容
      • 打破所有其他人

    主数据集很快就会变得不一致,并失去上述要求3)的价值。

    因此,我们可以添加一个传统的&#39;共享主数据上的图层:任何人都可以从完整集中读取,但只能修改他们创建的对象?

答案 2 :(得分:0)

从我的角度来看,只有对象使用的服务应该具有状态。让我们考虑一下您的示例:服务X负责用户ID,服务A负责配置文件信息等。让我们假设用户Y具有一些安全令牌(例如可以通过使用它来创建&#39;用户名和密码 - 应该是唯一的)系统条目。然后,客户端包含用户信息,将安全令牌发送到服务X.服务X包含有关链接到此令牌的用户ID的信息。在新用户的情况下,服务X创建新ID并存储它的令牌。然后服务X将ID返回给用户对象。用户对象通过提供用户ID向服务A询问用户简档。如果存在该ID,则服务A获取ID并询问服务X.服务X发送肯定答案,然后服务A可以通过用户ID搜索简档信息或者要求用户提供这样的信息以便创建它。相同的逻辑应该与B和C服务一起使用。他们必须与其他人交谈,但他们不需要了解用户状态。

关于环境的几句话。我建议使用puppets。这是自动化服务部署过程的方法。我们正在使用木偶在不同的环境中部署服务。木偶脚本到达并允许灵活配置。