MongoDB 作为一款优秀的基于分布式文件存储的 NoSQL 数据库,在业界有着广泛的应用。下文对 MongoDB 的一些基础概念进行简单介绍。
一个 MongoDB 实例可以创建多个 database。连接时如果没开启免认证模式的话,需要连接到 admin 库进行认证。如果开启免认证模式,若不指定 database 进行连接,默认连接一个叫 db 的数据库,该数据库存储在 data 目录中。通过 show dbs 命令可以查看所有的数据库。数据库名不能包含空字符。数据库名不能为空并且必须小于 64 个字符。
MongoDB 预留了几个特殊的 database。
一个 MongoDB 实例的数据结构如下图:
MongoDB 集合存在于数据库中,没有固定的结构,可以往集合插入不同格式和类型的数据。集合不需要事先创建。当第一个文档插入,或者第一个索引创建时,集合就会被创建。集合名必须以下划线或者字母符号开始,并且不能包含 $,不能为空字符串(比如 ""),不能包含空字符,且不能以 system. 为前缀。
capped collection 是固定大小的集合,支持高吞吐的插入操作和查询操作。它的工作方式与循环缓冲区类似,当一个集合填满了被分配的空间,则通过覆盖最早的文档来为新的文档腾出空间。和标准的 collection 不同,capped collection 需要显式创建,指定大小,单位是字节。capped collection 可以按照文档的插入顺序保存到集合中,而且这些文档在磁盘上存放位置也是按照插入顺序来保存的,所以更新 capped collection 中的文档,不可以超过之前文档的大小,以便确保所有文档在磁盘上的位置一直保持不变。
视图基于已有的集合进行创建,是只读的,不实际存储硬盘,通过视图进行写操作会报错。视图使用其上游集合的索引。由于索引是基于集合的,所以你不能基于视图创建、删除或重建索引,也不能获取视图的索引列表。如果视图依赖的集合是分片的, 那么视图也视为分片的。视图是实时计算并读取的。
MongoDB 支持丰富的索引方式。如果没有索引,读操作就必须扫描集合中的每个文档并筛选符合查询条件的记录。索引能够在很大程度上提高查询速度。
ObjectId 可以快速生成并排序,长度为 12 个字节,包括:
在 MongoDB 中,存储在集合中的每个文档都需要一个唯一的 _id 字段作为主键。如果插入的文档省略了 _id 字段,则自动为文档生成一个 _id。
MongoDB 的复制集又称为副本集(Replica Set),是一组维护相同数据集合的 mongod 进程。复制集包含多个数据节点和一个可选的仲裁节点(arbiter)。在数据节点中,有且仅有一个成员为主节点(primary),其他节点为从节点(secondary)。
一个典型的复制集架构图如下:
MongoDB 的副本集协议(又称为 pv1),是一种 raft-like 协议,即基于 raft 协议的理论思想实现,并且对之进行了一些扩展。当往复制集添加一个节点,或当主节点无法和集群中其他节点通信的时间超过参数 electionTimeoutMillis 配置的期限时,从节点会尝试通过 pv1 协议发起选举来推荐自己成为新主节点。
在选举前具有投票权的节点之间两两互相发送心跳,以侦测节点是否存活。复制集节点每两秒向彼此发送心跳。如果心跳未在 10 秒内返回,则发送心跳的一方将被发送方标记为不可访问,也就是说,默认当 5 次心跳未收到时判断为节点失联。如果失联的是主节点,从节点会发起选举,选出新的主节点;如果失联的是从节点则不会产生新的选举。选举基于 raft 一致性算法实现,在大多数投票节点存活下选举出主节点。只有能够与多数节点建立连接且具有较新的 oplog 的节点才可能被选举为主节点,如果集群里的节点配置了优先级,那么具有较高的优先级的节点更可能被选举为主节点。
复制集中最多可以有 50 个节点,但具有投票权的节点最多 7 个。
MongoDB 支持通过分片技术来支持海量数据存储。解决数据增长的扩展方式有两种:垂直扩展和水平扩展。垂直扩展通过增加单个服务器的能力来实现,比如磁盘空间、内存容量、CPU 数量等;水平扩展则通过将数据存储到多个服务器上来实现。MongoDB 通过分片实现水平扩展。
一个典型的分片集群架构如下:
MongoDB 集合若要采用分片,必须要指定分片键(shard key)。分片键由文档中的一个或多个字段组成。分片集合必须具有支持分片键的索引,索引可以是分片键的索引,也可以是以分片键是索引前缀的复合索引。要对已填充的集合进行分片,该集合必须具有以分片键开头的索引;分片一个空集合时,如果该集合还没有包含指定分片键的索引,则 MongoDB 会默认给分片键创建索引。
对于一个即将要分片的集合,如果该集合具有其他唯一索引,则无法分片该集合。
对于已分片的集合,不能在其他字段上创建唯一索引。
4.2 版本开始可以更改文档的分片键值,除非分片键字段为不可变的 _id 字段。更新分片键时必须在事务中或以可重试写入的方式在 mongos 上运行,不能直接在分片上执行操作。在此之前文档的分片键字段值是不可变的。
4.4 版本开始,可以向现有片键中添加一个或多个后缀字段以优化集合的片键。
5.0 版本开始,实现了实时重新分片(live resharding),可以实现分片键的完全重新选择。live resharding 机制下,数据将根据新的分片规则进行迁移,不过有一些限制,比如一个实例中有且只能有一个集合在相同的时间下 resharding 等。
数据库可以混合使用分片和未分片集合。分片集合被分区并分布在集群中的各个分片中。而未分片集合仅存储在主分片中。
设置 shard key 时应该充分考虑取值基数和取值分布。分片键应被尽可能多的业务场景用到。尽可能避免使用单调递增或递减的字段作为分片键。
MongoDB 将分片数据拆分成块。每个分块都有一个基于分片键的上下限范围 。分片策略包括哈希分片、范围分片和自定义 zone 分片。
MongoDB 聚合框架(Aggregation Framework)是一个计算框架,功能是:
MongoDB 提供了三种执行聚合的方法:聚合管道,map-reduce 和单一目的聚合方法(如 count、distinct 等方法)。
在聚合管道中,整个聚合运算过程称为管道(pipeline),它是由多个步骤(stage)组成的, 每个管道的工作流程是:
聚合计算基本格式如下:
pipeline = [$stage1, $stage2, ...$stageN]; db.collection.aggregate( pipeline, { options } )
map-reduce 操作包括两个阶段:map 阶段处理每个文档并将 key 与 value 传递给 reduce 函数进行处理,reduce 阶段将 map 操作的输出组合在一起。map-reduce 可使用自定义 JavaScript 函数来执行 map 和 reduce 操作,以及可选的 finalize 操作。通常情况下效率比聚合管道低。
主要包括以下三个:
分布式系统有个 PACELC 理论。根据 CAP,在一个存在网络分区(P)的分布式系统中,要面临在可用性(A)和一致性(C)之间的权衡,除此之外(E),即使没有网络分区的存在,在实际系统中,我们也要面临在访问延迟(L)和一致性(C)之间的权衡。MongoDB 的一致性模型对读写操作 L 和 C 的选择提供了丰富的选项。
单节点的数据库由于为读写操作提供了顺序保证,因此实现了因果一致性。分布式系统同样可以提供这些保证,但必须对所有节点上的相关事件进行协调和排序。
以下是一个不遵循因果一致性的例子:
为了保持因果一致性,必须有以下保证:
实现因果一致性的单号读写应遵循以下流程:
为了建立复制集和分片集事件的全局偏序关系,MongoDB 实现了一个逻辑时钟,称为 lamport logical clock。每个写操作在应用于主节点时都会被分配一个时间值。这个值可以在副本和分片之间进行比较。从驱动到查询路由器再到数据承载节点,分片集群中的每个成员都必须在每条消息中跟踪和发送其最新时间值,从而允许分片之间的每个节点在最新时间保持一致。主节点将最新的时间值赋值给后续的写入,这为任何一系列相关操作创建了一个因果顺序。节点可以使用这个因果顺序在执行所需的读或写之前等待,以确保它在另一个操作之后发生。
从 MongoDB 3.6 开始,在客户端会话中开启因果一致性,保证 read concern 为 majority 的读操作和 write concern 为 majority 的写操作的关联序列具有因果关系。应用程序必须确保一次只有一个线程在客户端会话中执行这些操作。
对于因果相关的操作:
线性一致性又被称为强一致性。CAP 中的 C 指的就是线性一致性。顺序一致性中进程只关心各自的顺序一样就行,不需要与全局时钟一致。线性一致性是顺序一致性的进化版,要求顺序一致性的这种偏序(partial order)要达到全序(total order)。
在实现了线性一致性的系统中,任何操作在该系统生效的时刻都对应时间轴上的一个点。把这些时刻连接成一条线,则这条线会一直沿时间轴向前,不会反向。任何操作都需要互相比较决定发生的顺序。
以下是一个线性一致性的系统示例:
在以上系统中,写操作生效之前的任何时刻,读取值均为 1,生效后均为 2。也就是说,任何读操作都能读到某个数据的最近一次写的数据。系统中的所有进程看到的操作顺序,都遵循全局时钟的顺序。
read concern 是针对读操作的配置。它控制读取数据的新近度和持久性。read concern 选项控制数据读取的一致性,分为 local、available、majority、linearizable 四种,它们对一致性的承诺依次由弱到强。其中 linearizable 表示线性一致性,另外 3 种级别代表了 MongoDB 在实现最终一致性时,对访问延迟和一致性的取舍。
下面借用一张图展示 majority 和 linearizable 的区别:
write concern 是针对写操作的配置,表示写请求对独立 mongod 实例或复制集或分片集进行写操作的确认级别。它主要是控制数据写入的持久性。包含三个选项:
w:指定了写操作需要复制并应用到多少个复制集成员才能返回成功,可以为数字或 majority。
w:0 表示客户端不需要收到任何有关写操作是否执行成功的确认,就直接返回成功,具有最高性能。
w:1 表示写主成功则返回。
w: majority 需要收到多数节点(含主节点)关于操作执行成功的确认,具体个数由 MongoDB 根据复制集配置自动得出。w 值越大,对客户端来说,数据的持久性保证越强,写操作的延迟越大。w:1 要求事务只要在本地成功提交即可,而 w: majority 要求事务在复制集的多数派节点提交成功。
w:all 表示全部节点确认才返回成功。
j:表示写操作对应的修改是否要被持久化到存储引擎日志中,只能选填 true 或 false。
j:false 表示写操作到达内存即算作成功。
j:true 表示写操作落到 journal 文件中才算成功。w:0 如果指定 j:true,则优先使用 j:true 来请求独立或复制集主副本的确认。j:true 本身并不能保证不会因复制集主故障转移而回滚写操作。
wtimeout:主节点在等待足够数量的确认时的超时时间,单位为毫秒。超时返回错误,但并不代表写操作已经执行失败。跟 w 有关,比如:w 是 1,则是带主节点确认的超时时间;w 为 0,则永不返回错误;w 为 majority,表示多数节点确认的超时时间。
从 3.2 版本开始,默认使用 WiredTiger 存储引擎,每个被创建的表和索引,都对应各自独立的 WiredTiger 表。为了保证 MongoDB 中数据的持久性,使用 WiredTiger 的写操作会先写入 cache,并持久化到 WAL(write ahead log),每 60s 或日志文件达到 2 GB,就会做一次 checkpoint,定期将缓存数据刷到磁盘,将当前的数据持久化产生一个新的快照。
MongoDB 采用插件式存储引擎架构,实现了服务层和存储引擎层的解耦,可支持使用多种存储引擎。除此之外,底层的 WiredTiger 引擎还支持使用 B+ 树和 LSM 两种数据结构进行数据管理和存储,默认使用 B+ 树结构做存储。使用 B+ 树时,WiredTiger 以 page 为单位往磁盘读写数据,B+ 树的每个节点为一个 page,包含三种类型的 page,即 root page、internal page 和 leaf page。
以下是 B+ 树的结构示意图:
WiredTiger 支持在内存和磁盘上对索引进行压缩,通过前缀压缩的方式减少 RAM 的使用。
WiredTiger 使用了二级缓存 WiredTiger Cache 和 File System Cache 来保证 Disk 上 Database File 数据的最终一致性。
WiredTiger 使用 MVCC 进行写操作,多个客户端可以并发同时修改集合的不同文档。事务开始时,WiredTiger 为操作提供反映内存数据的一致视图的时间点快照。MVCC 通过非锁机制进行读写操作,是一种乐观并发控制模式。WiredTiger 仅在全局、数据库和集合级别使用意向锁。当存储引擎检测到两个操作之间存在冲突时,将引发写冲突,从而导致 MongoDB 自动重试该操作。
使用 WiredTiger,如果没有 journal 记录,MongoDB 能且仅能从最后一个检查点恢复。如果需要恢复最后一次 checkpoint 之后所做的更改,那么开启日志是必要的。
默认情况下,客户端读取复制集主节点上的数据。但客户端可以指定一个 read perference 改变读取行为,以便对复制集上的其他节点进行直接读操作。可选值包括:
读操作由客户端指定的 read prefenence 选项决定。
所有的写操作都在集合的主节点上执行。主节点执行写操作并将操作记录在操作日志或 oplog 上。oplog 是 local 数据库的一个集合,叫 local.oplog.rs。这是一个 capped collection,是固定大小,循环使用的。oplog 是对数据集的可重复操作序列,其记录的每个操作都是幂等的,也就是说,对目标数据集应用一次或多次 oplog 操作都会产生相同的结果。从节点从上一次结束时间点建立 tailable cursor,不断的从同步源拉取 oplog 并重放应用到自身,且严格按照原始的写顺序对给定的文档执行写操作。mongodb 使用多线程批量执行写操作来提高并发,根据文档 id 进行分批执行。MongoDB 为了提升同步效率,将拉取 oplog 以及重放 oplog 分到了不同的线程来执行。
大致的写流程如下:
对于分片集群,需要一个 mongos 实例提供客户端应用程序和分片集群之间的接口。在客户端看来,该 mongos 实例的行为与其他 MongoDB 实例是相同的。客户端向路由节点 mongos 发送请求,由该节点决定往哪个分片进行读写。对于读取操作,若能定向到特定分片时,效率最高。一般而言,分片集合的查询应包含集合的分片键,以避免低效的全分片查询。在这种情况下,mongos 可以使用配置数据库 config 中的集群元数据信息,将查询路由到分片。如果查询不包含分片键,则 mongos 节点必须将查询定向到集群中的所有分片,然后在 mongos 上聚合所有分片的查询结果,返回给客户端。
对于写操作, mongos 定向到负责数据集特定部分的分片,config 数据库上有集合相关的分片键信息,mongos 从中读取配置,并路由写操作到适当的分片。
MongoDB 在一定程度上支持了事务的 ACID 特性。MongoDB 4.0 版本开始支持复制集上的多文档事务,4.2 版本引入了分布式事务,它增加了对分片群集上多文档事务的支持。
事务中的操作使用事务级别的 read concern。事务内部忽略在集合和数据库级别设置的任何 read concern。事务支持设置 read concern 为 local、majority 和 snapshot 其中之一。
事务使用事务级别的 write concern 来进行写操作提交,可以通过配置 w 选项设置节点个数,来决定事务写入是否成功,默认情况下为 1。
MongoDB 3.6 引入了 change stream(变更流)。它的使用场景包括:
change stream 允许外部程序访问实时数据更改,而不会增加 MongoDB 基础操作的复杂性,也不会导致 oplog 延迟的风险。应用程序可以使用 change stream 来订阅单个集合、数据库或整个集群中的所有数据变更。若要开启 change stream,必须使用 WiredTiger 存储引擎。
change stream 可应用于复制集和分片集。应用于复制集时,可以在复制集中任意一个节点上开启监听;应用于分片集时,则只能在 mongos 上开启监听。在 mongos 上发起监听,是利用全局逻辑时钟提供了整个分片上变更的总体排序,确保监听事件可以按接收到的顺序安全地解释。mongos 会一直检查每个分片,查看每个分片是否存在最新的变更。如果多个分片上一直很少出现变更,则可能会对 change stream 的响应时间产生负面影响,因为 mongos 仍必须检查这些冷分片保持总体有序。
从 change stream 中能监听到的变更事件包括:insert、update、replace、delete、drop、rename、dropDatabase 和 invalidate。
MongoDB 4.0 之后,可以通过指定 startAtOperationTime 来控制从某个特定的时间点开启监听,但该时间点必须在所选择节点的有效 oplog 时间范围内。change stream 监听返回的字段中有个 _id 字段,表示的是 resume token,这是唯一标志 change stream 流中的位置的字段。
如果 change stream 监听比中止后需要继续监听,那么可指定 resumeAfter 恢复订阅。指定 resumeAfter 为 change stream 中断处的 _id 字段即可。
当监听的集合发生 rename、drop 或 dropDatabase 事件,就会导致 invalidate 事件;当监听的数据库出现 dropDatabase 事件,也会导致无效事件。invalidate 事件后 change stream 的游标会被关闭,这时就需要使用 resumeAfter 选项来恢复 change stream 的监听,在 4.2 版本后也可以通过 startAfter 选项创建新的更改流来恢复监听。
本文由哈喽比特于3年以前收录,如有侵权请联系我们。
文章来源:https://mp.weixin.qq.com/s/CWjPigYjnREPXTiIRXI6MA
京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。
日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。
据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。
今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。
日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。
近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。
据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。
9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...
9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。
据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。
特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。
据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。
近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。
据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。
9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。
《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。
近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。
社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”
2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。
罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。