浅谈MongoDb
一、发展史
1、mongoDB由来
2007 年,Dwight、Eliot 和 Kevin Ryan 一起创办了一家叫作 10gen 的新公司。10gen 专注于提供一个带有自有应用程序和数据库栈的 PaaS 托管解决方案。10gen 很快引起了风险投资人 Albert Wenger(Union Square Ventures) 的注意,他向 10gen 投资了 150 万美元。以下是 Albert Wenger 在 2008 年写的有关 10gen 投资的文字:今天,我们很高兴地宣布,我们将为一支特立独行的团队提供支持,也就是 10gen 的一班天才们。他们汇聚了构建互联网规模系统的经验,比如 DART、Panther Express CDN,广泛参与了开源活动,包括 Apache 软件基金会。他们正在为云计算构建一个开源技术栈,包括一个应用服务器和一个数据库,它们都是基于现代硬件能力和构建 Web 站点或服务的经验从头开始开发的。应用服务器最初支持服务器端 Java 和 Ruby(实验性的)。数据库采用了一种有趣的设计来存储对象,这种设计在快速随机访问和高效的集合扫描之间做出了平衡。Albert 所说的“采用了有趣的设计的数据库”实际上指的就是 MongoDB。
2、发展历程
个人觉得,最重要的几个时间节点如下:
2010 年 8 月, 10gen 发布了 MongoDB 1.6,第四个大版本。这个版本最大的一个功能就是 Sharding,自动分片。
2014 年 12 月,MongoDB 收购了 Keith Bostic 和 Michael Cahil 的 WiredTiger 存储引擎团队,并将其集成到 3.0 版本中,成为一个新的存储引擎。
2017 年 10 月,MongoDB 成功在纳斯达克敲钟,成为 26 年来第一家以数据库产品为主要业务的上市公司。
二、mongoDb核心知识点
MongoDB 是一个基于文档的 NoSQL 数据库。它将数据实体存储在集合中,存储的每一个数据块都是 JSON 格式。
1、文档数据库
为了方便大家的理解,特意和mysql进行了对比,如下
2、引擎
MMAPV1:
因为是基于内存映射文件,所以MMAPV1不支持压缩。如果所有数据都能放入内存那么它将变的非常高效。MMAPV1善于处理大量插入、删除及更新的工作场景。
WiredTiger:
支持snappy和zlib两种压缩模式。因此与MMAP相比,使用WiredTiger的MongoDB占用的磁盘空间要小很多。并且WiredTiger引擎本身有自己的写缓存(可配置)同时也能使用文件系统缓存。
Snappy: 默认压缩策略,兼顾高效计算机合理的压缩。
Zlib: 高压缩比但是同时对cpu消耗也比较大。
3、存储结构
chunk 本质上就是由一组 Document 组成的逻辑数据单元。它是分片集群用来管理数据存储和路由的基本单元。
4、日志
Oplog即操作日志(operation log)是用于保存Mongodb数据库所有数据操作记录(实际上只记录改动数据库数据的操作记录,即增/删/改)的固定大小集合(Capped Collections)。类比过来的话就相当于是mysql的binlog日志。但有一点不同的区别就是,oplog大小固定,超过设定阈值后oplog将会覆盖重写。
三、mongo副本集架构
这是之前实践过程中,比较节省机器的一种复用方式,但条件允许情况下,建议mongos和仲裁还是分开部署要好。
1、mongos路由机制
mongos 负责将查询与写入分发到 分片 中.使用 mongos,应用有了访问集群的统一入口,而不需要直接访问集群的每个分片.
Config Servers 配置服务器是保存集群中 元信息 的特殊 mongod .
Shard MongoDB使用片键的范围把数据分布在分片中,每个范围,又称为数据块,定义了一个不重叠的片键范围,MongoDB把数据块与他们存储的文档分布到集群中的不同分片中
相对于clickhouse等其它nosql而言,自带的路由机制就能让应用层无需再担心数据的平衡、落盘,通过统一入口就能快速进行数据的交互。
2、同步原理
总数据大于100MB 已经取到部分数据但没到100MB,但是目前队列没数据了,这个时候会阻塞等待一秒,如果还没有数据则本次取数据完成。(横向对比一下,其实目前大多数优秀的DB,都是基于这几种方式相结合的同步机制)
上述两个条件满足一个之后,就会将数据给prefetchOps方法处理,prefetchOps方法主要将数据以database级别切分,便于后面多线程写入到数据库中。
如果采用的WiredTiger引擎,那这里是以Docment ID 进行切分。最终将划分好的数据以多线程的方式批量写入到数据库中(在从库批量写入数据的时候MongoDB会阻塞所有的读)。然后再将Queue中的Oplog数据写入到Sencondary中的oplog.rs集合中。
四、实践分享
分享当年使用mongo时的小案例,在mongoDb的使用过程中,遇到过这样的一个瓶颈,QPS已经上不去了,那怎么办呢?翻阅了下资料,发现有些参数是可以调动的。如:batchSize
MongoDb 查询数据是先返回游标集,而后真正轮询数据,当batch设置过小时,则getmore次数增加,导致增加真正与mongo交互次数,而
batch最大为4M,所以,当batch设置过大时,mongo也会限制到4M。
于是乎,我把mongo源码改了。。。,是的,你没看错。在我以为能以此来提高并发的时候,其实一切的默认都已是最好的结局
调整前:
调整后:
经测试后表明:发现 batchSize设置很大,getmore次数少但是数据一次拿回来大,导致传输慢。相反getmore多次,拿的数据量小,所以每次
都快,但是加起来时间差不多。
结论:调整batchSize对于mongoDb性能提升不明显,4M确实是较为合理的设置。
其它的案例,有兴趣的同学可以一起交流探讨,毕竟19年的mongo也是在高速迭代的过程,在某搜索高并发的场景下,也踩了不少的坑。
PS:印象中踩过的坑
1、chunksize设置必须为INT类型,否则所有分片无法读取chunk配置,从而使分片失败,所有chunk集中在一个分片上,且chunk无法自行平衡。
2、 3.2版本mongod实例直接挂了,原因为Mongo自身bug导致,提过jira给官方,https://jira.mongodb.org/browse/SERVER-38292?attachmentViewMode=list,但官方也找不到根本原因,提议为升级。为应对这种情况,需要有定时检测脚本检测实例是否运行。
3、OPS自带告警通知机制,建议配置需要告警机制。
4、mongod实例自己挂了,重启该从库实例发现数据已经超过了增量同步的界限,解决办法为清除从库,全量同步
5、ops中shard状态变更为R时需要关注,必要时清除从库全量同步反而比恢复要更快
6、别以为三台机器的2分片高可用架构就是最稳定的,曾经试过在某攻击下,流量过载导致1台机器崩溃,但重启恢复速度不足,导致第二台机器也撑不了多久被打爆,导致集群崩溃。(所以平时就要考虑好降级、熔断机制,还有合理的oplog大小,这能帮助mongo以最快的速度重新营业)
7、很多坑忘记了。。。有遇到再一起探讨
本文是浅为介绍mongo的同时,结合了自己几年前的一些实践经验而谈,希望能帮助到读者对mongo了解一二。
最后想表达的就是,很多sql、nosql,我们用过,实践过,但哪怕再熟悉,当过了几年后,试问下你还能记得多少呢。
只有当横向拉平这些nosql的特点,对比每个数据库的优缺点,集群架构,才能帮助我们更好的去理解,乃至能快速适应新颖的数据库,毕竟优秀的产品都是建立的伟大的前辈们肩上过来的。