在我们公司,我们正在从一个巨大的单片应用程序过渡到微服务架构。这一决定的主要技术驱动因素是需要能够独立扩展服务和开发的可扩展性——我们有十个scrum团队在不同的项目(或"微服务")中工作。
过渡过程非常顺利,我们已经开始受益于这种新的技术和组织结构的优势。另一方面,我们正在努力解决的一个主要问题是:如何管理这些微服务之间依赖关系的"状态"。
举个例子:其中一个微服务处理用户和注册。这个服务(我们称之为X)负责维护身份信息,因此是用户"id"的主要提供者。其余的微服务都强烈依赖于此服务。例如,有一些服务负责依赖于那些用户ID的用户简档信息(A)、用户权限(B)、用户组(C)等,因此需要在这些服务之间保持一些数据同步(即,服务A不应该具有未在服务X中注册的用户ID的信息)。我们目前通过使用RabbitMQ通知状态更改(例如新注册)来保持这种同步。
正如你所能想象的,有许多X:许多"主"服务以及它们之间许多更复杂的依赖关系。
主要问题出现在管理不同的开发/测试环境时。每个团队(因此,每个服务)都需要经历几个环境才能使一些代码生效:持续集成、团队集成、验收测试和生效环境。
显然,我们需要在所有这些环境中工作的所有服务来检查系统是否作为一个整体工作。现在,这意味着为了测试依赖服务(A、B、C…),我们不仅必须依赖于服务X,还必须依赖于它的状态因此,我们需要以某种方式保持系统的完整性,并存储全局&相干态。
我们目前的方法是从实时环境中获取所有数据库的快照,进行一些转换以缩小和保护数据隐私,并在特定环境中测试之前将其传播到所有环境。这显然是一个巨大的开销,无论是在组织上还是在计算资源上:我们有十个连续集成环境、十个集成环境和一个验收测试环境,所有这些环境都需要频繁地用来自实时和最新版本代码的共享数据"刷新"。
我们正在努力寻找一种更好的方法来缓解这种痛苦。目前,我们正在评估两种选择:
- 为所有这些服务使用类似docker的容器
- 每个服务有两个版本(一个用于该服务的开发,另一个作为沙盒,供其他团队在开发和集成测试中使用)
这些解决方案都无法缓解服务之间共享数据的痛苦。我们想知道其他一些公司/开发人员是如何解决这个问题的,因为我们认为这在微服务架构中一定很常见。
你们做得怎么样?你也有这个问题吗?有什么建议吗?
抱歉解释太长,非常感谢!
这次我从不同的角度阅读了你的问题,所以这里有一个"不同的观点"。我知道这可能为时已晚,但希望这有助于进一步发展。
看起来shared state
是错误解耦的结果。在"正确"的微服务架构中,所有微服务都必须在功能上而不是在逻辑上隔离。我的意思是,所有三个user profile information (A), user permissions (B), user groups (C)
在功能上看起来都是相同的,并且或多或少在功能上是连贯的。它们似乎是具有一致存储的单个user service
,尽管它看起来可能不是微服务。我在这里看不出任何脱钩的原因(或者至少你没有告诉他们)。
从这一点开始,将其拆分为更小的独立部署单元可能会带来更多的成本和麻烦,而不是好处。应该有一个重要的原因(有时是政治原因,有时只是缺乏产品知识)
因此,真正的问题与微服务隔离有关。理想情况下,每个微服务都可以作为完整的独立产品生存,并提供定义良好的业务价值。在阐述系统架构时,我们将其分解为微小的逻辑单元(在您的情况下为A、B、C等,甚至更小),然后定义功能连贯的子组。我不能告诉你如何做到这一点的确切规则,也许还有一些例子。单元之间复杂的通信/依赖关系,许多通用术语在其普遍存在的语言中,因此看起来这些单元属于同一个功能组,因此属于单个服务。
因此,从您的示例来看,由于只有一个存储,所以您只能像以前一样管理其一致性。
顺便说一句,我想知道你解决问题的实际方法是什么?
让我试着重新表述这个问题:
参与者:
- X: UserId(帐户状态)
- 提供获取ID(基于凭据)和帐户状态的服务
- A: 用户配置文件
- 使用X检查用户帐户的状态。存储名称以及帐户链接
- 提供基于ID获取/编辑名称的服务
- B: 用户博客
- 以同样的方式使用X。当用户写博客时,将博客文章与帐户链接一起存储
- 使用A根据用户名搜索博客文章
- 提供基于ID获取/编辑博客条目列表的服务
- 提供基于名称搜索博客文章的服务(依赖于A)
- C: MobileApp
- 将X、A、B的功能封装到移动应用程序中
- 提供上述所有服务,依赖于与所有其他人明确定义的通信合同(遵循@neleus声明)
要求:
- X、A、B、C团队的工作需要脱钩
- X、A、B、C的集成环境需要使用最新功能进行更新(以便执行集成测试)
- X、A、B、C的集成环境需要有"足够"的数据集(以便执行负载测试和查找边缘案例)
遵循@eugene的想法:为每个团队提供的每项服务提供模拟将允许1)和2)
- 成本是团队的更多开发
- 还维护了模型以及主要功能
- 障碍是您有一个单一的系统(您还没有一套定义良好/隔离的干净服务)
建议的解决方案:
使用一组要解决的主数据创建一个共享环境(3)怎么样?每一项"交付的服务"(即在生产中运行)都是可用的。每个团队都可以选择他们将在这里使用哪些服务,以及他们将在自己的环境中使用哪些服务
我看到的一个直接的缺点是数据的共享状态和一致性。
让我们考虑针对主数据运行的自动化测试,例如:
- B更改名称(归A所有)以使用其博客服务
- 可能会损坏A或C
- A更改帐户的状态以处理某些权限方案
- 可能会破坏X、B
- C在相同的帐户上更改所有内容
- 打破所有其他
主数据集将很快变得不一致,并失去其对上述要求3)的价值。
因此,我们可以在共享的主数据上添加一个"常规"层:任何人都可以从全集中读取,但只能修改他们创建的对象?
从我的角度来看,只有使用服务的对象才应该具有状态。让我们考虑您的示例:服务X负责用户Id,服务A负责配置文件信息,等等。让我们假设用户Y在系统中有一些安全令牌(例如,可以使用其用户名和密码创建,应该是唯一的)条目。然后,包含用户信息的客户端将安全令牌发送到服务X。服务X包含关于链接到该令牌的用户ID的信息。如果是新用户,服务X将创建新的ID并存储其令牌。然后,服务X向用户对象返回ID。用户对象通过提供用户ID来向服务A询问用户配置文件。服务A获取该ID并询问服务X是否存在该ID。服务X发送肯定的答案,然后服务A可以通过用户ID搜索配置文件信息,或者要求用户提供这样的信息来创建它。同样的逻辑应该适用于B和C服务。他们必须相互交谈,但不需要了解用户状态。
对环境只字不提。我建议用木偶。这是实现服务部署过程自动化的方法。我们正在使用木偶在不同的环境中部署服务。木偶脚本是触手可及的,并允许灵活的配置。