• [技术干货] MongoDB的一些约束和阈值(2):关于Shard模式的约束
    本帖最后由 lipo 于 2018-5-15 20:25 编辑Sharding模式下操作限制 [*]分片模式下不能使用的操作类型 [*]group操作符在sharding模式下无效,需要使用mapReduce或者aggregate替代。 [*]db.eval()操作在mongo3.0后版本无法使用。(被废弃) [*]geoSearch命令在分片后的模式中无法使用。 [*]$where操作符不能引用db中对象。 [*]查询的限制 [*]在mongos上使用非片键作为索引查询分片后的集合时,会覆盖不到所有数据,即查到数据可能会不全。 [*]将要分片的集合的大小限制 [*]不是所有的未分片集合都能应用分片,未分片集合的大小必须不得超过某个最大值。这个最大值可以通过配置的chunksize以及片键平均大小来估算(16777216 bytes为Bson文件最大的大小),分片成功后的集合解除此限制: [code]maxSplits = 16777216 (bytes) / [/code][code]maxCollectionSize (MB) = maxSplits * (chunkSize / 2)[/code] [*]对单个Document的操作限制 [*]对已分片的单个Document做update或者remove操作时,必须带片键,否则会报错 [*]唯一索引的限制 [*]MongoDB不支持跨shard的唯一索引,除非此唯一索引前缀由所有的片键组成 Chunk的限制 [*]MongoDB对于chunk内超过250000条Document的chunk,或者Chunk size超过所配置Chunk size1.3倍的Chunk,均无法迁移。 [*]所配置的chunkSize可以通过db.collections.stats()内的avgObjSize查询。 片键的限制 [*]片键大小不能超过512byte。 [*]片键类型不能为multikey,文本类型key,或者geo类型的key。 [*]片键是不可变的。 [*]单调的增加片键,会影响**的吞吐量,若要避免此情况,需要使用hash的片键 [*]
  • [技术干货] MongoDB oplog
    本帖最后由 Mongo_奇 于 2018-5-14 20:52 编辑oplog的作用: oplog是副本集之间数据同步的纽带。本质上是一个特殊的固定集合用来记录数据库中所有更改数据的操作。备节点通过复制主节点的oplog并应用其中的操作来和主节点保持一致。oplog在local.oplog.rs中保存。 oplog的大小: Mongodb默认将其大小设置为可用disk空间的5%(默认最小为1G,最大为50G),可以在配置文件中设置:oplogSizeMB,只有第一次生效。 oplog状态查询: replica:PRIMARY> db.getReplicationInfo() { "logSizeMB" : 10240, "usedMB" : 0.01, "timeDiff" : 1873, "timeDiffHours" : 0.52, "tFirst" : "Mon May 14 2018 09:27:51 GMT+0000 (UTC)", "tLast" : "Mon May 14 2018 09:59:04 GMT+0000 (UTC)", "now" : "Mon May 14 2018 11:28:09 GMT+0000 (UTC)" } 如何合理的设置oplog大小,以上一步的查询结果为例: 1. 计算oplog的增长速度:从输出可以看出oplog的保存了0.52小时共计520MB的数据,也就是说,业务量不变的情况下1小时大约会产生1000MB数据。[indent] [/indent][indent]2. 确定oplog时间窗: oplog时间窗可以理解需要保留oplog最大的timeDiffHours。考虑这种场景,数据库每12小时触发一次备份,恢复备份时间需要2小时。此时要给备节点进行恢复操作,则oplog需要保存十二小时的数据才能保证备节点可以和主节点完成同步。[/indent][indent]3. 计算oplog的大小: 假设oplog的增长速率为1000MB/h,需要至少保存12小时的oplog,则oplog的大小应该设为:12h*1000MB/h=12000MB[/indent] oplogSize的修改: 3.6版本之前修改比较复杂,可以参考官方文档: https://docs.mongodb.com/v3.2/tutorial/change-oplog-size/ 3.6版本之后(包括3.6版本)可以直接通过命令来修改: db.adminCommand({replSetResizeOplog: 1, size: 16000})
  • [技术干货] MongoDB快照备份——LVM基础
    LVM对lv提供了快照“snapshot”备份功能,这种功能也只对LVM 有效。 当一个 snapshot创建的时候,仅拷贝原始卷里的源数据,这不是物理上的数据拷贝,因此snapshot的创建特别快,当原始卷里的数据有写入时,备份卷开 始记录原始卷哪些数据发生了变化,然后在原始卷新数据覆盖旧数据时,将旧数据拷贝到snapshot的预留空间里,起到备份数据的作用,就保证了所有数据 和创建备份卷之前的数据一致性。 而对于snapshot的读操作,如果是读取数据块是没有修改过的,那么会将读操作直接重定向到原始卷上,如果是要读取已经修改过的块,那么就读取拷贝到snapshot中的块。所以当原始卷破坏了之后还能用snapshot备份的数据还原。 快照创建成功后,源和快照共享同一份物理数据拷贝,直到数据发生写操作,此时源上老数据或者新增数据将被写向新的存储空间。为了记录和追踪块的变化和复制信息,需要一个位图(bitmap),它用于确定实际拷贝数据的位置,以及确定从源还是目标来获取数据。并发(concurrent) 它与改变块非常相似,但它总是物理地拷贝数据。当即时拷贝执行时,没有数据被复制。取而代之,它创建一个位图来记录数据的复制情况,并在后台进行真正的数据物理复制。 写时复制快 照在快照时间点之后,没有物理数据复制发生,仅仅复制了原始数据物理位置的元数据。因此,快照创建非常快,可以瞬间完成。然后,快照副本跟踪原始卷的数据变化(即原始卷写操作),一旦原始卷数据块发生写操作,则先将原始卷数据块读出并写入快照卷,然后用新数据块覆盖原始卷。这样我们访问快照卷上的数据仍旧 是写操作前的,可以保证我们备份数据的一致性。 采取COW实现方式时,snapshot的大小并不需要和原始卷一样大。那设置成多大呢?第一、根据原始卷数据的改变大小范围来设置;第二、根据 原始卷数据的更新频率来定。一旦 snapshot的空间记录满了原始卷块变换的信息,那么这个snapshot就无法使用了。当然,如果你的snapshot大小和原始卷一样大,甚至还 要大,那snapshot备份就绝对的不会崩溃啦。 主要操作: [root@desktop21 /]# vgs VG #PV #LV #SN Attr VSize VFree vol0 2 4 1 wz--n-55.22g 26.22g [root@desktop21 /]# lvcreate -L 3G -n syslv vol0 Logical volume "syslv" created [root@desktop21 /]# lvdisplay /dev/vol0/syslv --- Logical volume --- LVName /dev/vol0/syslv VGName vol0 LVUUID xQXHqK-N3Oj-y9Z1-TBU6-hAsI-ek3V-PkmVmL LV WriteAccess read/write LVStatus available #open 0 LV Size 3.00 GiB (lv大小3G) CurrentLE 96 Segments 1 Allocation inherit Read ahead sectors auto - currently set to 256 Blockdevice 253:6 [root@desktop21 /]# lvcreate -s -n snapsyslv -L 50M/dev/vol0/syslv Rounding up size to full physical extent 64.00 MiB Logical volume "snapsyslv" created [root@desktop21 /]# lvdisplay /dev/vol0/snapsyslv --- Logical volume --- LVName /dev/vol0/snapsyslv VGName vol0 LVUUID snoXql-gI1Q-TSsF-F3LN-SyRI-HInY-8cZM3r LV WriteAccess read/write LV snapshot status activedestination for /dev/vol0/syslv LVStatus available #open 0 LVSize 3.00 GiB Current LE 96 COW-tablesize 64.00 MiB (我的PE为32M,创建的只能是32的倍数) COW-tableLE 2 Allocated to snapshot 0.03% (使用率为0.03%) Snapshot chunk size 4.00 KiB Segments 1 Allocation inherit Read ahead sectors auto - currently set to 256 Blockdevice 253:7 [root@desktop21 /]# lvs /dev/vol0/snapsyslv LV VG Attr LSize Origin Snap% Move LogCopy% Convert snapsyslv vol0 swi-a- 64.00m syslv 0.07 三、改变原始卷的数据,查看备份卷的变化 1、登录到syslv所在的系统,新建文件测试 [root@desktop64 ~]# dd if=/dev/zero of=testfile bs=1M count=20 20+0 records in 20+0 records out 20971520 bytes (21 MB) copied, 0.0329396 s, 637 MB/s [root@desktop21 /]# lvs /dev/vol0/snapsyslv LV VG Attr LSize Origin Snap% Move LogCopy% Convert snapsyslv vol0 swi-a- 64.00m syslv 33.83 [root@desktop64 ~]# dd if=/dev/zero of=testfile bs=1M count=50 50+0 records in 50+0 records out 52428800 bytes (52 MB) copied, 0.132893 s, 395 MB/s [root@desktop21 /]# lvs /dev/vol0/snapsyslv LV VG Attr LSize Origin Snap% Move LogCopy% Convert snapsyslv vol0 Swi-I- 64.00m syslv 100.00 [root@desktop21 /]# lvdisplay /dev/vol0/snapsyslv --- Logical volume --- LVName /dev/vol0/snapsyslv VGName vol0 LVUUID snoXql-gI1Q-TSsF-F3LN-SyRI-HInY-8cZM3r LV WriteAccess read/write LV snapshot status INACTIVEdestination for /dev/vol0/syslv (挂了) LVStatus available #open 0 LVSize 3.00 GiB CurrentLE 96 COW-tablesize 64.00 MiB COW-tableLE 2 Snapshot chunk size 4.00 KiB Segments 1 Allocation inherit Read ahead sectors auto - currently set to 256 Blockdevice 253:7 [root@desktop21 /]# lvchange -ay /dev/vol0/snapsyslv Can't change snapshot logical volume "snapsyslv" [root@desktop21 /]# lvremove /dev/vol0/snapsyslv Do you really want to remove active logical volume snapsyslv?[y/n]: y Logical volume "snapsyslv" successfullyremoved
  • [技术干货] MongoDB身份认证
    本帖最后由 昵称 于 2018-5-14 00:02 编辑[postbg]bg3.png[/postbg] 身份认证是验证客户端身份的过程。当启用访问控制 (即授权) 时, MongoDB 要求所有客户端对自己进行身份认证, 以确定它们的访问权限。尽管身份认证和授权紧密相连, 但身份认证与授权不同。身份认证验证用户的身份;授权决定验证用户对资源和操作的访问权限。 身份认证方法 要作为用户进行身份认证, 必须提供与该用户关联的用户名、密码和身份认证数据库(一般为admin数据库) 。 使用mongo shell 进行身份认证, 执行以下操作之一: • 使用mongo命令行身份认证选项 (--username, --password, and--authenticationDatabase) 连接到 mongod 或 mongos 实例 [code]mongo –host {ip}:{port} –username {user} –password {pwd} –authenticationDatabase {auth_db}[/code] • 首先连接到 mongod 或 mongos 实例,然后在认证数据库下运行认证 命令 [code]mongo –host {ip}:{port} use {auth_db} db.auth(“{user}”, “{pwd}”)[/code] 重要 在一次连接请求中,将多次身份认证为不同的用户时,不会去除以前经过身份认证的用户的凭据。这可能导致连接的权限超出了用户的预期, 并导致逻辑会话中的操作引发错误。 身份认证机制 MongoDB 支持多种身份认证机制, 客户端可以使用这些机制验证其身份。这些机制允许 MongoDB 集成到您现有的身份认证系统中。 MongoDB 支持多种身份认证机制: • SCRAM(默认) • MongoDBChallenge and Response (MONGODB-CR) (已弃用 MongoDB 3.6) • x.509 证书身份认证。 除了支持上述机制外, MongoDB 企业还支持以下机制: • LDAP代理身份认证 • Kerberos身份认证。 内部身份认证 除了客户端认证外, MongoDB 还可以要求副本集或分片集群的成员在各自的副本集或分片集群上验证其成员身份。 可以对副本集和分片集群的成员进行身份认证。对于成员的内部身份认证, MongoDB 可以使用 keyfiles 或 x. 509 证书。Keyfiles Keyfiles 使用 SCRAM challenge andresponse身份认证机制. keyfiles 的内容用作为成员的共享密钥。密钥的长度必须介于6到1024个字符之间, 并且只能包含 base64 集中的字符。MongoDB 去除带空格字符 (例如 x0d, x09, and x20), 为了跨平台的方便。因此,下列操作产生相同的键:[code]echo -e "my secret key" > key1 echo -e "my secret key\n" > key2 echo -e "my secret key" > key3 echo -e "my\r\nsecret\r\nkey\r\n" > key4 [/code] 在 UNIX 系统上, 密钥文件不能具有group或world权限。在Windows 系统上, 不检查密钥文件权限。 密钥文件的内容在所有连接到彼此的 mongod 和 mongos 实例上必须相同. 必须将密钥文件存储在副本集或分片集群的每个成员上。要指定密钥文件, 在配置文件中使用 security.keyFile设置或使用命令行参数选项 --keyFile x. 509 副本集或分片集群的成员可以使用 x. 509 证书进行内部身份认证, 而不是使用 keyfiles。MongoDB支持用于安全 TLS/SSL 连接的 x. 509 证书身份认证。 成员证书要求: 用于验证分片集群或副本集的成员身份的成员证书必须具有以下属性: [*]单个CertificateAuthority (CA) 必须为分片集群或副本集的成员颁发所有的 x. 509 证书。 [*]在成员证书的中找到的Distinguished Name (DN)必须为以下属性的至少一个指定非空值: Organization(O), the Organizational Unit (OU) 或theDomain Component (DC) [*]Organization属性(O)、Organizational Unit属性 (OU) 和DomainComponent (DC)必须与其他集群成员的证书匹配。要匹配, 证书必须与这些属性的所有规范属性 (甚至这些属性的非规范属性) 匹配。属性的顺序无关紧要。 在下面的示例中, 两者包含匹配的规范属性以及非规范属性。[code]CN=host1,OU=Dept1,O=MongoDB,ST=NY,C=US C=US, ST=CA, O=MongoDB, OU=Dept1, CN=host2[/code] 但是, 下面两个项包含属性的不匹配, 因为其中包含两个规范属性, 另一个则只有一个规范属性。[code]CN=host1,OU=Dept1,OU=Sales,O=MongoDB CN=host2,OU=Dept1,O=MongoDB[/code] CommonName (CN)或Subject Alternative Name (SAN) 必须与集群的其他成员使用的服务器的主机名相匹配。例如, 集群的证书可以具有以下subject:[code]subject= CN=,OU=Dept1,O=MongoDB,ST=NY,C=US subject= CN=,OU=Dept1,O=MongoDB,ST=NY,C=US subject= CN=,OU=Dept1,O=MongoDB,ST=NY,C=US [/code] 如果证书包含Extended Key Usage (EKU)设置, 则该值必须包括clientAuth (“TLS Web ClientAuthentication”)。 可以不使用 Extended Key Usage (EKU) 证书的配置[code]extendedKeyUsage = clientAuth[/code] MongoDB 配置 若要为内部身份认证指定 x. 509, 除了 TLS/SSL 配置外, 对于副本集或分片集群的每个成员, 包括配置:如果使用配置文件,须配置 security.clusterAuthMode 和 net.ssl.clusterFile如果使用命令行选项 --clusterAuthMode --sslClusterFile 成员证书和PEMKeyFile要为客户端证书身份认证配置 MongoDB, mongod 和 mongos 需要指定PEMKeyFile 以向客户端证明其身份, 方法是通过配置文件中的 net.ssl.PEMKeyFile参数或命令行选项--sslPEMKeyFile如果未为内部成员身份认证指定 clusterFile 证书, MongoDB 将尝试使用PEMKeyFile证书进行成员身份认证。为了使用PEMKeyFile证书进行内部身份认证以及客户端身份认证,必须:忽略extendedKeyUsage配置指定extendedKeyUsage配置。包括clientAuth 和 serverAuth[s][/s] 分片集群的身份认证 在分片集群中, 客户端通常直接连接mongos 实例进行身份认证。但是, 某些维护操作可能需要直接对特定的shard进行身份认证。
  • [技术干货] Mongodb批量操作
    本帖最后由 自在极意 于 2018-5-13 17:43 编辑概述 MongoDB给用户提供了单个集合的批量操作,包括批量**,更新和删除操作。 顺序操作与无序操作 使用有序的操作,Mongodb串行执行操作。如果在写入操作的一个过程中发生错误,Mongodb将返回而不处理列表中的剩余写入操作。 使用无序的操作,Mangodb可以并行执行操作。如果在写入操作的一个过程中发生错误,Mongodb将继续处理列表中的剩余写入操作。 串行操作通常比并行操作慢,因为使用有序列表,每个操作必须等待先前的操作完成。 默认情况下,bulkwrite()执行有序操作。若要指定无序写入操作,请在选项文档中设置ordered: false。 bulkwrite方法介绍 bulkwrite支持如下写操作: [code]db.collection.insertOne()db.collection.updateOne()db.collection.updateMany()db.collection.replaceOne()db.collection.deleteOne()db.collection.deleteMany()[/code] 每个写操作把文档封装成数组传递给bulkwrite 例如,下面执行多个写入操作: characters 集合包含以下文档: [code]{ "_id" : 1, "char" : "Brisbane", "class" : "**", "lvl" : 4 }, { "_id" : 2, "char" : "Eldon", "class" : "alchemist", "lvl" : 3 }, { "_id" : 3, "char" : "Meldane", "class" : "ranger", "lvl" : 3 }[/code] 如下bulkwrite对集合执行多个操作 [code]try {db.characters.bulkWrite([{ insertOne :{"document" :{"_id" : 4, "char" : "Dithras", "class" : "barbarian", "lvl" : 4}}},{ insertOne :{"document" :{"_id" : 5, "char" : "Taeln", "class" : "fighter", "lvl" : 3}}},{ updateOne :{"filter" : { "char" : "Eldon" },"update" : { $set : { "status" : "Critical Injury" } }}},{ deleteOne :{ "filter" : { "char" : "Brisbane"} }},{ replaceOne :{"filter" : { "char" : "Meldane" },"replacement" : { "char" : "Tanys", "class" : "oracle", "lvl" : 4 }}}]);}catch (e) {print(e);}[/code] 返回结果如下[code]{"acknowledged" : true,"deletedCount" : 1,"insertedCount" : 2,"matchedCount" : 2,"upsertedCount" : 0,"insertedIds" : {"0" : 4,"1" : 5},"upsertedIds" : {}}[/code] 批量装入策略 大批量的**操作,包括初始数据**或常规数据导入,可能会影响shard集群性能。对于批量**,考虑以下优化策略: 分片预拆分 如果shard集合是空的,那么集合只有一个初始chunk,它位于单个shard上。Mongodb必须耗费大量时间来接收数据、创建拆分,并将分割的chunk分发到可用shard钟。为了避免这种性能成本,可以预先配置集合分割策略,分割操作见 https://docs.mongodb.com/manual/tutorial/split-chunks-in-sharded-cluster/。 Mongos无序写入 为了提高对shard集群的写入性能,可以将bulkwrite参数有序集设为false。mongos将会同时对多个shard进行写操作。对于空集合,依然需要配置集合的分割策略,相关操作如上连接所示。
  • [技术干货] Mongodb原生导入导出工具对比
    总览:当你想把某个mongodb实例中的数据导出,然后再导入到另一mongodb的实例的时候,有两种工具可以选择。导出:mongodump和mongoexport,导入mongorestore和mongoimport。那当我们想导入导出数据时到底应该选择哪种工具呢?下面我们详细分析两种工具的不同点。 mongoexport,mongoimport导出导入的数据格式更丰富 mongoexport可以把实例中的数据导出成JSON, CSV格式的数据。JSON,CSV格式的数据方便人眼阅读,并且很多程序都能处理这些格式的数据。如果要使用一些程序对实例中的数据进行分析,那么JSON,CSV格式的数据便有很大的优势,各种分析处理程序都支持这两种通用的文件格式。而mongodump只能把数据保存为BSON的格式,BSON大家可以把它想象成JSON的二进制模式,既然是二进制模式那肯定人眼是无法直接阅读的,为了能够人眼阅读,需要使用bsondump(mongodb的开源工具)将BSON格式的数据转换成JSON格式的数据,用法很简单 bsondump test.bson > test.json,即可转换成人眼能够阅读的JSON格式数据。 mongoexport导出的数据会丢掉一些数据类型前面说了mongoexport 导出的数据是JSON,CSV格式的数据,而mongodb实例本身里面的数据类型其实是BSON的数据类型。而JSON是无法真正表达所有BSON的数据类型,只能表达BSON数据类型的一个子集,精确的说JSON对某些BSON数据类型使用的是严格模式(strict mode).例如BSON里面对于时间有Date这种数据类型,而转成JSON格式的时候就是一个字符串类型来代表Date,显然这种表示方式会丢掉一些数据类型。所以对于线上正式环境,如果数据类型很多,尽量避免使用mongoexport,mongoimport导出导入数据。以免丢掉源库中的某些数据类型。 mongoexport,mongoimport需要的权限更少 mongoexport导出数据,只需要目标库的read role权限,mongoimport 导入数据只需要目标库readWrite role权限。Mongodump导出数据需要目标库read权限,admin以及local数据库read权限。Mongorestore导入数据需要readWrite权限。显示mongodump需要的权限更多。 mongodump,mongorestore能够使用oplog 如果导出过程比较长,而这段时间变更的数据怎么办呢,大家脑海里冒出来的就是使用oplog来同步这段时间的数据。如果要使用oplog那就只有mongodump和mongorestroe了,这对工具在加了—oplog参数后会将导出这段时间的任何数据变更记录到oplog.bson里面,就可以做到任意时间的数据同步了。而mongoexport和mongoimport就没有这个功能了。 mongoexport,mongoimport不会导出shard模式下的元数据信息Shard模式下。Mongodb实例分为mongos,config,shard。其中config记录的是管理整个集群数据的元数据信息,例如哪些数据存在哪些shard,各个shard的名字以及其中成员信息。对应这些信息mongoexport是不会导出来的,它只是导出数据,然后使用mongoimport将这些数据一条一条**到目标库,而不管目标库的shard个数,因为这些都是目标库自己内部处理的。而mongodump,mongorestroe则可以并行分别导出shard,config数据,这样导出导入数据速度更快,当然也有一个问题如果目标库和源库的shard成员信息不一样,mongorestore导入数据后,还需要将config里面的数据改为目标库对应的信息。否则集群是无法使用的。 总结: 上面就是两对导入导出工具在大方面的不同了,至于细节,大家可以在mongodb官网上阅读他们的使用指南,看他们各自支持的参数。当你面对你的应用环境时到底选择哪种工具,可以参考下这些大方面的不同点,然后选择合适的工具完成你的需要。
  • [技术干货] mongodb4. 即将支持事务
    事务很重要。任何数据库都需要提供事务保证来保证数据的完整性。但他们并不都以同样的方式进行 - 不同的数据库技术采用不同的方法: [*]关系数据库在多行和父子表中建模实体的数据,因此事务需要跨越这些行和表。 [*]通过子文档和数组,文档数据库允许相关数据在单个数据结构内分层统一。该文档可以使用原子操作进行更新,使其具有与关系数据库中的多表事务相同的数据完整性保证。 由于数据建模的这一根本区别,MongoDB的现有原子性保证能够满足大多数应用程序的数据完整性需求。事实上,我们估计80%-90%的申请根本不需要多文件交易。但是,有一些合法用例和工作负载需要跨多个文档进行交易。在这些情况下,如果没有事务处理,开发人员必须在应用程序层自己实现复杂的逻辑。此外,一些开发人员和数据库管理员已经受到40年的关系数据建模的制约,以假定多表/文档事务是任何数据库的要求,而不管其构建的数据模型如何。其他人则担心,尽管今天他们的应用不需要多文档交易,因此,添加多文档ACID事务使得开发人员能够比以往更轻松地处理MongoDB上的所有用例。可以想象,在分布式数据库中构建多文档事务比在单一的大规模数据库中构建要复杂得多。事实上,我们一直致力于将多文档交易引入MongoDB,作为大规模多年工程投资的一部分。我们对系统的几乎所有部分进行了增强 - 存储层本身,我们的复制共识协议,分片体系结构,一致性和持久性保证,引入全局逻辑时钟以及重构的集群元数据管理等等。我们已经通过我们的驱动程序完全消费的API公开了所有这些增强功能。下图显示了这些增强功能的发展以及正在进行的支持多文档交易的工作。正如你所看到的,我们快完成了。 在2018年夏季即将到来的MongoDB 4.0中,多文档事务将跨越一个副本集合。我们将在以下版本中扩展对分片部署中事务的支持。重要的是,绿色框突出显示了过去3年中已交付的所有交易的关键依存关系。坦率地说,这是该项目中最难的部分 - 如何平衡建设我们需要进行交易的垫脚石,并随时向用户提供有用的功能,以便在此过程中提高他们的开发体验。无论我们在哪里,我们都会构建适合这两个目标的组件。例如,在存储层中引入全局逻辑时钟和时间戳会在分布式集群中的每个操作中实施一致的时间。为了提供快照隔离,这些增强功能是交易所需要的,但它们也允许我们实施改变 MongoDB 3.6中的流可恢复性和因果一致性,这对他们自己来说是非常有价值的。更改流允许开发人员构建响应式应用程序,以便实时查看,过滤数据更改并对数据更改进行操作,并从瞬时故障中恢复。因果一致性允许开发人员利用我们的智能分布式数据平台的可扩展性和可用性,利用“读取自己的写入”保证来维护强大的数据一致性带来的好处。全局逻辑时钟仅仅是一个例子。沿途的其他一些关键改进措施说明了mongodb的工程团队如何故意为交易奠定基础,以便我们始终为我们的用户带来额外的好处: [*]对WiredTiger Inc.的收购以及将其存储引擎方式整合到MongoDB 3.0中带来了巨大的可扩展性,其中包括对MongoDB的文档级并发控制和压缩。借助MVCC支持,它还为来自MongoDB 4.0的事务提供了存储层基础。 [*]在MongoDB 3.2中,增强共识协议允许从主副本集成员的故障或网络分区进行更快速和更确定的恢复,同时为写入提供更严格的持久保证。这些增强功能对MongoDB用户立即有用,而且它们也是交易的基本功能。 [*]在3.2中引入readConcern允许应用程序在每个操作的基础上指定读取隔离级别,从而提供强大的粒度一致性控制。 [*]MongoDB 3.6中的逻辑会话为我们的用户提供了因果一致性和可重试写入,但是作为事务的基础,它们为MongoDB提供了跨分布式集群的节点协调客户端和服务器操作的能力,管理事务中每个语句的执行上下文。 [*]同样,在MongoDB 3.6中实现的可重写写操作简化了面对选举(或其他暂时失败)时应用程序的开发,而服务器在处理语义时最多执行一次。 [*]4.0中的副本设置时间点读取对于事务一致性是必不可少的,但对于不需要在事务中执行的常规读取操作也是非常有价值的。使用此功能,读取将仅显示在find()操作启动时数据的一致视图,无论哪个副本服务于读取,或哪些数据已被并发操作修改。 交易路线图上的剩余件数很少。一旦完成,多文档分布式事务将通过快照隔离提供全局一致的数据视图(包括副本集和分片部署),并在发生节点故障时保持全有或全无保证。这将大大简化您的应用程序代码。毕竟,MongoDB的工作是解决难题并为尽可能多的开发人员解决问题,以便您可以专注于为应用程序增加价值,而不是处理潜在的管道问题。我们对多文档交易的发布感到非常兴奋,他们将允许您使用MongoDB进行构建。您应该查看我们的多文档交易页面以了解更多信息,并且我们邀请您注册测试计划,以便您可以开始完成我们通过其步伐完成的所有工作。
  • [技术干货] MongoDB的性能注意点收集(索引部分)
    建立索引的原则: 一,在满足索引需求的情况下,索引越少越好。 索引可以极大地提高查询性能,那么索引是不是越多越好?答案是否定的,并且索引并非越多越好,而是越少越好。每当你建立一个索引时,系统会为你添加一个索引表,用于索引指定的列,然而当你对已建立索引的列进行**或修改时,数据库则需要对原来的索引表进行重新排序,重新排序的过程非常消耗性能,但应对少量的索引压力并不是很大,但如果索引的数量较多的话对于性能的影响可想而知。所以在创建索引时需要谨慎建立索引,要把每个索引的功能都要发挥到极致,也就是说在可以满足索引需求的情况下,索引的数量越少越好。 比如: 如果建立了索引:db.test.ensureIndex({"age": 1,"no": 1,"name": 1 }) 那么下面两条命令均可用到这个索引,无需重复创建 db.test.find().sort("age": 1,"no": 1)db.test.find().sort("age": 1) 二,索引颗粒越少越好 什么叫颗粒越小越好?在索引列中每个数据的重复数量称为颗粒,也叫作索引的基数。如果数据的颗粒过大,索引就无法发挥该有的性能。例如,我们拥有一个"age"列索引,如果在"age"列中,20岁占了50%,如果现在要查询一个20岁,名叫"Tom"的人,我们则需要在表的50%的数据中查询,索引的作用大大降低。所以,我们在建立索引时要尽量将数据颗粒小的列放在索引左侧,以保证索引发挥最大的作用。 本文参考:http://www.cnblogs.com/mokafamily/p/4102829.html 参考链接:http://t.dbdao.com/archives/arch ... -mongodb-tools.html
  • mongodb几种备份恢复方式比较
    总览[hr]MongoDB server 提供了两种备份恢复的方法:一种是通过拷贝底层数据文件进行备份(这种方法又细化为两个不同的操作模式:1.文件快照 2.cp or rsync 等类似的文件传输复制工具)。第二种是通过mongodb 的备份恢复工具mongodump,mongorestore进行对应的备份恢复操作。两种方法有各种的优缺点和适应的应用场景,下面详细进行对比分析。1.通过文件快照(Filesystem Snapshots)进行备份和恢复[hr]概述 文件快照备份依赖mongodb宿主机器的操作系统(linux 的LVM特性),它使用操作系统级别的工具对mongodb数据文件所在的设备进行拷贝备份,由于这种方法使用的是操作系统级别的工具,因此拷贝备份效率高并且可靠性也高,同时也决定了它的一个缺点:需要宿主环境的支持。操作步骤(linux LVM) · 创建快照:lvcreate --size 100M --snapshot --name mdb-snap01 /dev/vg0/mongodb· 归档快照:umount/dev/vg0/mdb-snap01; dd if=/dev/vg0/mdb-snap01 | gzip > mdb-snap01.gz· 恢复快照:lvcreate--size 1G --name mdb-new vg0;gzip -d -c mdb-snap01.gz | ddof=/dev/vg0/mdb-new;mount /dev/vg0/mdb-new /srv/mongodb操作步骤(未开启日志功能或日志文件和数据文件不在同一个卷) · 刷新写操作到硬盘并锁住数据库:db.fsyncLock()· 创建快照· 快照完成后,解锁数据库:db.fsyncUnlock()优点 · 支持时间点的快照备份(point-in-time snapshots)· 更高的效率和可靠性· 在满足一定条件下能够获取分片集群的一致性快照备份· 提供增量备份缺点 · 需要文件系统支持时间点快照(linux:the Logical Volume Manager LVM)· 需要开启日志功能(journalingenabled)并且日志文件和数据文件位于同一个文件卷上(3.2 WiredTiger 数据文件和日志文件可以位于不同的文件卷),否则无法保证快照有效性和一致性· 为获取分片集群的一致快照,需要关闭集群均衡器并在大致相同的时刻从集群的每个分片和配置服务器上抓取快照· 没有开启日志功能时,备份前需要将写落地硬盘,备份中停止任何写操作(MMAPv1)· MMAPv1通过日志功能在快照时无需停止写达到一致状态, WiredTiger通过thelast checkpoint 达到一致状态(Checkpoints 每2G数据或每分钟)· 快照创建整个磁盘的镜像,因此将数据文件,配置,日志放在一个逻辑磁盘上节约空间版本特性 · MongoDB 3.2以上的WiredTiger引擎支持卷级备份,也就是说日志文件(journal files)和数据文件位于不同的磁盘卷上,而3.2以前版本的WiredTiger引擎如果要支持卷级备份,日志文件和数据文件必须在同一个卷上(只要开启日志就无需刷新硬盘并停写进行备份)2.通过cp 或rsync 备份和恢复[hr]概述 利用cp 或者rsync 等类似的文件复制同步工具对mongodb 的数据库文件进行拷贝备份优点 · 无需文件系统支持快照功能缺点 · 备份拷贝前必须停止所有的对mongod的写操作,否则将是一个无效的备份· 不支持副本集时间点级(point in time recovery)恢复,并且很难管理大型分片集群· 备份文件占有更多的空间(包括索引以及重复的底层文件填充和碎片)操作步骤 · 执行对应的文件传输工具命令直接拷贝数据文件3.通过mongodump/mongorestore工具进行备份和恢复[hr]概述 在运行的mongod程序上,mongodump从MongoDB数据库中读取数据生产一个高质量的BSON格式文件,mongorestore则可以将其还原为MongoDB数据库。优点 · 备份恢复小型mongoDB集群更简单和效率,备份文件占有的空间更少(只备份文档,不备份索引)· 备份过程中应用可以继续修改数据(记录oplog,通过--oplog选项达到数据状态一致)缺点 · 备份的数据库中不包含local数据库,只备份数据库的文档不备份数据库索引,因此恢复后必须重建索引· 备份恢复大型mogoDB集群不理想(效率不高)· 备份时会影响运行中的mongod的性能(产生网络流量)· 备份的数据比系统内存大时,查询操作会引起页错误· 必须拥有对应的访问控制权限(执行find操作的权限,内建的backup角色拥有备份的权限)· mongodump不同版本的格式不能兼容,不要使用新版本的mongodump备份老版本的数据操作步骤 · 备份:mongodump--host mongodb.example.net --port 27017 --collection myCollection --db test--out /data/backup/(会覆盖备份目录中的文件)· 恢复:mongorestore--port --oplogReplay4.总结 Snapshot备份时由于是对整个磁盘卷进行快照,为了减少不必要的数据的备份,需要预先将mongodb的数据,日志等放在一个单独的磁盘卷上。而mongodump备份时只备份数据文档,不备份索引,恢复后需要重建。但mongodump可以备份指定的数据库和集合,备份数据更灵活些,但备份的时候会对运行的mongodb产生性能影响。两者对分片集群备份,要产生同一时间点的一致备份,都需要在备份期间停止应用程序对mongodb的写操作,否则两者对分片集群的备份只能达到近似的同一时间点备份(approximately the same moment in time)。 两者在做恢复的时候都需要对集群进行一段时间的停机操作维护。
  • [技术干货] 部署Mongodb之安全检查项
    本帖最后由 昵称 于 2018-5-6 20:50 编辑此文档介绍了部署MongoDB服务时,需要进行的安全检查项。 启用访问控制并强制进行身份验证 启用访问控制并指定身份验证机制。您可以使用MongoDB 默认的身份验证机制或现有的外部框架。身份验证要求所有客户端和服务器都提供有效的凭据才能连接到系统。在群集部署中, 为每个 MongoDB 服务器都启用身份验证。 配置基于角色的访问控制 首先创建用户管理员, 然后创建其他用户。为访问系统的每个人和应用程序创建唯一的 MongoDB 用户。创建定义一组用户需要的确切访问权限的角色。遵循最小特权原则。然后创建用户, 并仅为他们分配执行其操作所需的角色。用户可以是个人或客户端应用程序。 加密通信 配置 MongoDB 对所有传入和传出连接使用 TLS/SSL。使用 TLS/SSL 可以加密部署的mongod 和mongos 服务器和所有应用程序之间的通信。 加密和保护数据 从 MongoDB 企业版3.2 开始, WiredTiger 存储引擎基于REST加密可以配置为对存储层中的数据进行加密。如果您没有基于REST加密使用 WiredTiger, 则应使用文件系统、设备或物理加密,在每个主机上加密 MongoDB 数据。使用文件系统权限保护 MongoDB 数据。MongoDB 数据包括数据文件、配置文件、审计日志和密钥文件。 限制网络暴露 确保 MongoDB 在受信任的网络环境中运行, 并限制 MongoDB 实例侦听传入连接的接口。仅允许受信任的客户端访问 MongoDB 实例可用的网络接口和端口。 从 MongoDB 3.6 开始, MongoDB 二进制文件, mongod 和mongos服务器,默认情况下绑定到本地主机, 从 MongoDB 2.6 开始, 只有从官方 MongoDB RPM (Red Hat, CentOS, Fedora Linux) 和 DEB (Debian, Ubuntu) 的二进制文件默认情况下绑定到本地主机。 审计系统活动 跟踪对数据库配置和数据的访问和更改。MongoDB版包括可在 MongoDB 实例上记录系统事件 (例如用户操作、连接事件) 的系统审核工具。这些审计记录允许分析, 并允许管理员验证适当的控制。 使用专用操作系统用户运行 MongoDB 使用专用操作系统用户运行 MongoDB 进程。确保该用户具有访问数据但没有不必要的权限。 使用安全配置选项运行 MongoDB [*]MongoDB 支持执行某些服务器端操作的JavaScript 代码: 如mapReduce,group, $where。如果不必使用这些操作, 请使用命令行上的 -noscripting选项禁用服务器端脚本。 [*]仅在生产部署中使用 MongoDB wire协议。 [*]保持输入验证已启用。MongoDB 通过 wireObjectCheck设置默认启用输入验证。这可确保实例存储的所有文档都是有效的BSON文档。 安全技术实施指南 (如果适用) "安全技术实施指南"(STIG) 包含美国国防部内部发布的安全指南。MongoDB 公司根据要求提供其STIG。 考虑安全标准合法性 对于需要 HIPAA 或 PCI DSS 法规遵从性的应用程序, 可参阅MongoDB 安全参考体系结构, 了解有关如何使用密钥安全功能构建兼容的应用程序基础结构。
  • [技术干货] MongoDB锁机制
    本帖最后由 Mongo_奇 于 2018-5-6 18:54 编辑MongoDB 允许多个客户端读取和写入相同的数据。面对大量的并发,MongoDB如何保持其数据一致性呢?这里将会介绍MongoDB的锁机制(基于3.2版本)。 MongoDB的锁可以分为四个粒度: Global:全局锁 Database:数据库锁 Collection:集合锁 Document: 文档锁(存储引擎实现) MongoDB的锁可以分为四个类型: R读锁(共享锁)W写锁(排它锁)r意向读锁(意向共享锁)w意向写锁(意向排它锁)这四种锁类型很好理解: 读锁是在读取时添加的锁,加了读锁的资源同时也可以被其它读操作读取。 写锁是在有写操作时加的锁,加了写锁的资源不允许被其它写操作修改。 意向读锁表示该锁持有者将以更细的粒度读取该资源。比如,数据库的意向读锁意味着,它将会读取数据库中的集合或文档。 意向写锁表示该锁持有者将以更细的粒度写入该资源。比如,数据库的意向写锁意味着,它将会在数据库中的集合或者文档进行写入操作。 举个例子,当要在集合中进行写入时: 1. 首先获取全局的意向写锁,为了在更细粒度(数据库/集合/文档) 中应用写操作。 2. 获取数据库级别的意向写锁,为了在(集合/文档)中应用写操作。 3. 获取集合的写锁,为了在集合中应用写操作。 那么对于加锁有怎样的限制呢?可以参考下图理解: 14877
  • [技术干货] MongoDB存储引擎WireTiger介绍 10
    本帖最后由 自在极意 于 2018-5-7 15:10 编辑WireTiger是Mongodb的默认存储引擎,可在mongod服务启动时指定存储引擎 mongod --storageEngine mmapv1 wireTiger允许多个客户端同时对同一个集合不同文档进行写操作,避免不了出现多线程读写数据产生冲突的情况,wireTiger使用乐观并发控制的形式(悲观并发控制即加锁,乐观并发控制不加锁,但写入的时候若有其他修改,需要手动解决冲突,如git push解决conflict,wireTiger的解决冲突方法就是给一个操作返回写失败)。 ​ wireTiger磁盘文件组织形式如下所示,存储压缩后的集合和索引。 $tree . ├── admin │ ├── collection-11--5764503550749656746.wt │ ├── collection-14--6907424972913303461.wt │ ├── collection-16--6907424972913303461.wt │ ├── collection-20--6907424972913303461.wt │ ├── collection-8--6907424972913303461.wt │ ├── collection-9--5764503550749656746.wt │ ├── index-10--5764503550749656746.wt │ ├── index-12--5764503550749656746.wt │ ├── index-13--5764503550749656746.wt │ ├── index-15--6907424972913303461.wt │ ├── index-17--6907424972913303461.wt │ └── index-9--6907424972913303461.wt ├── journal │ ├── WiredTigerLog.0000000003 │ └── WiredTigerPreplog.0000000001 ├── local │ ├── collection-0--5764503550749656746.wt │ ├── collection-2--5764503550749656746.wt │ ├── collection-4--5764503550749656746.wt │ ├── collection-6--5764503550749656746.wt │ ├── collection-7--5764503550749656746.wt │ ├── index-1--5764503550749656746.wt │ ├── index-3--5764503550749656746.wt │ ├── index-5--5764503550749656746.wt │ └── index-8--5764503550749656746.wt ├── _mdb_catalog.wt ├── mongod.lock ├── products │ ├── collection-6--6907424972913303461.wt │ └── index-7--6907424972913303461.wt ├── sizeStorer.wt ├── storage.bson ├── WiredTiger ├── WiredTiger.basecfg ├── WiredTiger.lock ├── WiredTiger.turtle └── WiredTiger.wt 当用户需要进行增删改查操作时,mongodb数据会将相关collection数据从磁盘复制到内存,这些内存数据称为老检查点,在内存中再复制出一个副本用于修改操作,称为新检查点,修改后默认60秒进行磁盘写入,写入时先判断老检查点是否和磁盘数据一致(不一致可能是读磁盘时出问题),若一致则根据新检查点进行写操作,若写到一半失败了,则把老检查点的数据重新写到磁盘(相当于回滚),如果想恢复写失败前的数据,则需要使用日志,每个数据库都有一个jounal目录存放日志信息。若写到一半宕机了,则将副本集一个secondary升级到primary节点进行数据恢复。
  • [技术干货] Mongodb数据分片及几种特殊分片策略
    本帖最后由 Nosql_newbee 于 2018-5-5 19:30 编辑mongodb数据分片: 除非明确指定规则,否则mongodb不会自动对数据进行拆分,如有必要,必须明确告知数据库和集合。 假设我们希望对music数据库中的artist集合按照name键进行分片,首先对music数据库启用分片: db.enableSharding("music") 对数据库分片是对集合分片的先决条件。 对数据启用分片后,就可以使用shardCollection()命令对集合进行分片了: sh.shardCollection("music.artists",{"name":1}) 现在,集合会按照name键进行分片。如果是对已存在的集合进行分片,那么name键上必须有索引,否则shardCollection()返回错误。如果出现了错误,就先创建索引(mongos会建议创建的索引作为错误消息的一部分返回),然后重试。 如果是新的集合,mongos会自动在片键上创建索引。shardCollection()命令会将集合拆分为多个数据块,这是MongoDB迁移数据的基本单元,命令成功执行后,MongoDB会均衡的讲集合数据分散到集群的分片上,对于比较大的集合,可能会花费几个小时才能完成。 流水策略 如果有一些服务器比其他服务器更强大,我们可能会希望让这些强大的服务器处理更多的负载。比如说,假如有一个使用SSD的分片能够处理10倍于其他机器的负载,如果有10个分片,可强制将所有新数据**到SSD,然后让均衡器将旧的块移动到其他分片上。为实现这种策略,需要将最大范围的块分布在SSD上,首先,为SSD指定一个标签: sh.addShardTag("shard-name","ssd") 将升序键的当前值也知道正无穷范围的块指定分布在SSD上,以便后续的写入请求均被分发到SSD分片上: sh.addTagRange("dbName.collName",{"_id":object()},{"_id":MaxKey},"ssd") 现在,所有的**请求都会被路由到这个块上,这个块始终位于标签为ssd的分片上。 但是,除非修改标签范围,否则从升序键的当前值一直到无穷的这个范围固定在这个分片上,可创建一个定时任务每天更新一次标签范围, use config var tag=db.tags.findOne({"ns":"dbName.collName","max":{"shardKey":MaxKey}}) tag.min.shardKey=objectId() db.tags.save(tag) 这样,前一天的块就可以被移动到其他分片上了。
  • [技术干货] mongodb均衡器简介
    均衡器(balancer)负责数据的迁移。它会周期性的检查分片间是否存在不均衡,如果存在,则会开始块的迁移。虽然均衡器通常被看做是单一实体,但每个mongos有时也会扮演均衡器的角色。 每隔几秒钟,mongos就会尝试变为均衡器,如果没有其他可用的均衡器,mongos就会对整个集群加锁,已防止配置服务器对集群进行修改,然后做一次均衡,均衡并不会影响mongos的正常操作,所以使用mongos的客户端不会受到影响。 查看config.locks集合,可以查到哪一个mongos是均衡器: use config mongos> db.locks.findOne({"_id":"balancer"}) { "_id" : "balancer", "state" : 0, "ts" : ObjectId("5aed7b24b88f3ea3e2307262"), "who" : "EulerOS-BaseTemplate:8637:1525499107:240928211:Balancer", "process" : "EulerOS-BaseTemplate:8637:1525499107:240928211", "when" : ISODate("2018-05-05T09:36:36.948Z"), "why" : "doing balance round" } config.locks 集合会追踪所有集群范围的锁,_id为balancer的文档就是均衡器。who为当前或者曾经作为均衡器的mongos是哪个,state字段表明均衡器是否正在运行:0表示处于非活动状态,2表示正在均衡(1表示mongos正在尝试得到锁,但还没有得到,通常不会看到状态1)。 mongos成为均衡器后,就会检查每个集合的分块表,看是否有分片达到了均衡阈值。不均衡的表现指,一个分片明显比其他分片拥有更多的快,如果检测到不均衡,均衡器就会开始对块进行再分布,使每个分片拥有数量相当的快,如果没有集合达到均衡阈值,mongos就不在充当均衡器的角色了。 有些集合到达了阈值,均衡器开始做迁移,它会从负载比较大的分片中选择一个块,并询问该分片是否需要在迁移之前对块进行拆分,完成必要的拆分后,就会将块迁移至数量较少的机器上。 使用集群的应用程序无需知道数据迁移,在数据迁移完成前,所有的读写请求都会路由到旧的块上,如果元数据更新完成,那么所有试图访问旧位置数据的mongos进程都会得到一个错误。这些错误应该对客户不可见,mongos会对这些错误进行静默处理,然后在新的分片上重新执行之前的操作。 有时会在mongos的日志中看到"unable to setShardVersion" 的信息,这是很常见的错误。mongos在收到这种错误时,会查看配置服务器数据的新位置,并更新块分布表,然后重新执行之前的请求。如果成功从新的位置得到了数据,则会将数据返回给客户,日志中会记录一条错误日志,用户的操作不受影响。 如果由于配置服务器不可用导致mongos无法获取块的新位置,则会向客户端返回错误。
  • MongoDB 聚合操作基本介绍
    本帖最后由 danglf 于 2018-5-5 17:43 编辑聚合操作处理数据记录并返回计算结果。汇总操作将来自多个文档的值组合在一起,并且可以对分组数据执行各种操作以返回单个结果。MongDB提供了三种执行聚合的方式:聚合 Pipeline,map-reduce功能和简单功能的聚合方法。 Aggregation Pipeline MongoDB的聚合框架是基于数据处理管道的概念建模的。文档输入一个多级流水线,将文档转换为汇总结果。 最基本的流水线阶段提供了像查询和文档转换一样操作的过滤器,这些过滤器修改了输出文档的形式。 其他流水线操作提供了按特定字段或字段分组和排序文档的工具,以及用于汇总数组内容(包括文档数组)的工具。另外,流水线阶段可以使用运算符执行任务,例如计算平均值或连接字符串。 该管道使用MongoDB中的本地操作提供有效的数据聚合,并且是MongoDB中数据聚合的首选方法。 聚合管道可以在分片集合上运行。聚合管道可以使用索引来改进其某些阶段的性能。 14872 Map-Reduce MongoDB还提供map-reduce操作来执行聚合。通常,map-reduce操作有两个阶段:处理每个文档并为每个输入文档发出一个或多个对象的映射阶段,以及减少组合地图操作输出的阶段。或者,map-reduce可以有一个finalize阶段来对结果进行最终修改。像其他聚合操作一样,map-reduce可以指定查询条件来选择输入文档以及对结果进行排序和限制。 Map-Reduce使用自定义JavaScript函数来执行映射和减少操作,以及可选的finalize操作。虽然自定义JavaScript与聚合流水线相比提供了很大的灵活性,但通常,map-reduce比聚合流水线效率更低且更复杂。 Map-reduce可以在分片集合上运行。映射减少操作也可以输出到分片集合。有关详细信息,请参阅集合流水线和分片集合以及映射简化和分片集合。 14873 单一功能聚合操作 MongoDB还提供了db.collection.count(),db.collection.group(),db.collection.distinct()。专用数据库命令。所有这些操作都汇总了单个集合中的文档。 虽然这些操作提供了对常见聚合流程的简单访问,但它们缺乏聚合流水线和map-reduce的灵活性和功能。 14874 参考链接 :MongoDB 聚合操作