Как разрешить имена авторов книг в мире микросервисов?

Поэтому я начинаю путешествие по микросервисам. Я провел несколько часов в Интернете, пытаясь погрузиться в эту тему.

Одной из концепций, которые я пока не понимаю, является идея не использовать 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"
  }
}]

Ответ 1

Есть, по крайней мере, три способа, которые я могу придумать, чтобы решить эту проблему.

  1. Модель документа NoSQL DB: вместо использования SQL DB рассмотрите возможность использования модели NoSQL для модели документов, такой как Mongo DB. Поэтому вместо реляционной БД с таблицами, такими как Books и Authors и таблицей AuthorBooks, которые все соединены на пару внешних ключей, вы можете использовать документ NoSQL DB, такой как Mongo, где ваши книги хранятся как тип документа, в формате BSON который выглядит почти идентично JSON в вашем вопросе. Хорошей особенностью таких документов, как Mongo, является то, что вы можете настроить индекс в JSON внутри документа Book на Author, тем самым улучшив время вашего запроса. Это довольно хорошо обсуждается в NoSQL Distilled by Martin Fowler (раздел 2.2 и глава 9).
  2. Разрыв отношения внешнего ключа, чтобы ссылочная целостность поддерживалась службой вместо БД: вместо того, чтобы полагаться на реляционную БД для обеспечения ссылочной целостности для вас (посредством обслуживания внешних ключей), ограничивайте доступ БД только к вашему микросервису и поддерживать целостность внешних ключей самим сервисом. Эта тактика обсуждается Сэмом Ньюманом в " Building Microservices" на стр. 84-85.
  3. Денормализовать БД: вместо того, чтобы иметь две таблицы для книг и авторов, просто объедините их в денормализованную таблицу. Итак, создайте новую таблицу, в которой информация для ваших книг дублируется, а информация об авторе уникальна для каждой книги в строке. Это уродливо. Поиски теперь имеют большее пространство для поиска, но это просто. Например, что-то вроде следующего формата:

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

Ответ 2

основная идея потребовать две отдельные услуги представляется сомнительной в этом случае, поскольку 1 автор, возможно, написал N книг, так же как и 1 книга может иметь N авторов. а также идея использования собственной базы данных представляется сомнительной - потому что есть библиотеки подобно node-isbn, которые можно обернуть в службу, которую можно запросить для автора, названия и номера ISBN.

Ответ 3

Для меня есть несколько вариантов, которые мы можем выбрать:

  • Сделайте сопоставление на сервере. книга получает список книг из БД, а затем получает authorIds, используя их для внутреннего вызова службы автора для получения имени автора.

  • Пусть клиент делает ленивую загрузку. В этом случае книжный сервис возвращает список книг (id, name, authorId). Затем клиенту необходимо агрегировать список authorId и обратиться к автору, чтобы получить имя авторов. Наконец, клиент сам делает карту.

  • Денормализация БД. У нас есть 2 варианта

options 1: Добавить стол столбца authorName для записи DB.

options 2: Создайте новую базу данных NoSQL для кэширования данных как из книги, так и из автора. С помощью этой опции он также подходит для крупномасштабного приложения, где объем запроса на получение данных большой (или даже нужен поиск и другие требования к запросу).

В приведенных выше вариантах. Мы должны убедиться, что каждое изменение в таблице авторов должно быть синхронизировано с связанной денормализованной информацией.

Ответ 4

Мой предпочтительный способ будет выглядеть так:

Во-первых, как уже упоминалось другими, можно утверждать, что требуется AuthorService, или если он слишком близко находится в Book и поэтому может быть частью BookService.

Итак, для этого примера я PersonService его PersonService, потому что таким образом ваш будущий ConferenceService мог бы его использовать.

Следуя подходу Microservice, вы должны знать о двух целях, которые вы хотите достичь:

  • Слабая связь
  • Когезионное поведение

это означает, что этим двум службам не разрешено совместно использовать базу данных (это может быть одно и то же физически, но не логически), так что 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 (entity in) PersonService. Эта связь является свободной, потому что Link менее вероятно, будет изменяться как представление Person протяжении всего вашего приложения. Приписывая author поля, вы также получаете семантику отношения между Book и Person. Конечно, интерфейсные приложения, как правило, не хотят, чтобы столько запросов на предоставление страницы, это нужно учитывать, расширяя эти Links. Я предпочитаю иметь Model -objekt, которая содержит только Links и Representation -object, которые имеют ссылки своей соответствующей модели, расширенные путем вызова Link. В тех случаях, когда вы не хотите делать кеширование, основанное на времени, это оказалось очень ценным для меня.

Но вещи могут быть очень сложными. Предположим, что правило "Объект домена может быть испущен только соответствующей службой" для достижения когезионного поведения. Это означает, что только BookService разрешено доставлять Book s. Теперь представьте себе такую просьбу, как "все книги Мартина Фаулера". Какую услугу следует запрашивать? Следуя приведенному выше правилу, это должен быть BookService. Но как BookService знает о чем-то, что называется Мартин Фаулер, он просто знает Books? В таком случае есть вещь, называемая неавторизированным кешем (который также может сохраняться в БД). Это просто означает, что BookService разрешено хранить Person в кеше или в базе данных, но не разрешено делиться ими с другими. Таким образом, вышеприведенное правило все еще соблюдается, а поведение Cohesive все еще под рукой. Неавторизованного кэш не нужно, чтобы отразить полный объект домена Person, но все, что необходимо для выполнения UseCases.