本文由 简悦 SimpRead) 转码, 原文地址 mp.weixin.qq.com)
2. 大器晚成 NoSQL
2009 年在亚特兰大的一次重要会议上对 NoSQL 提出了个文雅 & 响亮的口号:
select fun, profit from real_world where relational=false;
本质上 NoSQL 是一类数据库的泛称,具体的可以分为以下几种:
本文只介绍键值对 key-value 型数据库,先看下 NoSQL 名字的来源和含义的几种解读吧:
- 解读一
NoSQL 意为 “No SQL” 翻译为 SQL 已死。潜台词是这类数据库没有 SQL 语句,摒弃了老大哥 MySQL 的路子,让它退休。
嚯,好家伙,口气不小,事实证明,这种 “SQL 已死 “ 的自信确实有点扯犊子了。 - 解读二
NoSQL 意为 “Not Only SQL“,显然没有那么嚣张了,倒添了几分谦虚,不仅仅是 SQL,除了继承了老大哥 MySQL 的一些功能,还增加了新东西,听起来还不错的样子。 - 解读三
NoSQL 本质上是非关系型数据库,我们都知道关系型数据库一般缩写为 RDS 或者 RDB,所以有人觉得 NoSQL 应该称为 “No Relational Database“,简称” 没关系数据库 “
综上,我们更倾向于 NoSQL 为 “Not Only SQL“,作为关系型数据库的补充而存在的一种新形式的数据库。
3. 给 NoSQL 一首歌的时间
工欲善其事 必先利其器,大家都这么忙,必须要给个学习 NoSQL 的理由。
- 场景一
Leader 大熊给小黑一个需求,这个需求在几千万行的 MySQL 中加个字段,由于是生产环境需要找 DBA 手动执行,好家伙排队大半天才给执行,给小黑气的,太耽误事了太不方便了。
- 场景二
Leader 大熊又给了小黑一个需求,让他存储一个数据包,数据包其实是 Json 的串,里面有很多字段,但是现在也不明确 PM 要怎么用,字段是否会调整,所以用 MySQL 存储的话,字段还不能确定,于是小黑加了个 extra 字段来存储后续的扩展,暂时解决了。 - 场景三
Leader 大熊让小黑设计一个并发访问大一些的服务,来完成用户账号体系查询,目前差不多有 4 亿账号 ID,大熊搞了 C++ 服务 & 存储选择了 MySQL,性能怎么也提不上去,真是一筹莫展。
MySQL 横行江湖数十载,无人匹敌,尤其在事务、数据一致性、关联查询等场景具有绝对的统治力,确实是数据库蓝波万。
科技进步和新常用新形式的出现也让 MySQL 有些捉襟见肘,毕竟 MySQL 不是万金油,要保住地位必须与时俱进才行。
在很多场景中我们并不需要事务、强数据一致性、多表关联等特性,所以我们需要一类更轻快的数据库,它就是 NoSQL。
4. MySQL vs NoSQL
我们有必要将 MySQL 和 NoSQL 进行一番对比,来加深印象:
- MySQL 是高度组织化结构化的数据存储,NoSQL 无结构化存储
- MySQL 使用结构化查询语句,NoSQL 无查询语言
- MySQL 需要定义字段和模式,NoSQL 自由扩展
- MySQL 海量数据时读写性能劣于 NoSQL
- MySQL 扩展性较差
上面这些好像全是 diss 老大哥 MySQL 的,但是并不是说 MySQL 很弱,相反是 MySQL 非常强悍。
高并发 & 高可用 & 高可扩展的新要求成就了 NoSQL,NoSQL 之所以可以应对这些新场景,和它的设计思想有很大的关系。
或许可以用葡萄来说明为啥 NoSQL 更适用于高并发场景。
- NoSQL 是一粒一粒的葡萄,存取都非常方便,读写速度快
- MySQL 是一串葡萄,每一粒都是相互关联的,存取较为麻烦,读写速度慢
两类数据库的对比就说这么多,我们来看看几款大白在实际工作中用过的 NoSQL 吧!
5. NoSQL 明星项目
开源的 NoSQL 非常多,大白按照层次挑几个典型的代表来和大家分享一下。
NoSQL 可以是单机的,也可以是分布式的,可以根据自己的目的来使用。
今天要介绍的几款数据库:Redis、Pika、SSDB、RocksDB、LevelDB。
其中 LevelDB 是谷歌开发的,RocksDB 是 Facebook 在 LevelDB 的基础上增加新特性开发的,Redis 则不用多说,SSDB 和 Pika 则是国内开源的类 Redis 的数据库,也非常棒。
接下来看看这几款数据库的特点、联系、底层原理等有趣的东西。
5.1 谷歌出品 LevelDB
LevelDB 是谷歌的 Sanjay Ghemawat 和 Jeff Dean 使用 C++ 开发的单进程 / 单机版持久化的 key-value 数据库,于 2011 年 7 月开源,可以说是重磅产品。
LevelDB 支持了最基础的 key-value 操作:Get/Put/Delete,但是并没有封装其他的东西,严格意义上来说只是 NoSQL 存储引擎。
一般来说,机械磁盘最害怕的就是随机读写,磁盘呼噜噜转起来就意味着读写效率在下降。
LevelDB 具有很高的随机写,顺序读 / 写性能,因此 LevelDB 很适合应用在写多读少的场景,真让人好奇高性能的随机写怎么做到的。
5.1.1 LSM 树
很多数据在逻辑上相近,但是在物理存储上却可能相隔很远,这样就会造成大量的随机读写问题,从而降低性能。
LevelDB 实现高性能随机写的秘密武器在于使用 LSM 树存储结构,LSM 树又称为日志结构合并树 (Log-Structured Merge-Tree),它并不是具体的数据结构,而是一种设计思想。
LSM 树对于每次写入操作,并不是直接将最新的数据驻留在磁盘中,而是将数据先放在内存。
当内存数据达到一定的阈值,再将这部分数据真正刷新到磁盘文件中,从而将磁盘随机写转换为内存顺序写,因而获得了极高的写性能,但是这种机制会降低读的性能,总体来说降低部分读性能来大幅提升写性能是值得的。
5.1.2 LevelDB 整体架构
LevelDB 存储结构主要由六个部分组成:
- MemTable:内存数据结构,使用 SkipList 实现,新的数据修改会首先在这里写入,并且有容量限制。
- Immutable MemTable:待落盘的数据库内存结构,当 MemTable 的大小达到设定的阈值时,会变成 Immutable MemTable,只接受读操作,不再接受写操作,后续会 Flush 到磁盘上。
- SST Files:Sorted String Table Files,磁盘数据存储文件,分为 Level0 到 LevelN 多层,每一层包含多个 SST 文件,文件内数据有序。
- Manifest Files:leveldb 元信息清单文件。Manifest 记录 SST 文件在不同 Level 的分布,相当于 SST 文件的索引。
- Current File:当前正在使用的文件清单文件。
LevelDB 的读写过程和上述的整体架构关系密切,也是先内存后磁盘,一层层读取搜索数据的。
5.2 脸书出品 RocksDB
青出于蓝而胜于蓝。
RocksDB 在 LevelDB 的基础上进行了改进和优化,也成为后续很多 NoSQL 所选择的存储引擎。
RocksDB 仍然是采用 C++ 开发的,并且完全向后兼容了 LevelDB 的接口,可以说是个平滑升级。
5.2.1 RocksDB 提升点
来看看 RocksDB 做了哪些优化和提升:
- RocksDB 支持一次获取多个 Key,还支持 Key 范围查找,LevelDB 只能获取单个 Key。
- RocksDB 支持多线程合并,而 LevelDB 是单线程合并的,多核时代前者效率更高。
- RocksDB 增加了合并时过滤器,对不符合条件的 Key 进行丢弃。
- RocksDB 可采用多种压缩算法,除了 LevelDB 用的 snappy,还有 zlib、bzip2。
- RocksDB 支持增量备份和全量备份。
- RocksDB 支持管道式的 Memtable,使用多个 Memtable,LevelDB 只有一个 Memtable。
5.2.2 RocksDB 整体架构
Rocksdb 中引入了 Column Family(列族的概念,所谓列族也就是一系列 kv 组成的数据集,所有的读写操作都需要先指定列族。
每个 ColumnFamily 有自己的 Memtable, SST 文件,所有 ColumnFamily 共享 WAL、Current、Manifest 文件。
如果说 LevelDB 是个平民版的 NoSQL 存储引擎,那么 RocksDB 绝对是尊享版,所以很多优秀的 NoSQL 成品都是基于 RocksDB 来封装上层协议和代理支持完成的。
5.3 ideawu 的 SSDB
SSDB 是基于 SSD 作为底层存储介质的类 Redis 数据库。
Redis 过于迷人和好用,但是又太昂贵了,所以我们幻想着有一款支持 Redis 数据结构且容量没限制的数据库。
这种数据库将 Redis 的数据结构优势和廉价磁盘介质联合起来,着实让人着迷。
没错,SSDB 就是这样一款 NoSQL 数据库。
目前 SSDB 的维护者并不是特别多,并且在集群化等方面还存在一些问题,不过也算是非常优秀的开源 NoSQL 了。
来简单看下 SSDB 的基本架构:
简单来说,SSDB 在 LevelDB 和 Redis 协议之间做了一层转换,从而实现命令和数据的切换,这就是使用存储引擎之前封装附加部分,从而形成完整的 NoSQL。5.4 360 出品 Pika
其实 SSDB 和 Pika 很有渊源,SSDB 的作者曾经在 360 工作,并且 SSDB 当时在 360 的生产环境中使用广泛,Pika 数据库是 360 基于 RocksDB 开发的集群化高性能 NoSQL。
Pika 是 360DBA 团队和基础架构团队使用 C++ 语言联合开发的类 Redis 存储系统,所以完全支持 Redis 协议。
Pika 是一个可持久化的大容量 Redis 存储服务,解决 Redis 由于存储数据量巨大而导致内存不够用的容量瓶颈,并且支持全同步和部分同步。
Pika 还提供了迁移工具,实现 Redis 数据到 Pika 的平滑迁移,Pika 的定位目标并不是取代 redis, 而是作为 redis 的补充,在性能上肯定会低于 Redis。
从整体架构可知,Pika 是多线程实现的,因此对多核使用效率更高,虽然单线程性能不如 Redis,但是多个线程一起上性能也还不错。
Pika 目前在 360 内部使用非常广泛,在一些其他的互联网公司也有使用。
说到底 NoSQL 是一个实践类的项目,本文也不能讲述太多,否则很空洞,意义不大。
5.5 其他 NoSQL
基本上很多互联网公司都会基于 LevelDB 或者 RocksDB 开发一款自己的 Key-Vaule 数据库,有的只支持简单的 string 结构,有的完全兼容 Redis 协议和客户端。
大都是解析 Redis 协议、使用 Redis 的客户端、增加一层命令解析和数据格式解析层、再有可能有多线程支持 & 主从化 & 集群化等。
自己开发一款简单的 NoSQL,可以极大提升自己对于 NoSQL 的理解,在 github 上有很多这样的项目,可以参考学习下。
6. 本文小结
本文粗浅阐述了 NoSQL 的一些相关知识点,以及一些笔者实践过的 NoSQL。
大致原理本质上差不多,但是要打造一款高性能 & 高可用的工业级 NoSQL 是非常困难的。
往期精彩: