微服务和noSQL - 丰富微服务架构中数据的最佳实践

时间:2015-05-17 16:03:12

标签: microservices

我想计划一个在我的架构中管理丰富数据的解决方案 更清楚的是,我有几十个微服务 让我们说 - 乡村,建筑,地板,工人。
全部运行在单独的NoSql数据存储中。

当我从工作服务获取数据时,我想要提供楼层名称(工作人员正在处理),建筑物名称和国家名称。

解决方法1。
客户端将查询所有微服务 问题 - 多个请求并使客户了解结构 我知道多个请求不应该打扰我,但我相信在一次调用中返回描述实体的json更好。

解决方案2。
创建一个从多个服务中检索数据的业务流程 问题 - 如果数据(例如实体名称)未存储在数据库中的同一文档中,则很难按这些字段进行排序和筛选。

解决方案3。
在保存实体之前,例如工人,调用所有其他服务并填写相关数据(建筑物名称,国家名称) 问题 - 当建筑物名称发生变化时,它不会反映在工人服务中。

解决方案4.
(这是我能想到的最好的一个) 创建订阅代理并接收所有实体更改的流程 对于每个实体,它更新所有相关实体 当实体发生变化时,让我们说建筑物名称更改,它会更新所有包含建筑物名称的文件 问题: 每项服务都必须知道可以更新的内容。 当发生尾随更新时,它不应该再次更新代理(递归更新),因此这可能会使微服务变得复杂。

解决方案5.
保持一切正常化。在ElasticSearch中进行文件管理和排序。 问题:在ES中保持标准化数据在性能方面太昂贵了

4 个答案:

答案 0 :(得分:1)

很难就解决方案N级别提出建议,但以下建议可以避免某些问题:

  1. 为实体使用全局唯一标识符。例如,通过为键值指定某种URI。

  2. 全局ID还可以简化更新,因为您可以跟踪实际更改的内容,名称或实体。 (实体与全局URI具有一对一的关系)

  3. CAP定理说你只能从CAP中选择两个。你想要一个CA架构吗?还是CP?或者AP?这将极大地影响您分发数据的方式。

  4. 对于“排序和过滤”,有MapReduce方法,可以分配计算出来的负担。

  5. 仔细考虑规范化/非规范化的平衡。如果您的服务在URI上运行,您可以拥有一个将URI转换为标签(名称,描述等)的服务,但您无需在任何地方保留冗余信息并进行更新。不要进行初步优化,但要尽可能长时间地保持数据标准化。这样,工人甚至可能不需要建筑物名称,但它是全球ID。微服务从另一个微服务中查找元数据。

  6. 换句话说,最小化服务之间共享的密钥数量,作为关注点分离的一部分。

  7. 专注于底层模型,而不是JSON来往。正确建模系统中的数据不仅可以节省JSON调用。

  8. 对于NoSQL,请看一下Riak数据库:它具有可调节的CAP属性IIRC。即使您不这样使用它,阅读它的文档也可能有助于为您的分布式微服务系统提供合适的架构。 (当然,如果你有基本上并行的系统,这适用)

答案 1 :(得分:1)

我看到Netflix做的一件事(我喜欢)是为这样的东西创建中介服务。因此,可能是一个新的中介服务,可以调用其他服务来收集所有数据,然后使用Country,Building,Floor,Worker创建统一输出。

你甚至可以更进一步,尝试提出一个方案,提供你想要包含在输出中的资源作为输入。

所以我猜这与你的解决方案非常匹配2.我注意到你提到的解决方案2存在对DB的排序/过滤的担忧。我认为如果你使用的是NoSQL,那么它必须是有原因的,更常见的不是性能的原因。我认为如果做错了那么是的你会遇到问题,但是如果可搜索的所有相应字段都被正确键入并编入索引(正如@Roman Susi在他的第1点和第2点中提到的那样)那么我就不会看到这个这是一个问题。是的,这项服务只会与您的其他服务和数据存储的高潮一样快,因此它们必须快速。

现在,您可以保持您的个人微服务,让客户端调用一个服务,并封装将数据合并到这个新服务中的复杂性。

这是我在(https://www.youtube.com/watch?v=StCrm572aEs)中看到的视频...这是一个很长的视频但非常有用。

答案 2 :(得分:1)

首先,谢谢你的问题。它类似于文档DB的主要问题:如何从另一个集合中按字段对集合进行排序?我有自己的答案,所以我会试着评论你所有的解决方案:

解决方案1:如果客户希望独立地使用Countries / Building / Floors,那就太好了。但是,它并没有解决你在解决方案2中提到的问题 - 通过构建缓慢来排序10k工人

解决方案2:与解决方案1类似,如果所有客户需要的是列表丰富的工作人员,而不知道如何将其从多个部分组合

解决方案3:正如您所说,由于数据不一致而无法接受。

解决方案4:大部分时间都会工作。但是:

  • 巨大的数据重复。如果您有20个实体,那么您将获得x20数据。
  • 复杂性很大。 20个实体 - >更新相关数据的20种不同程序
  • 高凝聚力。您的所有服务必须彼此了解。由于更新过程,数据模型更改将传播到每个服务
  • 可疑的最终一致性。可以这样做,这样数据在失败后就会保持一致,但这并不容易

解决方案5:答案: - )

但是 - 你不想要一切。保留为分离的实体提供服务的分离服务,并在它们之上构建其他服务。

如果客户需要丰富的数据 - 构建返回丰富数据的服务,如解决方案2中那样。

如果客户希望通过过滤和排序显示丰富数据列表 - 构建一个服务,提供具有过滤和排序功能的丰富数据!可能,此类服务的实现将包含ES实例,该实例包含来自较低级别服务的缓存和索引数据。这里要说的是ES不必包含所有内容或在每个服务之间共享 - 由您来决定性能和基础架构资源之间的更好平衡。

答案 3 :(得分:1)

这是Linked Data可以帮助您的情况。

工作人员的Floor属性基本上是地板本身的URI(链接)。任何其他链接数据也应表示为URI。

使用一些JSON-LD建模它看起来像这样:

worker = {
  '@id': '/workers/87373',
  name: 'John',
  floor: {
    '@id': '/floors/123'
  }
}

floor = {
  '@id': '/floor/123',
  'level': 12,
  building: { '@id': '/buildings/87' }
}

building = {
  '@id': '/buildings/87',
  name: 'John's home',
  city: { '@id': '/cities/908' } 
}

这样客户端所要做的就是将BASE URL(如api.example.com)附加到@id并进行简单的GET调用。

为了消除来自客户端的额外呼叫负担(如果它是一个缓慢的移动设备),我们使用具有微服务的网关模式。网关可以很轻松地扩展这些链接并增加返回对象。它还可以并行执行多个调用。

因此网关将进行GET / floor / 123调用,并使用回复替换worker上的floor对象。