MongoDB与Amazon DynamoDB:分布式数据库的解析
1. MongoDB的数据分区与复制
MongoDB为实现水平扩展,提供了两种数据分区或分片策略:基于哈希的分片和基于范围的分片。用户需为每个文档定义一个分片键,该键基于一个或多个字段值。在创建文档时,MongoDB会依据以下两种方式选择存储文档的数据库分片:
- 对分片键应用哈希函数的结果。
- 存储分片键所在范围的分片。
1.1 MongoDB分片部署的组件
MongoDB的分片部署需要多个不同的数据库组件:
-
mongod进程
:MongoDB数据库守护进程,必须在每个分片上运行。
-
mongos进程
:负责处理数据库客户端查询,将请求路由到目标分片,并将结果返回给客户端。客户端使用MongoDB驱动程序发出API调用。
-
配置服务器
:存储数据库集群配置元数据,mongos根据分片键值使用这些元数据将查询路由到正确的分片。
mongos进程充当客户端MongoDB驱动程序和数据库分片之间的代理,所有客户端请求都必须通过mongos实例。mongos没有持久状态,仅缓存从配置服务器获取的集群配置信息。
1.2 mongos部署的配置选项
有三种基本的mongos部署配置:
| 配置类型 | 描述 | 优点 | 缺点 |
| ---- | ---- | ---- | ---- |
| 配置 (A) | 在每个充当MongoDB客户端的应用服务器上部署一个mongos。 | 减少延迟,因为每个客户端对mongos的请求都是本地调用。 | 无 |
| 配置 (B) | 在每个数据库分片上部署一个mongos。 | mongos可以与分片进行本地通信。 | 无 |
| 配置 (C) | 在专用硬件上部署一组mongos。 | mongos负载从应用服务器和数据库节点中移除,mongos进程分配到更多专用处理能力。 | 与客户端和数据库分片通信会产生额外的网络延迟。 |
1.3 MongoDB的存储单元与数据平衡
在每个分片中,MongoDB将文档存储在称为块的存储单元中,默认块的最大大小为64 MB。当块超过其最大配置大小时,MongoDB会自动将其拆分为两个或更多新块。块拆分是由插入或更新触发的元数据更改,不涉及任何数据移动。
随着集群中数据的增长,分片间的数据分布可能会变得不平衡,导致分片负载不均并产生热点,影响查询性能。为此,MongoDB在主配置服务器上运行集群平衡器进程,监控分片间的数据分布。当检测到达到可配置的迁移阈值时,会触发块迁移。迁移阈值基于集合中块数最多和最少的分片之间的块数差异。
块迁移由平衡器发起,它向源分片发送moveChunk命令,源分片负责将块复制到目标分片。迁移期间,源分片处理块的任何更新,并确保迁移完成后将这些更新同步到目标分片。最后,源分片在配置服务器上更新集群配置元数据,记录迁移块的新位置,并删除其本地副本。
1.4 MongoDB的分片复制
MongoDB通过分片复制提高可用性和读查询能力。每个主分片可以有多个从分片,它们共同构成一个副本集。所有客户端写入操作由主分片处理,主分片将所有更改记录到操作日志(oplog)数据结构中。主分片定期将其oplog发送到从分片,从分片将oplog中的修改应用到其本地数据库副本。
副本集中的节点默认每两秒发送一次心跳消息,以确认成员的可用性。如果从节点在默认10秒内未收到主节点的心跳消息,将启动领导者选举,选举算法基于Raft协议。此外,如果领导者处于少数分区中,它将主动放弃领导权。在选举新领导者期间,副本集无法进行写入操作。
1.5 MongoDB的一致性控制
MongoDB支持可调节的一致性。用户可以使用MongoDB的写入关注来控制写入操作的副本一致性。在5.0版本中,默认设置为多数,确保写入在副本集中多数节点上持久化后才确认成功。早期版本默认仅等待主节点使写入持久化,以性能换取数据安全性。
同样,读偏好允许用户配置副本集中哪些节点可以处理读操作。默认情况下,请求发送到主节点,确保一致读取。用户可以修改此设置以权衡读性能和一致性,例如指定由任何副本或最近的副本处理读操作,但这可能导致读取到旧数据。从最近的副本读取在地理分布广泛的部署中特别有用,可以减少网络延迟。
2. MongoDB的优缺点
2.1 性能
早期MongoDB版本的写入性能较差,但在过去十年中,由于WiredTiger存储层的引入,性能有了显著提升。与大多数数据库一样,每个节点的性能受益于为内部缓存分配的大量本地内存空间。如果应用程序需求允许,用户可以选择更注重原始性能而非一致性的读偏好和写入关注。
2.2 数据安全
默认的多数写入关注确保更新在副本集的多数节点上持久化。用户可以通过指定仅在主节点上使更新持久化来提高写入性能,但这可能导致主节点崩溃且更新未复制时的数据丢失。基于Raft的领导者选举算法确保只有最新的从节点可以晋升为领导者,从而防止数据丢失。
2.3 可扩展性
MongoDB可以通过分片和部署多个mongos查询路由进程来水平扩展数据集合。节点间的自动数据重新平衡有助于在集群中均匀分布请求,提高集群利用率。用户可以添加和移除节点,MongoDB集群平衡器会自动在集群中移动块以利用容量。此外,通过允许从副本集的从节点读取数据,可以扩展读负载。
2.4 一致性
MongoDB支持跨多个分片集合的ACID事务,为开发人员提供事务一致性能力。用户还可以使用适当的写入关注设置实现副本一致性。基于会话的因果一致性提供了读你所写(RYOW)的能力,并且可以通过设置读关注为线性化和写入关注为多数来确保单个文档的线性化读写。
2.5 可用性
副本集是确保数据可用性的主要机制。用户应将配置服务器配置为副本集,以确保在节点故障和分区时集群元数据仍然可用。此外,需要部署足够的mongos查询路由进程,因为如果无法访问mongos进程,客户端将无法查询数据库。
3. Amazon DynamoDB概述
Amazon的DynamoDB是AWS云中的核心服务。其起源可追溯到Werner Vogels及其团队关于Dynamo数据库的原始研究。Dynamo最初用于亚马逊网站,内部经验教训促使其发展为2012年公开可用的完全托管的DynamoDB数据库服务。
作为完全托管的数据库,DynamoDB减少了应用程序的数据库管理工作量。它自动管理复制的数据库分区,并对数据进行重新分区以满足大小和性能要求。数据项根据用户定义的分区键进行哈希处理,存储在不同分区中。每个数据项由嵌套的键值对组成,并复制三次以确保数据安全。
DynamoDB的点时间恢复功能会自动执行增量备份,并将其存储35天。用户可以随时进行全量备份,对生产系统影响极小。
在费用方面,用户根据使用的存储量和应用程序对DynamoDB的使用情况付费。存储费用按每GB数据存储计算,应用程序使用费用则较为复杂,影响性能和可扩展性。用户可以选择两种容量模式:
-
按需容量模式
:适用于流量不可预测、有快速高峰和低谷的应用程序。DynamoDB使用自适应容量功能确保数据库部署能够满足性能和可扩展性要求,用户按每个操作付费。
-
预配置容量模式
:适用于负载更可预测的应用程序。用户指定DynamoDB数据库每秒应提供的读写次数,以读写容量单位表示。如果应用程序超过此读写容量,请求可能会被限流。DynamoDB提供突发容量以避免限流,用户还可以定义数据库使用自动扩展功能,根据最小和最大预配置容量限制动态调整容量。
4. DynamoDB的数据模型和API
4.1 数据模型
DynamoDB将数据项组织在称为表的逻辑集合中。表包含多个项,每个项由主键唯一标识。每个项有一组唯一标识的属性,这些属性可以嵌套。单个项的大小限制为400 KB,DynamoDB是无模式的,同一表中的项可以有不同的属性集。
支持的标量数据类型包括字符串、二进制、数字和布尔值。用户可以使用列表和映射数据类型构建文档,这些类型可以嵌套最多32层。还可以使用集合创建包含唯一值的命名属性。以下是一个DynamoDB项的示例:
{
"skierID": "6788321471",
"Name": {
"last": "Gorton",
"first": "Ian"
},
"location": "USA-WA-Seattle",
"skiresorts": [
"Crystal Mountain",
"Mission Ridge"
],
"numdays": "2",
"season21": {
"day1": {
"date": "12/1/2021",
"vertical ": 30701,
"lifts": 27,
"resort": "Crystal Mountain"
},
"day2": {
"date": "12/8/2021",
"vertical": "17021",
"lifts": 10,
"resort": "Mission Ridge"
}
}
}
项的主键值作为分区键,通过哈希映射到不同的数据库分区。用户还可以通过定义排序键创建复合主键,将逻辑相关的项分组在同一分区中,并按排序键值排序存储。
4.2 索引
为支持替代的高效查询路径,用户可以在表上创建多个二级索引,分为本地二级索引和全局二级索引:
-
本地二级索引
:必须与基表具有相同的分区键和不同的排序键,在引用项所在的同一分区上构建和维护,读写操作消耗基表分配的容量单位。
-
全局二级索引
:可以有与基表不同的主键和排序键,索引条目可以跨越表的所有分区。全局二级索引在自己的分区中创建和维护,需要单独预配置容量。
4.3 API
DynamoDB提供两种API:
-
经典API
:提供单项目和多项目的CRUD操作,基于PutItem、GetItem、DeleteItem和UpdateItem四个核心操作的变体。例如,以下Java代码展示了GetItem API的使用:
Table table = dynamoDB.getTable("Skiers");
Item item = table.getItem("skierID", "6788321471");
如果需要同时读写多个项,可以使用BatchGetItem和BatchWriteItem操作,这些操作是单个GetItem和PutItem/DeleteItem/UpdateItem API的包装器,减少了客户端与DynamoDB之间的网络往返次数,提高了性能。
-
PartiQL API
:是一种基于SQL的方言,用户使用ExecuteStatement和BatchExecuteStatement API提交SQL语句,DynamoDB将这些语句转换为经典API中定义的单个API调用。
此外,用户可以使用ExecuteTransaction API进行ACID事务操作,将多个CRUD操作组合到多个项中,确保所有操作要么全部成功,要么全部失败。在预配置容量模式下,每个事务会对事务中访问的每个数据项产生两次读写操作,因此需要相应地规划读写容量单位。如果事务中访问的任何表没有足够的预配置容量,事务可能会失败。
5. DynamoDB的数据分布与复制
作为托管服务,DynamoDB从应用程序的角度简化了数据分布和复制。用户为项目定义一个分区键,DynamoDB对该键进行哈希处理,为每个项目存储三个副本。为了提高可用性,托管每个分区的节点位于单个AWS区域内的不同可用区,这些可用区设计为相互独立失效。
每个分区都有一个领导者和两个追随者。当用户向项目发出更新请求时,更新在领导者上持久化后,会收到HTTP 200响应代码。更新随后异步传播到副本。
默认情况下,读操作可以访问任何副本,这可能导致读取到旧数据。如果用户希望确保读取项目的最新值,可以将读API中的
ConsistentRead
参数设置为
true
,这会将读取操作定向到具有最新值的领导者节点。强一致性读取比最终一致性读取消耗更多的容量单位,并且如果领导者分区不可用,可能会失败。
DynamoDB会管理分区,并在以下情况下使用其自适应容量功能自动重新分区数据,同时保持可用性:
- 分区超过大约10GB的大小限制。
- 用户增加表的预配置吞吐量容量,现有分区无法满足更高的性能要求。
- 配置为使用按需容量的表请求量激增,超过其可维持的吞吐量。
默认情况下,DynamoDB表位于单个AWS区域。AWS区域与世界各地的数据中心相关联。对于服务于大规模全球用户群体的应用程序,如果请求必须长途传输到DynamoDB数据库所在的区域,延迟可能会很高。
例如,假设一个滑雪者管理系统在全球各地都有滑雪度假村,使用位于美国西海岸地区(如us - west - 1)的DynamoDB数据库。欧洲和澳大利亚度假村的滑雪者访问系统的延迟将比北美地区的滑雪者长得多。
为了解决这些延迟问题,用户可以使用DynamoDB全局表将表部署到多个区域。全局表在多个AWS区域维护额外的副本,并将所有项目复制到用户指定的所有区域。在一个区域进行的更新会异步传播到其他副本。不过,用户需要为每个区域的存储付费,这会增加应用程序的总体成本。
全局表是多领导者的,这意味着用户可以在任何区域更新领导者副本。如果同一项目在两个区域同时更新,可能会发生冲突。在这种情况下,DynamoDB使用最后写入者获胜的冲突解决策略来使副本收敛到单个值。
需要注意的是,全局表在强一致性读取和事务方面有一些限制:
- 强一致性读取返回读取发生区域内项目的最新值。如果同一项目键在其他区域有更近期的更新,该值不会被返回。最新版本可能需要几秒钟才能在区域间复制。
- 事务的ACID属性仅在处理事务的区域内得到保证。事务在源区域提交后,DynamoDB将结果更新复制到其他区域。更新按照标准复制协议进行,因此用户可能会看到不一致的数据。
6. 总结对比
| 特性 | MongoDB | Amazon DynamoDB |
|---|---|---|
| 数据分区策略 | 基于哈希和范围的分片 | 根据分区键哈希存储 |
| 部署组件 | mongod、mongos、配置服务器 | 自动管理分区,无需用户部署复杂组件 |
| 复制机制 | 副本集,主从复制 | 每个分区三副本,领导者 - 追随者模型 |
| 一致性控制 | 可调节,支持多数写入关注和读偏好设置 | 支持强一致性和最终一致性读取,可设置ConsistentRead参数 |
| 事务支持 | 支持跨多个分片集合的ACID事务 | 支持ACID事务,使用ExecuteTransaction API |
| 性能 | 写入性能在过去十年显著提升,依赖本地内存缓存 | 自适应容量功能,按需或预配置容量模式 |
| 数据安全 | 多数写入关注和基于Raft的领导者选举防止数据丢失 | 三副本存储和点时间恢复功能 |
| 扩展性 | 水平扩展通过分片和部署多个mongos进程,自动数据重新平衡 | 自动重新分区,支持全局表跨区域部署 |
7. 选择建议
在选择MongoDB和Amazon DynamoDB时,需要考虑以下因素:
-
应用场景
:
- 如果应用程序需要复杂的查询和事务处理,并且对数据一致性要求较高,MongoDB可能是更好的选择。例如企业级应用、内容管理系统等。
- 如果应用程序需要处理大量的读写请求,并且对延迟敏感,尤其是在全球分布式环境中,DynamoDB的全局表和自适应容量功能可能更适合,如电商平台、游戏后端等。
-
开发和管理成本
:
- MongoDB需要用户自行部署和管理数据库组件,如mongos和配置服务器,开发和管理成本相对较高。
- DynamoDB是完全托管的服务,用户无需担心数据库的部署和维护,开发和管理成本较低,但需要根据使用情况付费。
-
数据模型
:
- MongoDB的文档模型更灵活,适合存储半结构化和非结构化数据。
- DynamoDB的键值和文档模型相对简单,适合存储结构化数据。
综上所述,MongoDB和Amazon DynamoDB都是强大的分布式数据库解决方案,用户应根据应用程序的具体需求和特点进行选择。
8. 操作步骤总结
8.1 MongoDB操作步骤
-
分片部署
:
- 在每个分片上启动mongod进程。
- 部署配置服务器,存储集群配置元数据。
- 启动mongos进程,作为客户端和分片之间的代理。
-
副本集配置
:
- 定义主分片和从分片,形成副本集。
- 主分片处理写入操作,记录到oplog。
- 主分片定期将oplog发送到从分片,从分片应用修改。
-
一致性控制
:
- 使用写入关注设置控制写入一致性,如设置为多数。
- 使用读偏好配置读操作的节点选择。
8.2 DynamoDB操作步骤
-
数据模型定义
:
- 创建表,定义主键和属性。
- 可选:定义复合主键和二级索引。
-
API使用
:
- 使用经典API进行单项目和多项目的CRUD操作。
- 使用PartiQL API提交SQL语句。
- 使用ExecuteTransaction API进行ACID事务操作。
-
数据分布和复制
:
- 定义分区键,DynamoDB自动存储三副本。
- 可选:使用全局表跨区域部署。
-
设置
ConsistentRead参数确保强一致性读取。
9. 流程图
graph LR
classDef startend fill:#F5EBFF,stroke:#BE8FED,stroke-width:2px;
classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;
classDef decision fill:#FFF6CC,stroke:#FFBC52,stroke-width:2px;
A([开始]):::startend --> B{选择数据库}:::decision
B -->|MongoDB| C(分片部署):::process
B -->|DynamoDB| D(定义数据模型):::process
C --> E(副本集配置):::process
C --> F(一致性控制):::process
D --> G(选择API):::process
D --> H(数据分布和复制):::process
G --> I(执行操作):::process
H --> J(设置一致性读取):::process
E --> K([结束]):::startend
F --> K
I --> K
J --> K
这个流程图展示了在选择MongoDB或DynamoDB后,各自的主要操作步骤以及最终的结束点。它可以帮助读者更直观地理解两种数据库的使用流程。
MongoDB与DynamoDB:分布式数据库解析
超级会员免费看
1872

被折叠的 条评论
为什么被折叠?



