如何解析微服务世界中书籍的作者姓名?

Posted

技术标签:

【中文标题】如何解析微服务世界中书籍的作者姓名?【英文标题】:How do I resolve the authors names of books in microservice world? 【发布时间】:2019-01-03 14:18:50 【问题描述】:

所以我开始了一段微服务之路。我在网上花了几个小时试图让自己沉浸在这个话题中。

我还没有完全理解的一个概念是不使用 SQL 连接,因此有一个小型独立数据库供作者使用,书籍也是如此。

所以我理解以下SQL:

BooksTable - id, name, authorid
AuthorsTable - id, name

select book.name, author.name from book 
join author on book.authorId = author.id

在 Node.js 世界中

index.js

app.get('/api/books' bookDomain.get());

bookDomain.js

exports.get = () => 
  const books = bookService.get();

  const authors = authorService.get();

  /*
    This is where I'm lost: how do you achieve the simple SQL 
    above? I'm assuming in the domain is where this information is 
    "joined"? am I correct?
  */
;

服务

Database1
**bookService.js**
database context

Database2
**authorService.js**
database context

预期数据(类似的东西,基本上我是说 JSON 应该是返回类型)

[
  book 
    "name": "Book 1",
    "author": "Author Name 1"
  
,

  book 
    "name": "Book 2",
    "author": "Author Name 2"
  
]

【问题讨论】:

如果您要使用每个数据库路由的微服务,您的两个选择是在应用程序端加入数据或通过外键在第三种 Web 服务方法中加入数据(因此即使您的数据在物理上是分开的实际上仍然使用关系数据,只是没有 sql 连接的便利)。 microservices.io/patterns/data/database-per-service.html 【参考方案1】:

我的首选方式如下所示:

首先,正如其他人已经提到的那样,是否需要AuthorService,或者它是否离Book 太近,因此可能是BookService 的一部分,这是有争议的。

所以,对于这个例子,我将它命名为PersonService,因为这样你的未来ConferenceService 可以使用它。

通过遵循微服务方法,您必须了解要实现的两个目标:

松散耦合 内聚行为

这意味着这两个服务不允许共享一个数据库(物理上可能相同,但逻辑上不同),因此BookService 无法修改@987654327 的数据@。这必须由PersonService 专门完成。否则,内聚行为将面临风险。 所以我们有两个服务,每个服务都有一个单独的数据库。

我假设这两个服务有一个 RESTful API,这很好,因为我们想松散地耦合。 JSON 可能如下所示:

[
    book 
        "name": "Book 1",
        "author": 
            "name": "Author Name 1"
            "href": "apis.yourdomain.com/personservice/persons/1"
            "type": "application/json"
        

    
,

    book 
        "name": "Book 2",
        "author": 
            "name": "Author Name 2"
            "href": "apis.yourdomain.com/personservice/persons/2"
            "type": "application/json"
        
    
]

如您所见,这些作者仅表示为Link 引用(一个实体)PersonService。这种耦合是松散的,因为 Link 在应用程序的整个生命周期内不太可能更改为 Person 的表示形式。 通过命名字段author,您还可以获得BookPerson 之间关系的语义。 当然,前端应用程序往往不希望有那么多请求来呈现页面,这必须通过扩展那些Links 来考虑。我更喜欢有一个Model-objekt,它只包含Links 和一个Representation-object,它通过调用Link 扩展了其相应模型的链接。如果您不想进行基于时间的缓存,这对我来说非常有价值。

但是事情很容易变得复杂。假设像“一个域对象只能由相应的服务发出”这样的规则,以实现内聚行为。这意味着只允许BookService 传递Books。现在想象一个请求,比如“Martin Fowler 的所有书籍”。应该查询哪个服务?按照上述规则,它应该是BookService。但是BookService 怎么知道一个叫 Martin Fowler 的东西,他只知道Books? 在这种情况下,有一种称为非权威缓存的东西(也可以保存在数据库中)。这只是意味着BookService 允许将Persons 存储在缓存或数据库中,但不允许与他人共享。 这样,仍然遵循上述规则,并且内聚行为仍然存在。 非权威缓存不需要反映完整的域对象Person,而是满足用例所需的一切。

【讨论】:

【参考方案2】:

对我来说,我们可以选择一些选项:

在服务器上进行映射。 book 服务从 DB 中获取书籍列表,然后获取 authorId,使用它们在内部调用作者服务以获取作者姓名。

