简体   繁体   English

在微服务架构中管理与 MongoDb 的关系

[英]Managing relationships with MongoDb in a Microservices architecture

I've been working with microservices for some time now, always with relational databases.我使用微服务已经有一段时间了,总是使用关系数据库。 I am looking at MongoDb and I am not sure how to handle entity relationships involving different microservices.我正在查看 MongoDb,但我不确定如何处理涉及不同微服务的实体关系。 Here goes an example:这是一个例子:

public class Employee implements Serializable {
   private String id;
   ...
}

public class Department implements Serializable {
    private String id;
    private String desc;
    private List<Employee> employees = new ArrayList<>();
    ...
}

These two entities are managed by two different microservices, with a one-to-many relationship managed by the Department entity.这两个实体由两个不同的微服务管理,具有由Department实体管理的一对多关系。 So far, so good.到目前为止,一切都很好。

With a relational database (being an optional relationship and with the possibility of one employee belonging to several departments) I'd map this in the Departments microservice with one table containing two fields: employee_id and department_id .使用关系数据库(作为一个可选关系,并且一名员工可能属于多个部门),我会在Departments微服务中使用 map ,其中一个表包含两个字段: employee_iddepartment_id When the client calls getDepartmentWithEmployees(depId) this microservice will read the table and obtain the proper employees from the Employees microservice.当客户端调用getDepartmentWithEmployees(depId)时,此微服务将读取表并从Employees微服务中获取适当的员工。

But, in a MongoDb database, as far as I know, when I store a Department object it stores all associated Employee s.但是,据我所知,在 MongoDb 数据库中,当我存储Department object 时,它存储所有关联的Employee Is not that duplicating the information?这不是重复信息吗? Is there a way, maybe, where MongoDb don't store all info about the employees but just their id?有没有办法,也许,MongoDb 不存储有关员工的所有信息,而只存储他们的 ID? Or there is another answer?还是有别的答案?

I am pretty sure this is a very basic question, but I am new to all this stuff.我很确定这是一个非常基本的问题,但我对所有这些东西都很陌生。

Thanks in advance.提前致谢。

But, in a MongoDB database, as far as I know, when I store a Department object it stores all associated Employees.但是,据我所知,在 MongoDB 数据库中,当我存储部门 object 时,它会存储所有相关的员工。 Is not that duplicating the information?这不是重复信息吗?

First of all, the statement above is not correct.首先,上面的说法是不正确的。 From the MongoDB's perspective, whatever is provided as BSON is stored as it is.从 MongoDB 的角度来看,作为 BSON 提供的任何内容都按原样存储。 If you provide employees with the department then yes, it should.如果您为员工提供部门,那么是的,它应该。 You can apply partial updates after creating the department... (eg using $set operator).您可以在创建部门后应用部分更新...(例如使用$set运算符)。 But, I think the scope of your question is broader than this.但是,我认为您的问题的 scope 比这更广泛。

IMHO, creating nano-services for each document/table in the database is not a good approach.恕我直言,为数据库中的每个文档/表创建纳米服务不是一个好方法。 Especially, when the services only responsible for basic CRUD operation.特别是当服务只负责基本的 CRUD 操作时。 You should first define your bounded contexts, aggragate roots and etc... In short, do not try to design tables before mapping business requirements to domain objects.您应该首先定义您的有界上下文、聚合根等... 简而言之,在将业务需求映射到域对象之前不要尝试设计表。 What I'm trying to say is use DDD principles:)我想说的是使用 DDD 原则:)

These are the strategies that I found so far.这些是我目前发现的策略。 When designing microservices you should also consider pros and cons of each strategy.在设计微服务时,您还应该考虑每种策略的优缺点。 (See bottom for references.) (参见底部的参考资料。)

General Principles of Mapping Relational Databases to NoSQL关系型数据库映射到 NoSQL 的一般原则

  • 1:1 Relationship 1:1 关系
    • Embedding嵌入
    • Link with Foreign Key与外键链接
  • 1:M Relationship 1:M 关系
    • Embedding嵌入
    • Linking with Foreign Key与外键链接
    • (Hybrid) Bucketing Strategy (混合)分桶策略
  • N:M Relationship N:M 关系
    • Two-Way Referencing双向参考
    • One-Way Referencing单向参考

1:1 Relationship 1:1 关系

The 1:1 relation can be mapped in two ways;可以通过两种方式映射 1:1 关系;

  • Embed the relationship as a document将关系嵌入为文档
  • Link to a document in a separate collection链接到单独集合中的文档

Tables:表:

// Employee document
{
   "id": 123,
   "Name":"John Doe"
}

// Address document
{
   "City":"Ankara",
   "Street":"Genclik Street",
   "Nr":10
}

Example: Embedding (1:1)示例:嵌入 (1:1)

  • Advantage: Address can be retrieved with a single read operation.优点:可以通过一次读取操作来检索地址。

{
  "id": 123,
  "Name":"John Doe",
  "Address": {
    "City":"Ankara",
    "Street":"Genclik Street",
    "Nr":10
  } 
}

Example: Link with foreign key (1:1)示例:与外键链接 (1:1)

{
   "id": 763541685,  // link this
   "Name":"John Doe"
}

Address with document key;带文件密钥的地址;

{
   "employee_id": 763541685,
   "City":"Ankara",
   "Street":"Genclik street",
   "Nr":10
}

