我们经常看到主操作存储与一些附加服务结合使用,例如用于缓存或全文搜索。
另一种使用多个数据库的架构方法是微服务,其中每个微服务都有自己的数据库,针对该特定服务的任务进行了更好的优化。例如,您可以将 MySQL 用于主存储,将 Redis 和 Memcache(用于缓存)、Elastic Search 或原生 Sphinx 用于搜索。您可以应用 Kafka 之类的东西将数据传输到分析系统,这通常是在 Hadoop 之类的东西上完成的。
如果我们谈论主要操作存储,则有两种选择。我们可以选择 SQL 语言的关系型数据库。或者,我们可以选择非关系数据库,然后选择在这种情况下可用的类型之一。
如果我们谈论 NoSQL 数据模型,那么那里也有很多选择。最典型的是键值、文档或宽列数据库。
示例分别是 Memcache、MongoDB 和 Cassandra。
看DB-Engines Ranking,我们会看到这些年来开源数据库的流行度一直在增长,而商业数据库却在逐渐走下坡路。
更有趣的是,对于不同类型的数据库也观察到了相同的趋势:开源数据库在列式数据库、时间序列和文档故事等许多类型中最受欢迎。商业许可证仅适用于关系数据库数据等经典技术或多值数据库等更老的技术。
在 Percona,我们与最流行的关系型和非关系型开源数据库(MySQL、PostgreSQL 和 MongoDB)密切合作,与许多客户打交道;我们帮助他们做出选择,并为他们提供针对每个案例的最佳建议。
考虑到这一点,本文旨在展示在部署 MongoDB 之前值得考虑的场景,引导您思考何时应该和不应该使用它。此外,如果您已经进行了设置,这篇文章可能也很有趣,因为在评估产品期间,以下一些主题可能会被忽视。
目录
以下是我将在本文中进一步讨论的主题列表:
- 团队经验和偏好
- 开发方法和应用程序生命周期
- 数据模型
- 事务和一致性(ACID)
- 可扩展性
- 行政
1. 团队经验和偏好
在潜入 MongoDB 之前,最重要的是要考虑到团队的经验和偏好。
从MongoDB的角度来看,优点是我们有灵活的JSON格式文档,对于一些任务和一些开发者来说,这很方便。对于一些团队来说,这很困难,特别是如果他们长期使用 SQL 数据库并且非常了解关系代数和 SQL 语言。
在 MongoDB 中,您可以轻松熟悉CRUD操作,例如:
简单的查询不太可能导致问题。尽管如此,一旦出现需要更深入数据处理的日常任务,您当然需要一个强大的工具来处理它,例如 MongoDB聚合管道和map-reduce,我们将在本文中进一步讨论。
MongoDB 大学有很多很棒的免费课程,无疑可以帮助增加团队的知识。尽管如此,重要的是要记住,如果团队不完全熟悉,学习曲线的顶点可能需要一些时间才能达到。
2. 开发方法和应用生命周期
如果我们谈论使用 MongoDB 的应用程序,它们主要关注快速开发,因为您可以随时更改所有内容。您不必担心文档的严格格式。
第二点是数据模式。这里你需要明白数据总是有模式的;唯一的问题是它在哪里实施。您可以在应用程序中实现数据模式,因为不知何故,这就是您使用的数据。或者这个模式是在数据库级别实现的。
当你有一个应用程序时,通常只有这个应用程序处理数据库中的数据。例如,如果我们将应用程序中的数据保存到数据库中,则应用程序级模式运行良好。但是,如果我们有许多应用程序使用相同的数据,就变得非常不方便和难以控制。
应用程序开发周期的一个观点可以表示如下:
- 发展速度
- 无需同步数据库和应用程序中的模式
- 很明显如何进一步扩展
- 简单的预定解决方案
3. 数据模型
正如第一个主题中提到的,数据模型高度依赖于应用程序和团队的经验。
许多 Web 应用程序的数据通常很容易显示。因为如果我们存储结构,比如应用程序的关联数组,开发人员可以直接和清晰地将其序列化为 JSON 文档。
让我们举个例子。我们想从手机中保存一个联系人列表。有些数据非常适合一个关系表:名字、姓氏等。但是如果您查看电话号码或电子邮件地址,一个人可能有几个。如果我们想以一种良好的关系形式存储它,最好将它放在单独的表中,然后使用 JOIN 收集它,这比将它存储在具有分层文档的一个集合中要方便。
数据模型 - 联系人列表示例
关系型数据库
- 名字、姓氏、出生日期
- 一个人可以有多个电话号码和电子邮件
- 您应该为他们创建单独的表
- JSON 数组是非传统的扩展
面向文档的数据库
- 一切都存储在一个“集合”中。
- 数组和嵌入文档
但是,重要的是要考虑到更灵活的解决方案会产生可能具有完全不同结构的文档列表。前面有人说过,“能力越大,责任越大”。
不幸的是,操作无法管理大于16MB 的文档或保存 TB 级数据的单个集合是很常见的;或者,在更糟糕的情况下,分片键设计错误。
这些异常可能是一个很好的迹象,表明您正在将数据库变成数据沼泽。它是大数据部署中常用的一个术语,用于表示设计不当、记录不充分或维护不善的数据。
您不需要严格规范化您的数据,但必须花时间分析您将如何构建您的数据,以便在使用 MongoDB 后拥有最好的世界并避免这些陷阱。
您可以查看博客文章“ MongoDB 中的架构设计与 MySQL 中的架构设计”,以更好地说明数据建模及其不同之处。值得一提的是您可以在更新和插入期间使用的架构验证 功能。您可以在每个集合的基础上设置验证规则,限制正在存储的内容类型。
条款
有趣的是,在建模和查询时,关系和非关系 DBMS 之间有很多共同点。我们在这两种情况下都在谈论数据库,但是我们在关系数据库中所说的表通常在非关系数据库中称为集合。什么是 SQL 中的列,什么是 MongoDB 中的字段,不胜枚举。
在使用JOIN方面,我们一直提到,MongoDB没有这样的概念。但是,您可以在聚合管道上使用$lookup。它只对您的搜索执行左外连接;大量使用$lookup可能表明您的数据建模中存在错误。
至于访问:我们将 SQL 应用于关系数据。对于 MongoDB 和许多其他 NoSQL 数据库,我们使用诸如 CRUD 之类的标准。这个标准说有创建、读取、删除和更新文档的操作。
下面是一些在 SQL 世界中处理文档及其等价物的最典型任务的示例:
创建:
读:
- 更新:
删除:
如果您是熟悉 JavaScript 语言的开发人员,那么 CRUD(MongoDB)提供的这种语法对您来说会比 SQL 语法更自然。
在我看来,当我们有最简单的操作时,例如搜索或插入,它们都可以很好地工作。当涉及到更棘手的采样操作时,SQL 语言更具可读性。
数数:
使用该界面,可以轻松完成诸如计算表或集合中的行数之类的操作。
聚合
但是如果我们在 MongoDB 中做更复杂的事情,比如 GROUP BY,就需要聚合框架。这是一个更复杂的界面,显示了我们希望如何过滤、我们希望如何分组等。
4. 事务和一致性(ACID)
提出这个主题的原因是因为根据业务需求,数据库解决方案可能需要符合 ACID 。在这场比赛中,关系数据库遥遥领先。ACID 要求的一个很好的例子是涉及金钱的操作。
想象一下,您正在构建一个将资金从一个帐户转移到另一个帐户的函数。如果您成功从源账户中取钱,但从未将其记入目的地;或者,如果您转而记入目的地,但从未从来源中取出资金来支付它。这两次写入必须发生或都不会发生,以保持我们的系统正常,也知道“全有或全无”。
在 4.0 发布之前,MongoDB 不支持事务,但支持单个文档内的原子操作。
这意味着,从一个文档的角度来看,操作将是原子的。如果流程更改了多个文档,并且在更改过程中出现某种故障,那么这些文档有的会被更改,有的不会。
MongoDB 的这一限制已在 4.0 版本及以后的版本中解除。对于需要对多个文档(在单个或多个集合中)进行读写原子性的情况,MongoDB 支持多文档事务。它可以跨多个操作、集合、数据库、文档和具有分布式事务的分片使用。
- 在 4.0 版本中,MongoDB 支持副本集上的多文档事务。
- 在 4.2 版本中,MongoDB 引入了分布式事务,增加了对分片集群上多文档事务的支持,并合并了对副本服务器上多文档事务的现有支持
5. 可扩展性
在这种情况下,可扩展性是什么?您可以轻松地将一个小型应用程序扩展到数百万甚至数十亿用户。
如果我们谈论应用程序已经足够大的集群的可扩展性,很明显一台机器无法应对,即使它是最强大的机器。
讨论我们是否扩展读取、写入或数据量也很有意义。不同的应用程序的优先级可能不同,但一般来说,如果应用程序非常大,他们通常要处理所有这些事情。
在 MongoDB 中,最初的重点是跨多个节点的可扩展性。即使在小型应用程序的情况下。我们可以在早期发布的 Sharding 特性上注意到这一点,从那时起,它已经发展并越来越成熟。
如果您正在寻找垂直可扩展性,它可以通过副本集配置在 MongoDB 中实现。您可以通过很少的步骤扩展和缩小数据库,但这里的重点是仅扩展您的可用性和读取。您的写入仍然绑定到一个点,即主要点。
但是,我们知道应用程序在某个时候会需要更多的写入容量,或者数据集对于副本集来说会变得太大;因此,建议使用Sharding进行水平扩展,拆分数据集,并跨多个分片写入。
MongoDB sharding 有一些局限性:不是所有的操作都适用,shard-key设计不好会降低查询性能,造成数据分布不均匀,影响集群内部操作,如自动数据拆分,更糟糕的场景需要手动重新分片,这是一项广泛且容易出错的操作。
随着MongoDB 5.0的发布,最近引入了重新分片功能。与任何新功能一样,我的建议是在任何生产使用之前进行广泛的测试。如果在某些时候你正在寻找方法来优化您的碎片键,然后resharding新功能,文章中的MongoDB 4.4及以上炼油碎片键可以引导您更好的选择。
6. 行政
管理是开发人员不考虑的所有事情。至少,这不是他们的首要任务。管理是关于备份、更新、监控、在出现故障时恢复应用程序的需要。
MongoDB 更专注于标准方式——最小化管理。但很明显,这是以牺牲灵活性为代价的。MongoDB 的开源解决方案社区要小得多。您可以在本文开头突出显示的DB-Engines 排名和StackOverflow的年度调查中注意到它;毫无疑问,MongoDB 是最受欢迎的 NoSQL 数据库,但遗憾的是,它缺乏强大的社区。
此外,MongoDB 中的许多推荐内容都与Ops Manager 和 Atlas 服务(它们是 MongoDB 的商业平台)紧密相关。
直到最近,运行备份/恢复例程对于Sharded Cluster或ReplicaSet 来说都不是微不足道的操作。DBA 不得不依赖mongodump / mongorestore工具的方法或文件系统快照的使用。
借助Percona Hot-Backup和Percona Backup for MongoDB工具等功能,这种情况开始变得更好。
如果我们查看最流行的关系型数据库如 MySQL,它足够灵活并且有很多不同的方法。一切都有很好的开源实现,这是 MongoDB 中仍然存在的弱点。
结论
我已经讨论了一些可以帮助您日常工作的主题,提供了 MongoDB 将受益的广阔视野。重要的是要考虑到本文是在最新可用版本MongoDB 5.0之上编写的;如果您已经有一个部署,但它使用的是旧版本或已弃用的版本,则某些观察和功能可能无效。
如果您遇到问题或有更细粒度的问题,请查看我们的博客;我们可能已经写过一篇关于它的文章;我们还邀请您在此处查看我们的白皮书,其中详细介绍了 MongoDB 适合和不适合的更多场景和案例。
我希望这可以帮助你!
如果您有任何疑问,请随时通过下面的评论部分与我们联系。