本文来自网易云社区,转载务必请注明出处。

MongoDB是一个非常有前途的数据库,MongoDB官方对自己的定位是通用数据库,其实这个定位跟MySQL有些像。虽其流行度还远未达到MySQL的水平,但笔者有个可能不恰当的比较,MongoDB就像N年前的MySQL,随着时间的推移,会变得越来越强大,也会越来越流行。下面结合MongoDB的几大特色来谈谈MongoDB的适用场景。

首先,MongoDB是文档型(Document store)的NoSQL数据库,数据以文档(对应关系型数据库的记录,本文有时候会混用)的形式在MongoDB中保存,文档实际上就是一个个JSON字符串,想必大家对JSON都比较熟悉,不赘述。使用JSON的好处是非常直观,通过一系列的Key-Value键值对来表示数据,符合我们的阅读习惯,下图所示是以JSON表示的用户信息文档。

在主流的计算机语言如Java、Python中对JSON都有很好的支持,数据从MongoDB中读取出来后,可无需转换直接使用;MongoDB文档另一个特点是Key-Value键值对支持丰富的数据结构,Value可以是普通的整型、字符串,可以是数组,也可以是嵌套的子文档,使用嵌套的好处是在MongoDB中仅需一次简单的查询就能够获取到你所需的数据。举电商领域为例,网易严选上卖的上衣和裤子两种商品,除了有共同属性,如产地、价格、材质、颜色等外,还有各自有不同的属性集,如上衣的独有属性是肩宽、胸围、袖长等,裤子的独有属性是臀围、脚口和裤长等。

这些独有属性可以直接以JSON子文档的方式嵌套在商品这个文档中,一次查询直接获取全部内容,不需要进行多表join;MongoDB文档的另一大特点是模式灵活:不同文档相同key的value类型可以是整形也可以是字符串等其他类型,不同文档可以有不同的key,比如有些商品有折扣字段,可以定义不同会员等级的不同折扣。在电商配套的物流领域,可以将一个快递的物流信息直接嵌套在以商品id为唯一索引的文档中,一次查询就可以获取完整的快递流向信息。MongoDB查询还提供了非常丰富的操作符,在查询中组合使用效率倍增。

基于文档的灵活的数据模式,是MongoDB的一大优势,对于数据模型多样或多变的业务场景,相比MySQL等数据库,无需使用DDL语句进行表结构的修改;相比其他Key-Value数据库,由于MongoDB的Value字段对于MongoDB是非透明的,可以对其建立索引,还可以进行全文检索,在查询效率上更具优势。该模式在游戏、电商、社交、视频直播、物流等领域非常适用,通过在用户或商品中嵌套不同用途的子文档来实现快速查询。对于监控、日志数据存储,第三方信息抓取等场景也同样适用,因为不同监控数据、日志记录、抓取的数据所包含的字段往往是不一样的,某种程度上说也是不可控的。同时,灵活的模式对于类似游戏市场活动、移动App等要求快速开发上线但需求变动(导致数据模型变大)比较大的产品或场景也比较适用。

