NoSQL 的全称是 Not Only SQL, 也可以理解非关系型的数据库, 是一种新型的革命式的数据库设计方式, 不过它不是为了取代传统的关系型数据库而被设计的, 它们分别代表了不同的数据库设计思路。
1. MongoDB, MySQL 和 Redis
1.1 MongoDB
- 它是一个内存数据库, 数据都是放在内存里面的
- 对数据的操作大部分都在内存中, 但 MongoDB 并不是单纯的内存数据库
- MongoDB 是由 C++ 语言编写的, 是一个基于分布式文件存储的开源数据库系统
- 在高负载的情况下, 添加更多的节点, 可以保证服务器性能
- MongoDB 旨在为 WEB 应用提供可扩展的高性能数据存储解决方案。
MongoDB 将数据存储为一个文档, 数据结构由键值(key=>value)对组成。MongoDB 文档类似于 JSON 对象。字段值可以包含其他文档, 数组及文档数组。
1.1.1 MongoDB 的存储特点
在传统的关系型数据库中, 数据是以表单为媒介进行存储的, 每个表单均拥有纵向的列和横向的行。
由此可见, 相比较 MySQL, MongoDB 以一种直观文档的方式来完成数据的存储。它很像 JavaScript 中定义的 JSON 格式, 不过数据在存储的时候 MongoDB 数据库为文档增加了序列化的操作, 最终存进磁盘的其实是一种叫做 BSON 的格式, 即 Binary-JSON。
1.1.2 MongoDB 的应用场景
在另一方面, 对开发者来说, 如果是因为业务需求或者是项目初始阶段, 而导致数据的具体格式无法明确定义的话, MongoDB的这一鲜明特性就脱颖而出了。相比传统的关系型数据库, 它非常容易被扩展, 这也为写代码带来了极大的方便。
不过 MongoDB 对数据之间事务关系支持比较弱, 如果业务这一方面要求比较高的话, MongoDB 还是并不适合此类型的应用。
非关系型数据库(NoSQL ),属于文档型数据库。先解释一下文档的数据库, 即可以存放 xml、json、bson 类型系那个的数据。这些数据具备自述性(self-describing), 呈现分层的树状数据结构。数据结构由键值(key=>value)对组成。
1.1.3 存储方式: 虚拟内存+持久化
持久化方式:
MongoDB 的所有数据实际上是存放在硬盘的, 所有要操作的数据通过 mmap 的方式映射到内存某个区域内。
然后, MongoDB 就在这块区域里面进行数据修改, 避免了零碎的硬盘操作。
至于 mmap上的内容flush到硬盘就是操作系统的事情了, 所以, 如果, MongoDB 在内存中修改了数据后, mmap 数据flush到硬盘之前, 系统宕机了, 数据就会丢失。
1.1.4 主要特点
MongoDB 的提供了一个面向文档存储, 操作起来比较简单和容易。
你可以在 MongoDB 记录中设置任何属性的索引 (如: FirstName=“Sameer”,Address=“8 Gandhi Road”)来实现更快的排序。
你可以通过本地或者网络创建数据镜像, 这使得 MongoDB 有更强的扩展性。
如果负载的增加(需要更多的存储空间和更强的处理能力) , 它可以分布在计算机网络中的其他节点上这就是所谓的分片。
MongoDB 支持丰富的查询表达式。查询指令使用 JSON 形式的标记, 可轻易查询文档中内嵌的对象及数组。
MongoDB 使用 update() 命令可以实现替换完成的文档(数据)或者一些指定的数据字段 。
MongoDB 中的 Map/reduce 主要是用来对数据进行批量处理和聚合操作。
Map 和 Reduce。Map 函数调用 emit(key,value) 遍历集合中所有的记录, 将 key 与 value 传给 Reduce 函数进行处理。
Map 函数和 Reduce 函数是使用 JavaScript 编写的, 并可以通过 db.runCommand 或 mapreduce 命令来执行 MapReduce 操作。
GridFS 是 MongoDB 中的一个内置功能, 可以用于存放大量小文件。
MongoDB 允许在服务端执行脚本, 可以用 Javascript 编写某个函数, 直接在服务端执行, 也可以把函数的定义存储在服务端, 下次直接调用即可。
MongoDB支持各种编程语言:RUBY, PYTHON, JAVA, C++, PHP, C# 等多种语言。
- 它里面自带了一个名叫 GirdFS 的分布式文件系统, 这就为 MongoDB 的部署提供了很大便利。而像 MySQL 这种比较早的数据库, 虽然市面上有很多不同的分表部署的方案, 但这种终究不如 MongoDB 直接官方支持来得便捷实在。
- 另外, MongoDB 内部还自建了对 map-reduce运算框架的支持, 虽然这种支持从功能上看还算是比较简单的, 相当于MySQL里 GroupBy 功能的扩展版, 不过也为数据的统计带来了方便。
- MongoDB 在启动后会将数据库中的数据以文件映射的方式加载到内存中。如果内存资源相当丰富的话, 这将极大地提高数据库的查询速度, 毕竟内存的 I/O 效率比磁盘高多了。
MongoDB 以 BSON 结构(二进制)进行存储, 对海量数据存储有着很明显的优势。
1.1.5 监控
MongoDB提供了网络和系统监控工具Munin, 它作为一个插件应用于MongoDB中。
Gangila是MongoDB高性能的系统监视的工具, 它作为一个插件应用于MongoDB中。
基于图形界面的开源工具 Cacti, 用于查看CPU负载, 网络带宽利用率,它也提供了一个应用于监控 MongoDB 的插件。
查询语句: 是独特的 MongoDB 的查询方式。
适合场景: 事件的记录, 内容管理或者博客平台等等。
架构特点: 可以通过副本集, 以及分片来实现高可用。
数据处理: 数据是存储在硬盘上的, 只不过需要经常读取的数据会被加载到内存中, 将数据存储在物理内存中, 从而达到高速读写。
成熟度与广泛度: 新兴数据库, 成熟度较低, No SQL 数据库中最为接近关系型数据库, 比较完善的 DB 之一, 适用人群不断在增长。
1.1.6 MongoDB 优点
- 1.性能优越:快速!在适量级的内存的 MongoDB 的性能是非常迅速的, 它将热数据存储在物理内存中, 使得热数据的读写变得十分快
- 2.高扩展:第三方支持丰富(这是与其他的 No SQL 相比, MongoDB 也具有的优势)
- 3.自身的 Failover 机制!
- 4.弱一致性(最终一致), 更能保证用户的访问速度
- 5.文档结构的存储方式, 能够更便捷的获取数据: json 的存储格式
- 6.支持大容量的存储,内置 GridFS
- 7.内置 Sharding
1.1.7 MongoDB 缺点
- MongoDB 不支持事务操作(最主要的缺点)
- MongoDB 占用空间过大
- MongoDB 没有如 MySQL 那样成熟的维护工具, 这对于开发和IT运营都是个值得注意的地方
1.2 Redis
它就是一个不折不扣的内存数据库。
持久化方式:
Redis 所有数据都是放在内存中的, 持久化是使用 RDB 方式或者 aof 方式。
1.3 MySQL
无论数据还是索引都存放在硬盘中。到要使用的时候才交换到内存中。能够处理远超过内存总量的数据。
关系型数据库。
在不同的引擎上有不同 的存储方式。
查询语句是使用传统的 SQL 语句, 拥有较为成熟的体系, 成熟度很高。
开源数据库的份额在不断增加, MySQL 的份额页在持续增长。
缺点就是在海量数据处理的时候效率会显著变慢。
2. 三者之间的相互比较
- 当物理内存够用的时候, Redis > MongoDB > MySQL
- 当物理内存不够用的时候, Redis 和 MongoDB 都会使用虚拟内存
- 实际上如果Redis要开始虚拟内存, 那很明显要么加内存条, 要么你就该换个数据库了
但是, MongoDB 不一样, 只要, 业务上能保证, 冷热数据的读写比, 使得热数据在物理内存中, mmap 的交换较少。
MongoDB 还是能够保证性能。有人使用 MongoDB 存储了上T的数据。
MySQL, MySQL根本就不需要担心数据量跟内存下的关系。不过, 内存的量跟热数据的关系会极大地影响性能表现。
当物理内存和虚拟内存都不够用的时候, 估计除了 MySQL 你没什么好选择了。
其实, 从数据存储原理来看, 我更倾向于将 MongoDB 归类为硬盘数据库, 但是使用了 mmap 作为加速的手段而已。
<b>简说mmap</b>
mmap系统调用并不是完全为了用于共享内存而设计的。它本身提供了不同于一般对普通文件的访问方式, 进程可以像读写内存一样对普通文件进行操作。
mmap 系统调用使得进程之间通过映射同一个普通文件实现共享内存。普通文件被映射到进程地址空间后, 进程可以像访问普通内存一样对文件进行访问, 不必再调用。 read(), write()等操作。mmap 并不分配空间, 只是将文件映射到调用进程的地址空间里, 然后你就可以用 memcpy 等操作写文件, 而不用 write() 了.写完后用 msync() 同步一下, 你所写的内容就保存到文件里了. 不过这种方式没办法增加文件的长度, 因为要映射的长度在调用 mmap() 的时候就决定了。
2.1 MongoDB 与 MySQL 的比较
2.1.1 MongoDB 与 MySQL 的适用场景
MongoDB 的适用场景为: 数据不是特别重要(例如通知, 推送这些), 数据表结构变化较为频繁, 数据量特别大, 数据的并发性特别高, 数据结构比较特别(例如地图的位置坐标), 这些情况下用 MongoDB , 其他情况就还是用 MySQL , 这样组合使用就可以达到最大的效率。
-
基于以下几种情况的考量, 可以考虑吧 MongoDB 作为后端DB
- MongoDB 所负责部分以文档形式存储, 能够有较好的代码亲和性, json 格式的直接写入方便。(如日志之类)
- 从 data models 设计阶段就将原子性考虑于其中, 无需事务之类的辅助。开发用如 nodejs 之类的语言来进行开发, 对开发比较方便。
- MongoDB 本身的 failover 机制, 无需使用如 MHA 之类的方式实现。
-
将 MongoDB 作为类似 Redis, memcache 来做缓存db, 为 MySQL 提供服务, 或是后端日志收集分析
考虑到 MongoDB 属于 No SQL 型数据库, SQL 语句与数据结构不如 MySQL 那么亲和 , 也会有很多时候将 MongoDB 做为辅助MySQL 而使用的类 Redis memcache 之类的缓存db来使用。 亦或是仅作日志收集分析。
MongoDB 有一个最大的缺点, 就是它占用的空间很大, 因为它属于典型空间换时间原则的类型。那么它的磁盘空间比普通数据库会浪费一些, 而且到目前为止它还没有实现在线压缩功能, 在 MongoDB 中频繁的进行数据增删改时, 如果记录变了, 例如数据大小发生了变化, 这时候容易产生一些数据碎片, 出现碎片引发的结果, 一个是索引会出现性能问题。
另外一个就是在一定的时间后, 所占空间会莫明其妙地增大, 所以要定期把数据库做修复, 定期重新做索引, 这样会提升MongoDB 的稳定性和效率。
在最新的版本里, 它已经在实现在线压缩, 估计应该在2.0版左右, 应该能够实现在线压缩, 可以在后台执行现在repair DataBase 的一些操作。如果那样, 就解决了目前困扰我们的大问题。
- MySQL 使用 Table/Row/Column; MongoDB 使用 Collection/Document
- MySQL 需要指定 table 的 schema; MongoDB的 collection 的每个 document 的 schema 可以自由修改)
- MySQL 支持 join; MongoDB 没有 join
- MySQL 使用 SQL 语言; MongoDB 使用类似 JavaScript 的函数
2.1.2 命令对比
MongoDB 与 MySQL 命令对比 传统的关系数据库一般由数据库(database)、表(table)、记录(record)三个层次概念组成, MongoDB 是由数据库(database)、集合(collection)、文档对象(document)三个层次组成。MongoDB对于关系型数据库里的表, 但是集合中没有列、行和关系概念, 这体现了模式自由的特点。
MongoDB (文档型数据库): 提供可扩展的高性能数据存储
- 基于分布式文件存储
- 高负载情况下添加更多节点, 可以保证服务器性能
- 将数据存储为一个文档
2.1.3 MongoDB 与 MySQL 的比较
- 稳定性
- 索引, 索引放在内存中, 能够提升随机读写的性能。如果索引不能完全放在内存, 一旦出现随机读写比较高的时候, 就会频繁地进行磁盘交换, MongoDB 的性能就会急剧下降
- MongoDB占用的空间很大
- MongoDB 对数据间的事务关系支持比较弱
- 运维不方便
2.1.4 MongoDB 相对于 MySQL 的优势
- 适合那些对数据库具体数据格式不明确或者数据库数据格式经常变化的需求模型, 而且对开发者十分友好。
- 自带一个分布式文件系统, 可以很方便地部署到服务器机群上。
MongoDB 里有一个Shard的概念, 就是方便为了服务器分片使用的。每增加一台Shard, MongoDB 的插入性能也会以接近倍数的方式增长, 磁盘容量也很可以很方便地扩充。 - 自带了对map-reduce运算框架的支持, 这也很方便进行数据的统计。类似于group by
MongoDB 与 MySQL 命令对比 传统的关系数据库一般由数据库(database)、表(table)、记录(record)三个层次概念组成,
MongoDB 是由数据库(database)、集合(collection)、文档对象(document)三个层次组成。
MongoDB 对于关系型数据库里的表, 但是集合中没有列、行和关系概念, 这体现了模式自由的特点。
2.2 MongoDB 和 Redis 的比较
MongoDB 更类似 MySQL, 支持字段索引、游标操作, 其优势在于查询功能比较强大, 擅长查询 JSON 数据, 能存储海量数据, 但是不支持事务。
MySQL 在大数据量时效率显著下降, MongoDB 更多时候作为关系数据库的一种替代。
2.2.1 内存管理机制
Redis 数据全部存在内存, 定期写入磁盘, 当内存不够时, 可以选择指定的 LRU 算法删除数据。
MongoDB 数据存在内存, 由 linux系统 mmap 实现, 当内存不够时, 只将热点数据放入内存, 其他数据存在磁盘。
2.2.2 支持的数据结构
Redis 支持的数据结构丰富, 包括hash、set、list等。
MongoDB 数据结构比较单一, 但是支持丰富的数据表达, 索引, 最类似关系型数据库, 支持的查询语言非常丰富。
2.2.3 性能
二者性能都比较高, 应该说都不会是瓶颈。
2.2.4 可靠性
二者均支持持久化。
2.2.5 集群
MongoDB 集群技术比较成熟, Redis从3.0开始支持集群。
2.2.6 不适用的场景
- 需要使用复杂sql的操作
- 事务性系统
下面是 MongoDB 和 Redis 的对比图:
2.3 MySQL 与 Redis 的比较
MySQL 是持久化存储, 存放在磁盘里面, 检索的话, 会涉及到一定的 IO, 为了解决这个瓶颈, 于是出现了缓存, 比如现在用的最多的 memcached(简称mc)。首先, 用户访问mc, 如果未命中, 就去访问 MySQL, 之后像内存和硬盘一样, 把数据复制到mc一部分。
Redis 和mc都是缓存, 并且都是驻留在内存中运行的, 这大大提升了高数据量web访问的访问速度。然而mc只是提供了简单的数据结构, 比如 string存储; Redis却提供了大量的数据结构, 比如string、list、set、hashset、sorted set这些, 这使得用户方便了好多, 毕竟封装了一层实用的功能, 同时实现了同样的效果, 当然用Redis而慢慢舍弃mc。
内存和硬盘的关系, 硬盘放置主体数据用于持久化存储, 而内存则是当前运行的那部分数据, CPU访问内存而不是磁盘, 这大大提升了运行的速度, 当然这是基于程序的局部化访问原理。
推理到 Redis + MySQL, 它是内存+磁盘关系的一个映射, MySQL 放在磁盘, Redis放在内存, 这样的话, web应用每次只访问Redis, 如果没有找到的数据, 才去访问 MySQL。
然而 Redis + MySQL 和内存+磁盘的用法最好是不同的。
前者是内存数据库, 数据保存在内存中, 当然速度快。
后者是关系型数据库, 功能强大, 数据访问也就慢。
像memcache, MongoDB, Redis, 都属于No SQL系列。
不是一个类型的东西, 应用场景也不太一样, 还是要看你的需求来决定。
作者: 喵星人Xcode喵星人Xcode