繁体   English   中英

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

[英]Managing relationships with MongoDb in a Microservices architecture

我使用微服务已经有一段时间了,总是使用关系数据库。 我正在查看 MongoDb,但我不确定如何处理涉及不同微服务的实体关系。 这是一个例子:

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<>();
    ...
}

这两个实体由两个不同的微服务管理,具有由Department实体管理的一对多关系。 到目前为止,一切都很好。

使用关系数据库(作为一个可选关系,并且一名员工可能属于多个部门),我会在Departments微服务中使用 map ,其中一个表包含两个字段: employee_iddepartment_id 当客户端调用getDepartmentWithEmployees(depId)时,此微服务将读取表并从Employees微服务中获取适当的员工。

但是,据我所知,在 MongoDb 数据库中,当我存储Department object 时,它存储所有关联的Employee 这不是重复信息吗? 有没有办法,也许,MongoDb 不存储有关员工的所有信息,而只存储他们的 ID? 还是有别的答案?

我很确定这是一个非常基本的问题,但我对所有这些东西都很陌生。

提前致谢。

但是,据我所知,在 MongoDB 数据库中,当我存储部门 object 时,它会存储所有相关的员工。 这不是重复信息吗?

首先,上面的说法是不正确的。 从 MongoDB 的角度来看,作为 BSON 提供的任何内容都按原样存储。 如果您为员工提供部门,那么是的,它应该。 您可以在创建部门后应用部分更新...(例如使用$set运算符)。 但是,我认为您的问题的 scope 比这更广泛。

恕我直言,为数据库中的每个文档/表创建纳米服务不是一个好方法。 特别是当服务只负责基本的 CRUD 操作时。 您应该首先定义您的有界上下文、聚合根等... 简而言之,在将业务需求映射到域对象之前不要尝试设计表。 我想说的是使用 DDD 原则:)

这些是我目前发现的策略。 在设计微服务时,您还应该考虑每种策略的优缺点。 (参见底部的参考资料。)

关系型数据库映射到 NoSQL 的一般原则

  • 1:1 关系
    • 嵌入
    • 与外键链接
  • 1:M 关系
    • 嵌入
    • 与外键链接
    • (混合)分桶策略
  • N:M 关系
    • 双向参考
    • 单向参考

1:1 关系

可以通过两种方式映射 1:1 关系;

  • 将关系嵌入为文档
  • 链接到单独集合中的文档

表:

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

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

示例:嵌入 (1:1)

  • 优点:可以通过一次读取操作来检索地址。

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

示例:与外键链接 (1:1)

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

带文件密钥的地址;

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

1:M 关系

最初的:

// 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"
    }
]

示例:嵌入 (1:M)

警告:

  • 员工名单可能很大!
  • 在写入繁重的系统中使用这种方法时要小心。 IO 负载会由于索引、复制等内务操作而增加。
  • 员工分页很难!!!
{
  "id": 1,
  "deparment_name": "Software",
  "department_location": "Amsterdam",
  "employess": [
                   {
                     "employee_id": 46515,
                     "employee_name": "John Doe"
                   },
                   {
                     "employee_id": 81584,
                     "employee_name": "John Wick"
                   }
               ]
}

示例:链接 (1:M)

我们可以从员工文档中链接 department_id。

  • 优点:更容易分页
  • 缺点: 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
    }
]

示例:分桶策略(混合 1:M)

  • 对于时间序列等情况很有用。
  • 混合 = 嵌入 + 链接
  • 优点:一次读取 100 名员工,允许有效的分页
  • 请参阅使用模式构建:桶模式

我们将员工分成多个桶,每个桶中最多有 100 名员工。

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

N:M 关系

要选择Two Way EmbeddingOne Way Embedding ,用户必须确定 N 的最大尺寸和 M 的尺寸。
例如; 如果 N 是一本书最多 3 个类别,M 是一个类别中最多 5,000,000 本书,则您应该选择 One Way Embedding。
如果 N 最大为 3,M 最大为 5,则双向嵌入可能会很好地工作。 架构基础

示例:双向参考 (N:M)

在双向嵌入中,我们将在作者文档的 book 字段下包含 Book 外键。

作者合集

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

藏书:

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

示例:单向参考 (N:M)

示例书籍和类别:案例是几本书属于几个类别,但几个类别可以有很多书。

  • 优点:优化读取性能
  • 选择在书中嵌入对类别的所有引用的原因是因为类别中的书籍比书籍中的类别多得多。

类别

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

具有Categories外键的Book文档示例

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

参考

  1. 案例研究:一种将关系数据库映射到 mongodb 的算法
  2. 小MongoDB Schema设计书
  3. MongoDB 架构设计的 6 条经验法则

暂无
暂无

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

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