1:M Relationship 1:M 关系

Initial:最初的:

// Department collection
{
  "id": 1,
  "deparment_name": "Software",
  "department_location": "Amsterdam"
}

/// Employee collection
[
    {
      "employee_id": 46515,
      "employee_name": "John Doe"
    },
    {
      "employee_id": 81584,
      "employee_name": "John Wick"
    }
]

Example: Embedding (1:M)示例:嵌入 (1:M)

Warning:警告:

  • Employee list might be huge!员工名单可能很大!
  • Be careful when using this approach in write-heavy system.在写入繁重的系统中使用这种方法时要小心。 IO load would increase due to housekeeping operations such indexing, replicating etc. IO 负载会由于索引、复制等内务操作而增加。
  • Pagination on employees is hard!!!员工分页很难!!!
{
  "id": 1,
  "deparment_name": "Software",
  "department_location": "Amsterdam",
  "employess": [
                   {
                     "employee_id": 46515,
                     "employee_name": "John Doe"
                   },
                   {
                     "employee_id": 81584,
                     "employee_name": "John Wick"
                   }
               ]
}

Example: Linking (1:M)示例:链接 (1:M)

We can link department_id from employee document.我们可以从员工文档中链接 department_id。

  • Advantage: Easier pagination优点:更容易分页
  • Disadvantage: Retrieve all employees that are belong to department X. This query will need a lot of read operations!缺点: Retrieve all employees that are belong to department X.这个查询需要大量的读取操作!
[
    {
      "employee_id": 46515,
      "employee_name": "John Doe",
      "department_id": 1
    },
    {
      "employee_id": 81584,
      "employee_name": "John Wick",
      "department_id": 1
    }
]

Example: Bucketing Strategy (Hybrid 1:M)示例:分桶策略(混合 1:M)

  • Useful for cases like time series.对于时间序列等情况很有用。
  • Hybrid = Embedding + Linking混合 = 嵌入 + 链接
  • Advantage : Single read to fetch 100 employees at a time, allowing for efficient pagination .优点:一次读取 100 名员工,允许有效的分页
  • See Building with Patterns: The Bucket Pattern请参阅使用模式构建:桶模式

We'll split the employees into buckets with maximum of 100 employees in each bucket.我们将员工分成多个桶,每个桶中最多有 100 名员工。

{
    "id":1,
    "Page":1,
    "Count":100,
    "Employees":[
        {
            "employee_id": 46515,
            "employee_name": "John Doe"
        },
        {
            "employee_id": 81584,
            "employee_name": "John Wick"
        }
    ]
}

N:M Relationship N:M 关系

To choose Two Way Embedding or One Way Embedding , the user must establish the maximum size of N and the size of M.要选择Two Way EmbeddingOne Way Embedding ,用户必须确定 N 的最大尺寸和 M 的尺寸。
For example;例如; if N is a maximum 3 categories for a book and M is a maximum of 5,000,000 books in a category you should pick One Way Embedding.如果 N 是一本书最多 3 个类别,M 是一个类别中最多 5,000,000 本书,则您应该选择 One Way Embedding。
If N is a maximum 3 and M is a maximum of 5 then Two Way Embedding might work well.如果 N 最大为 3,M 最大为 5,则双向嵌入可能会很好地工作。 schema basics架构基础

Example: Two-Way Referencing (N:M)示例:双向参考 (N:M)

In Two Way Embedding we will include the Book foreign keys under the book field in the author document.在双向嵌入中,我们将在作者文档的 book 字段下包含 Book 外键。

Author collection作者合集

[
    {
       "id":1,
       "Name":"John Doe",
       "Books":[ 1, 2 ]
    },{
       "id":2,
       "Name": "John Wick",
       "Books": [ 2 ]
    }
]

Book collection:藏书:

[
    {
       "id": 1,
       "title": "Brave New World",
       "authors": [ 1 ]
    },{
       "id":2,
       "title": "Dune",
       "authors": [ 1, 2 ]
    }
]

Example: One-Way Referencing (N:M)示例:单向参考 (N:M)

Example Books and Categories: The case is that several books belong to a few categories but a couple categories can have many books.示例书籍和类别:案例是几本书属于几个类别,但几个类别可以有很多书。

  • Advantage: Optimize the read performance优点:优化读取性能
  • The reason for choosing to embed all the references to categories in the books is due to the fact that being lot more books in a category than categories in a book.选择在书中嵌入对类别的所有引用的原因是因为类别中的书籍比书籍中的类别多得多。

Catergory类别

[
  {
    "id": 1,
    "category_name": "Brave New World"
  },
  {
    "id": 2,
    "category_name": "Dune"
  }
]

An example of a Book document with foreign keys for Categories具有Categories外键的Book文档示例

[
    {
      "id": 1,
      "title": "Brave New World",
      "categories": [ 1, 2 ],
      "authors": [ 1 ] 
    },
    {
      "id": 2,
      "title": "Dune",
      "categories": [ 1],
      "authors": [ 1, 2 ] 
    }
]

References参考

  1. Case study: An algorithm for mapping the relational databases to mongodb 案例研究:一种将关系数据库映射到 mongodb 的算法
  2. The Little MongoDB Schema Design Book小MongoDB Schema设计书
  3. 6 Rules of Thumb for MongoDB Schema Design MongoDB 架构设计的 6 条经验法则

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM