系统设计常见取舍之一 SQL vs NoSQL

系统设计中免不了要提数据库设计,数据库设计又离不开 SQL vs NoSQL 的讨论。看完这篇文章,你将学会一步一步有理有据地锁定合适的数据库技术选型。

有兴趣让作者带你系统性学习系统设计,请点击免费试听:

爱思系统设计集训营「免费试听」
全网唯一资深面试官级深度的系统设计集训营免费试听课将于美西时间 4/22/2022 6:30pm 开讲。试听课覆盖系统设计考察要点,答题模板以及 Whatsapp 精解。完整课程共32课时,旨在培养扎实的系统设计能力。深挖20道常见系统设计面试原题,提炼面试答题技巧,详解设计图组件,总结分布式系统知识。有效帮你融会贯通,增加你的答题深度广度,让你能够举一反三,从容面对面试官的追问以及新题。

1. SQL 是什么

SQL 是一种管理 RDBMS (Relational Data Stream Management System 关系型数据库) 数据的编程语言。通常我们在讨论所谓 SQL 数据库的时候,我们指代的就是关系型数据库,在本文中我们就不做区分。

关系型数据库相对主流,不仅在传统行业(如银行)系统中有广泛应用,在当今的大型在线服务中也有一席之地。

关系型数据库存储结构化数据。这些数据逻辑上以行列二维表的形式存在,每一列代表数据的一种属性,每一行代表一个数据实体。

Image from Oracle Documentation

关系型数据库很多优点:

  • 易于理解 - 二维表很接近我们逻辑上理解世界的方式
  • 易于维护 - 社区成熟,服务稳定,数据稳定,高一致性 (Consistency),读写实时
  • 使用灵活 - SQL 语言功能丰富,可以在表间进行 JOIN

关系型数据库缺点也有不少:

  • 高并发读写性能较弱 - 为了保证高一致性加锁造成读写性能的牺牲
  • 表结构 (Schema) 改动成本高 - 修改表结构时会造成部分数据库服务不可用
  • 水平扩展 (Horizontal Scaling) 较难 - 需要解决跨服务器 JOIN,分布式事务等问题

关系型数据库诞生于上世纪70年代,时代变迁,很多当时还成立的假设现在已经有了变化,比如硬盘的成本不再是制约数据存储的瓶颈,海量数据的读写成为了如今应用的标配。这也就为 NoSQL 的发展提供了土壤。

2. NoSQL 是什么

NoSQL 也被称为 “non-SQL”, “non-relational”(非关系型),有时候也叫做 “Not only SQL”。NoSQL 数据库逻辑上提供了不同于二维表的存储方式。

Image from geeksboots.com. What is NoSQL database and why should you learn/use it?‌‌

NoSQL 的优势在于为现代应用提供更合适的数据库方案:

  • 横向扩展 (Horizontal Scaling) - 支持海量读写的需求
  • 数据复制 (Replication) 和分区 (Partition)
  • 更高的可用性 (Availability) - 以牺牲一定的一致性 (Consistency) 为代价
  • 提倡反正规化 (Denormalization) - 利用便宜的硬盘空间来提高查询性能
  • 多样的数据存储方式 - 使用更符合应用特征的方案节约开发时间
  • 简化应用设计初期的存储模型设计 - 支持存储信息更灵活地迭代

NoSQL 的缺点有几个:

  • 一致性支持较弱 - 多数 NoSQL 数据库倾向于牺牲一致性来增强可用性
  • 不支持 JOIN
  • 社区较新

3. 选择 SQL 还是 NoSQL

了解了 SQL 和 NoSQL 的基本特征后,我们来看看如何选择。

3.1 选择一 ACID vs BASE

Image from yalantis.com. Top Databases in 2020: Types, Popular Solutions, and Things to Consider

关系型数据库支持 ACID (Atomicity, Consistency, Isolation, Duration) 即原子性,一致性,隔离性和持续性。 相对而言,NoSQL 采用更宽松的模型 BASE (Basically Available, Soft state, Eventual Consistency) 即基本可用,软状态和最终一致性

从实用的角度出发,我们需要考虑对于面对的应用场景,ACID 是否是必须的。比如银行应用就必须保证 ACID,否则一笔钱可能被使用两次;又比如社交软件不必保证 ACID,因为一条状态的更新对于所有用户读取先后时间有数秒不同并不影响使用。

对于需要保证 ACID 的应用,我们可以优先考虑 SQL。反之则可以优先考虑 NoSQL。

值得注意的是,近年来随着 NoSQL 的发展,也有不少 NoSQL 数据库在分布式 ACID 的支持上越做越好,比如 MongoDB 和 DynamoDB。虽然还需要时间的检验,但可以想见未来 ACID 将不再是关系型数据库的专利。

3.2 选择二 结构化数据 vs 非结构化数据

有时候我们的应用包含着非常结构化的数据,可以简单地放入一个二维表中;有时候我们的应用需要存储一个键值对,一个图 (Graph),一篇文章。前者我们可以采用 SQL 或者 NoSQL,而后者我们优先考虑 NoSQL 并且选择合适类型的 NoSQL 数据库存储数据。