其次,MongoDB还具有强大的索引能力,支持创建唯一索引、二级索引、TTL索引和地理位置索引等,这在NoSQL数据库中是数一数二的,在此基础上,MongoDB还提供了执行计划功能,通过explain()(https://docs.mongodb.com/manual/reference/method/db.collection.explain/#db.collection.explain)和hint()命令可以查看执行计划、强制查询走某个索引,这些特性相比关系型数据库也不成多让。MongoDB集合在创建时默认就基于_id字段创建了唯一索引,数据插入时会检查_id字段的唯一性,MongoDB可以在包括数组中字段或嵌套文档中的字段几乎任意字段上创建索引(一般为二级索引),大大提高了查询效率,在没有跨记录或跨表事务但对性能要求又非常高的某些场景下能够替代关系型数据库。在内存足够的情况下,索引会被加载到Cache中,如果执行的查询是索引覆盖的(https://docs.mongodb.com/manual/core/query-optimization/#read-operations-covered-query),其性能甚至可以媲美Redis等内存数据库等。TTL索引在保存日志或监控数据等场景下大有用武之地,通过创建TTL索引,实现自动删除过期记录的功能,(在使用MongoDB TTL索引需要注意,数据的过期时间无法精确控制,无法做到过期即删除,在大数据量的情况下会有一定的性能开销和删除延迟)。

地理位置索引是MongoDB早已被用户所熟知的特性,其球面(Spherical)和平面(Flat)两种模式,提供了丰富的地址位置的表示方式,如2d、2dsphere和GeoJSON等,对于移动App,如地图软件、打车软件、外卖软件,MongoDB强大的地理位置索引功能使其最佳选择(https://www.mongodb.com/blog/post/geospatial-performance-improvements-in-mongodb-3-2);此外,对于物联网、智慧都市等领域,也需要大量的地理位置相关操作,这些都是MongoDB的竞技场。

再次,MongoDB的复制集是数据库领域领先的高可用和读写负载均衡解决方案,提供了数据自动(异步/同步)复制能力,一个新节点加入到复制集中会自动进行数据初始同步随后使用oplog进行增量复制,无需人工干预;如果复制集的Primary节点发生宕机,MongoDB会自动进行主从切换,在复制集大多数节点在线的情况下,能够基于Raft协议(MongoDB 3.2开始,之前版本不未使用Raft)自动地快速选出新的Primary并恢复读写服务(在选主期间,无法进行写操作),无需人工干预;MongoDB运维人员所需做的仅仅是将宕机节点重新启动,若宕机的是Primary,则重新启动后,会自动进行数据回滚并最终成为复制集的Secondary节点(正常情况下)。

在复制集机制下,还可以通过对节点进行滚动处理的方式进行在线维护升级。所以,相比目前的大多数关系型数据库,MongoDB复制集实现了自动复制和故障切换,大大减低了运维复杂度,解放了DBA。如果你对数据的持久化和可用性有较高的要求,MongoDB复制集是上佳的选择。此外,复制集还提供了Write Concern、Read Preference、Read Concern和Tag sets等读写行为控制功能,不同的业务应用类型可以参考官方手册(https://docs.mongodb.com/manual/applications/replication/)根据对数据持久化、数据一致性和可用性的不同要求进行灵活地设置。

最后,MongoDB是为大数据而生的,提供sharding机制用于实现业务的水平扩展。每个shard都保存业务的一部分数据,shard可以配置为复制集,确保shard上数据的高可用性,shard内部由一系列连续的chunk组成,chunk是某一片键区间内的数据记录集合;mongos用于业务请求的路由,将业务负载分摊到不同的shard上,此外mongos还会对shard上超过一定大小的chunk进行分裂(split);根据不同shard中数据量的大小,在shard将进行chunk迁移(migrate),应该说sharding提供了完善的业务数据和负载水平扩展的机制,对于物联网、日志系统和监控系统这类包含TB级海量数据的应用场景,使用MongoDB sharding是个不错的选择。

在生产环境中,sharding并不是必须的,并不是新业务起来的时候就马上部署sharding集群,只有当业务的数据量达到单个复制集无法支撑、或者业务的负载超过了复制集的服务能力的时候,才考虑部署sharding,毕竟相比复制集,sharding在部署和管理上都复杂很多。MongoDB复制集可以平滑升级到shard,所以当你真正需要sharding时,可以参考官方文档(https://docs.mongodb.com/manual/tutorial/convert-replica-set-to-replicated-shard-cluster/)进行操作,文档中提供了详细的升级步骤。

介绍了MongoDB的优势,也不得不提MongoDB的不足,MongoDB仅支持文档内的事务,所以对于需要跨文档或跨集合事务的应用,请谨慎使用MongoDB;另外,对于需要多表复杂Join的业务,还是使用关系型数据库为好,MongoDB还在改善的路上;最后,对于PB级大数据量,且需要进行大规模计算的场景,使用MongoDB时需要配套使用Spark、Hadoop等大数据套件,让MongoDB做正确的事情。总结起来,如果你的业务满足一个或多个特点,那么选择MongoDB是个正确的决定:

    • 无需要跨文档或跨表的事务及复杂的join查询支持

    • 敏捷迭代的业务,需求变动频繁,数据模型无法确定

    • 存储的数据格式灵活,不固定,或属于半结构化数据

    • 业务并发访问量大,需数千的QPS

    • TB级以上的海量数据存储,且数据量不断增加

    • 要求存储的数据持久化、不丢失

    • 需要99.999%的数据高可用性

    • 需要大量的地理位置查询、文本查询

目前开源数据库众多,大家可选的余地很大,就会出现这样的问题:MySQL、MongoDB、Redis、Hbase等这些数据库哪个更好?其实这是一个伪命题,脱离了具体的业务场景来讨论好坏是纸上谈兵,没有最好的,只有最合适的,谁也无法保证完全取代谁,上面的每种数据库都在变得更好,都在不停地完善自身。比如MySQL在不断提升其JSON和地理位置处理能力、组复制(group replication)已在开发等;而MongoDB在增强join类型支持,提供更为复杂的多集合查询能力,计划支持事务等;Redis也加入了地理位置处理能力。

最后,以新鲜出炉的12月份最新DB-Engines排行榜来结束本篇文章:

免费体验网易云MongoDB服务,为开发者提供了一站式的 MongoDB 云端解决方案,包括提供三节点复制集的高可用架构,故障切换,并提供专业的备份、监控以及性能优化方案,彻底免除开发者的运维烦恼。

本文来自网易云社区 ,经作者温正湖授权发布。

网易云免费体验馆,0成本体验20+款云产品!

更多网易研发、产品、运营经验分享请访问网易云社区

相关文章:
【推荐】 从加班论客户端开发中的建模
【推荐】 浅谈代码结构的设计

MongoDB的正确使用姿势的更多相关文章

  1. MongoDB系列:五、MongoDB Driver使用正确的姿势连接复制集

    MongoDB复制集(Replica Set)通过存储多份数据副本来保证数据的高可靠,通过自动的主备切换机制来保证服务的高可用.但需要注意的时,连接副本集的姿势如果不对,服务高可用将不复存在. 使用复 ...

  2. xpath轴的正确使用姿势

    网上看了许多关于轴的介绍,只介绍了语法,而没有明说具体实际中该怎么使用,百思不得其解. 背景--python中使用xpath:  ----------------------------------- ...

  3. 高版本jquery尤其是1.10.2的版本设置input radio设置值的最正确的姿势。

    $("input:radio[name="analyshowtype"]").attr("checked",false); $(" ...

  4. NSnotificationCenter 正确使用姿势, removeObject 探索

    最近在做平板的过程中,发现了一些很不规范的代码.偶然修复支付bug的时候,看到其他项目代码,使用通知的地方没有移除,我以为我这个模块的支付闪退是因为他通知没有移除的缘故.而在debug和看了具体的代码 ...

  5. 微信H5中静默登录及非静默登录的正确使用姿势

    在微信中打开网页且需要调用微信登录接口时,微信官方给我们提供了两种登录调用方式:静默登录和非静默登录:但是官方文档中却没有说明在何种情况下使用静默登录,何种情况下使用非静默登录,所以在这里,我想将之前 ...

  6. Java日志正确使用姿势

    前言 关于日志,在大家的印象中都是比较简单的,只须引入了相关依赖包,剩下的事情就是在项目中“尽情”的打印我们需要的信息了.但是往往越简单的东西越容易让我们忽视,从而导致一些不该有的bug发生,作为一名 ...

  7. 基于winserver的Apollo配置中心分布式&集群部署实践(正确部署姿势)

    基于winserver的Apollo配置中心分布式&集群部署实践(正确部署姿势)   前言 前几天对Apollo配置中心的demo进行一个部署试用,现公司已决定使用,这两天进行分布式部署的时候 ...

  8. 玩转java多线程(wait和notifyAll的正确使用姿势)

    转载请标明博客的地址 本人博客和github账号,如果对你有帮助请在本人github项目AioSocket上点个star,激励作者对社区贡献 个人博客:https://www.cnblogs.com/ ...

  9. Gradle的依赖方式——Lombok在Gradle中的正确配置姿势

    写过java的都知道,lombok几乎在项目中处于不可或缺的一部分,但是lombok在Gradle的项目中配置并非人人都知道. 很多人在项目依赖中直接这样写 1 compile "org.p ...

随机推荐

  1. P1816 忠诚 倍增

    链接:https://www.luogu.org/problem/show?pid=1816 题目描述 老管家是一个聪明能干的人.他为财主工作了整整10年,财主为了让自已账目更加清楚.要求管家每天记k ...

  2. 借助Code Splitting 提升单页面应用性能

    近日的工作集中于一个单页面应用(Single-page application),在项目中尝试了闻名已久的Code splitting,收获极大,特此分享. Why we need code spli ...

  3. 关于nodejs模块安装后找不到包解决办法

    主要原因是类似bower.gulp这些包后,没有添加到环境变量,但是有洁癖的我也不希望添加太多的软链接,所以在用phpstorm开始时有需要的情况下 定义临时的环境变量 http://stackove ...

  4. html5.0学习记录(一)——可拖动视频播放器

    最近自己在重新学习html5新特性,了解到有视频标签和拖动标签,于是自己用这两个特性写了一个小demo,主要功能就是可以通过拖动视频来直接播放.效果图如下: 页面使用了<video>标签和 ...

  5. iOS Runloop 消息循环

    介绍 Runloop是一种事件监听循环,可以理解成一个while死循环,监听到事件就起来,没有就休息. Runloop可以在不同模式下进行切换,iOS有五种模式,其中UIInitializationR ...

  6. SQL根据出生日期精确计算年龄、获取日期中的年份、月份

    第一种: 一张人员信息表里有一人生日(Birthday)列,跟据这个列,算出该人员的年龄 datediff(year,birthday,getdate()) 例:birthday = '2003-3- ...

  7. python在d盘,robotframework引入seleniumlibrary报错

    在*** setting*** 中引入库   Library  SeleniumLibrary  报错 unknown seleniumlibrary library ,try to use quic ...

  8. CentOS7——防火墙设置

    1.查看firewall服务状态 systemctl status firewalld 2.查看firewall的状态firewall-cmd --state 3.开启.重启.关闭.firewalld ...

  9. Open Cascade:拓扑类型(Topo_DS)之间类型转换

    TopoDS_Edge aEdge = TopoDS::Edge(myAISShape->Shape()); TopoDS_Wire S1_wire = static_cast(S1); // ...

  10. CPP-基础:strcpy之于C++(

    以下对strcpy函数错误的是? char atr1[]="string"; ]; char *str3; char *str4="sting"; A.strc ...