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

时间:2018-07-26 14:30:41

标签: node.js amazon-web-services aws-lambda microservices

因此,我正在开始微服务之路。我已经花了几个小时上网尝试使自己沉迷于这个主题。

我还不太了解的一个概念是不使用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"
  }
}]

4 个答案:

答案 0 :(得分:8)

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

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

答案 1 :(得分:4)

在这种情况下,需要两个单独的服务的基本想法令人怀疑, 因为1位作者可能写过N本书,而1本书也可以有N位作者。而且,必须使用自己的数据库的想法似乎令人怀疑-因为有node-isbn之类的库,可以将其包装到服务中,可以查询作者,标题和ISBN号。

答案 2 :(得分:2)

对于我来说,我们可以选择以下选项:

  • 在服务器上执行映射。图书服务从数据库获取图书列表,然后获取authorId,并使用它们在内部调用作者服务以获取作者姓名。

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

  • 反规范化数据库。我们有2个选项

选项1:将authorName列添加到图书DB。

选项2:有一个新的NoSQL数据库来缓存书籍和作者的数据。有了此选项,它也适合大型应用程序,在这种应用程序中,获取数据的请求量很大(甚至需要搜索和其他查询要求)。

在上述2个选项中。我们需要确保对author表的所有更改都必须同步到相关的非规范化信息。

答案 3 :(得分:2)

我首选的方式如下:

首先,正如其他人已经提到的,是否需要AuthorService还是在Book上太近而可能成为BookService的一部分是有争议的。 / p>

因此,在此示例中,我将其命名为PersonService,因为您的未来ConferenceService可以使用它。

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

  • 松散耦合
  • 内聚行为

这意味着不允许 共享这两个服务(在物理上,但在逻辑上可能是相同的),因此BookService无法修改PersonService。这只能由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-对象,该对象的对应模型的链接通过调用Link进行了扩展。如果您不想进行基于时间的缓存,这对我来说非常有用。

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