NoSQL 对于数据库结构 (Database Schema) 的依赖小于关系型数据库,很多时候,结构可以在应用开发过程中低成本迭代。这样做旨在对于开发者给出更大的灵活性以适应应用快速迭代的开发需求。

3.3 选择三 扩展性 (Scalability)

Image from turbonomic.com

NoSQL 数据库的横向扩展性 (Horizontal Sacaling) 一般来说要好于关系型数据库,多数 NoSQL 在设计之初就以横向扩展性作为优先设计目标,这就让数据库管理员可以使用数据库自带的功能,更容易满足高并发的需求。另外 NoSQL 因为提倡采用反正规划 (Denormalization) 并在表结构设计时采用查询驱动的设计 (Query-driven Design),查询时只需要访问一个表,这样也使得横向扩展更加容易。

相反,如果采用关系型数据库,传统上它的主要扩展方式是纵向扩展性 (Veritical Scaling) 即采用更大更强的机器。然而,今天的很多关系型数据库也拥有了一定的横向扩展性支持。相对来说横向扩展对于关系型数据库会更难一点,会更要求我们好好考虑如何设计表以及进行分片来满足查询的要求。

4. 挑选合适的 NoSQL 数据库

现在我们已经知道了该选择 SQL 还是 NoSQL 了。如果 NoSQL 是我们的选择,下一个需要考虑的问题就是选择哪一款 NoSQL 数据库。

在之前的讨论中我们把 NoSQL 作为一个整体来考虑,但实际上,NoSQL 有四个不同的类型,具体的实现就更多了。

在上文中我们提过,NoSQL 的结构设计是查询驱动的设计 (Query-driven Design),选择 NoSQL 数据库的关键要素是找到合适的查询模式。下面我们就分析一下这四种类型。

Image from Gleb B., Vlad L. (2018). Neo4j Graph Database: Use Cases and Real-life Examples‌‌

4.1 Key Value Store

这是 NoSQL 数据库的最简单的类型,数据即简单的键值对。这种类型的代表是 Redis,严格的来说,与其称 Redis 为数据库不如称其为缓存,其最合适的应用场景并不是长期存储数据而是将经常访问的请求结果暂时保存下来,避免反复向背后的数据库请求相同的信息。

Image from Deister Software

这类数据库适合存储大量具有 Key-Value 简单查询模式的数据。

4.2 Wide-Column Store

Image from Google BigTable Paper

Wide-column Store 的两个特点可以从上图中看出。

  • 可以看做二维版的 Key-value Store,如上图中的 “contents” 列包含不同时间戳的 HTML 内容。
  • 支持 Column Family, 如上图中的 anchor Column Family 包含两个包含 CNN 关键词的网站名。

BigTable 是这类数据库的鼻祖,HBase 和 Cassandra 也是这个类型的代表,其中 HBase 相比 Cassandra 提供更强的一致性 (Consistency) 。

此类数据库适合存储大量具有可预测的查询模式的数据。

4.3 Document Store

Image from MongoDB Documentation. What is a Document Database?

Document Store 以 JSON 的形式存储数据,这使得它的结构极其灵活,当我们有额外信息需要存储时只需要简单地将新的信息作为一对新的键值对加入 JSON 即可。在 JSON 的基础上, Document Store 同样支持添加 Index 来加速查询。

Document Store 的代表是 MongoDB 和 CouchDB。

此类数据库由于 JSON 的丰富表现力,对各类数据形式的适应性都比较好。

4.4 Graph Store

Image from neo4j.com Neo4J Code Sample for Social Use Case

Graph Store 顾名思义是用来建模图的。在 Graph Store 中信息以节点 (Node) 和边 (Edge) 的形式存储,其中边用来表达节点之间的关系。这种数据库可以实现非 Graph Store 数据库无法轻易实现的查询,如上图所表达的从两个节点(人)之间六个边(认识关系)之内的所有路径。

Graph Store 的代表是 Neo4J,很适合社交关系,网络管理和欺诈识别 (Fraud Detection) 等应用场景。

此类数据库专业处理分析图状数据。

5. 总结

回顾一下之前的内容,在本文中,我们讨论了如何选择数据库的技术选型,大致有以下几个步骤:

  1. 选择 SQL vs NoSQL 考虑以下因素
    a. ACID vs BASE
    b. 结构化数据 vs 非结构化数据
    c. 扩展性
  2. 如选择 NoSQL,根据查询模式选择以下四种之一
    a. Key-value Store
    b. Wide-column Store
    c. Document Store
    d. Graph Store

经过这些步骤,我们就能找到适合应用场景的数据库类型了。在实际工作中,我们还需要落实到具体的采用哪一个具体的数据库(如 MySQL, MongoDB) ,此时我们就要根据应用的一致性要求,数据库的配置选项等等因素来做进一步匹配。由于牵涉到特定数据库的细节,在本文中就不赘述了。

了解了以上这些内容,相信大家对于面试中的数据库选型已经不再陌生,并能够对于自己的选择给出令人信服的取舍理由。希望对大家有所帮助。

6. 参考文献