让客户端进行延迟加载。在这种情况下,图书服务返回图书列表(id、name、authorId)。然后,客户端需要聚合 authorId 列表并调用作者服务以获取作者姓名。最后,客户端自己做地图。

非规范化数据库。我们有两个选择

选项 1:将 authorName 列添加到图书数据库。

选项 2:拥有一个新的 NoSQL 数据库来缓存书籍和作者的数据。使用此选项,对于获取数据的请求量很大(甚至需要搜索和其他查询要求)的大规模应用程序也很有用。

在上述 2 个选项中。我们需要确保对作者表的每次更改都需要同步到相关的非规范化信息。

【讨论】:

【参考方案3】:

在这种情况下,要求两个独立服务的基本想法似乎存在问题, 因为1作者可能写过N书,就像1书可以有N作者一样。而且,必须使用自己的数据库的想法似乎是有问题的 - 因为有类似的图书馆 node-isbn,可以将其包装成服务,可以查询作者、标题和 ISBN 号。

【讨论】:

【参考方案4】:

我至少可以想到三种方法来解决这个问题。

    文档模型 NoSQL DB: 考虑使用像 Mongo DB 这样的文档模型 NoSQL DB,而不是使用 SQL DB。因此,您可以使用像 Mongo 这样的文档 NoSQL DB,将您的书籍存储为文档输入 BSON 格式,看起来与您问题中的 JSON 几乎相同。像 Mongo 这样的文档数据库的一个很好的特性是,您可以在 Author 上的 Book 文档内的 JSON 上设置索引,从而缩短查询时间。 Martin Fowler 在NoSQL Distilled 中对此进行了很好的讨论(第 2.2 节和第 9 章)。 打破外键关系,以便由服务而不是 DB 来维护引用完整性: 与其依赖关系 DB 为您强制执行引用完整性(通过维护外键)限制访问数据库仅用于您的微服务,并通过您的服务本身维护外键的完整性。 Sam Newman 在第 84-85 页的Building Microservices 中讨论了这种策略。 非规范化 DB: 不必为书籍和作者分别设置两个表,只需将它们组合成一个 denormalized table。因此,创建一个新表,其中您的书籍信息是重复的,并且作者信息对于每本书的每一行都是唯一的。它很丑。搜索现在有更大的搜索空间,但也很简单。例如,类似于以下格式:

    book_id | book_name              | book_author
    =====================================================
          1 | NoSQL Distilled        | Pramod J. Sadalage
    -----------------------------------------------------
          1 | NoSQL Distilled        | Martin Fowler
    -----------------------------------------------------
          2 | Building Microservices | Sam Newman

【讨论】:

好答案。作为附录,我还会质疑服务的边界是否正确。在此示例中,作者和书籍似乎紧密耦合,在两个不同的服务中将它们分开可能甚至没有意义。 感谢您的夸奖。作者和书籍域看起来确实紧密耦合。但是,如果您想将它们拆分为不同的服务,我的问题是作者是否需要拆分到自己的域中。是否需要在他们的书的上下文之外访问作者?如果不是,您可能不想梳理出单独的微服务。对于微服务,一种思想流派是您将一项微服务限制在一个有界上下文(即书籍域和作者域)中。 Building Microservices 在第 31-34 页讨论了这一点。 @entpnerd 在理论和实际应用之间可能存在差异......因为当将它们作为两个完全独立的域/服务时,必须创建大量重复记录,以便代表它(书籍/作者域有些巨大,并且将它们分开a)增加了更多的容量,b)保持它们的完整性需要更多的处理)......例如。两个服务都从中获取的一个数据库似乎是最实用的解决方案。 @MartinZeitler 这是真的。理论与实践之间往往存在差异。而对于现有系统,通常是一个问题,即对理想的改变是否真的值得。除非您需要访问书籍上下文之外的作者域,否则将两者分开可能不值得。

以上是关于如何解析微服务世界中书籍的作者姓名?的主要内容,如果未能解决你的问题,请参考以下文章

微服务笔记:百万程序员都读过的两本书!

微服务笔记:百万程序员都读过的两本书!

微服务笔记:百万程序员都读过的两本书!

微服务笔记:百万程序员都读过的两本书!

微服务笔记:百万程序员都读过的两本书!

微服务笔记:百万程序员都读过的两本书!