如前所述,我们成功实施了数据库与应用服务器的分离。PostgreSQL数据库现在拥有专属的强大服务器,不再与应用代码逻辑挤在一起。这对于关系型数据库而言是一个经典的拓展升级。
但在现代技术环境中,一个因此自然而生的问题是:为什么一定要用传统的关系型SQL数据库呢?换言之,为啥不考虑更快,水平拓展更容易的NoSQL数据库呢?比如我们常听到的一些流行选择:MongoDB或者Cassandra。
这其实是我们刻意的技术路线选择。要明白其中原因,需要搞清楚数据库世界里的两个基本哲学。
深入技术细节:两个数据库的平行宇宙
我们有两个平行的数据库世界:SQL以及NoSQL。这两个类别都包罗万象并且十分强大,但他们内在的运行逻辑迥异。
- SQL的宇宙(关系型数据库): 这个宇宙中包括广为人知的PostgreSQL,MySQL以及微软的SQL Server等。
- 类比:SQL数据库就像一个清晰明了的Excel文件,其中包含了多个互相关联的表格。
- 核心概念:结构和一致性。数据存储在有着严格类型和列定义的表(Table)中,比如一个price数据列必须保存的是数字类型,一个created_at数据列必须保存的是时间类型。各表之间的逻辑关系被严格约束。所以不可能出现一个商品属于一个不存在的店铺的情况。
- 超能力:ACID原则。这是一整套确保业务逻辑绝对正确的可靠保证,包括原子性(Atomicity),一致性(Consistency),隔离性(Isolation)以及持久性(Durability)。在电商语境里,意味着如果顾客下单买了5样东西,数据库要么(成功情形)会在顾客订单记录中完整保存5样已购商品并且更新相应商品的库存,要么(失败情形)就干脆什么也不记录。绝不会出现数据前后不一只保存了某个部分的情况。
- 最佳场景:任何对数据完整性和一致性有着苛刻要求的应用。这显然包括电商,银行,金融系统或者任何中介预定平台。
- NoSQL的宇宙(非关系型数据库): 这个宇宙会更加多元化,主流的选择包括MongoDB(文档型),Cassandra(超宽数据列),Redis(键值对)以及DynamoDB。
- 类比:NoSQL数据库就像一个文件目录,其中塞满了各式各样的Word文件或者JSON文件。每个文件都可能拥有完全不一样的内容结构。
- 核心概念:灵活性和可拓展性。NoSQL对于要保存的数据不做任何假设。比如某个商品的文档里面可能包含“颜色”这个字段,但并不是每个商品文档都有这个字段。这样的特性有利于在不做数据约束关系调整的情况下修改应用的功能。通常这些NoSQL从设计之初就适合做水平扩展(可以运行在多个廉价的服务器上)。
- 超能力:BASE以及水平拓展能力。大部分NoSQL不强制严格的ACID,而是提供一种成为BASE的替代:常可用(Basically Availabel),弱状态(Soft State)以及最终一致性(Eventual Consistency)。这意味着这类系统优先考虑的是系统可用,而不是时时刻刻的一致性(这个概念将在后面提及只读副本时继续讨论)。这有助于NoSQL以超高的数据写入速度进行海量数据的处理。
- 最佳场景:海量数据处理,社交媒体的信息流,物联网的传感器数据,实时的数据分析或者那些数据约束关系经常变化的应用。
快速总结一下SQL和NoSQL的不同点:
| 特性 | SQL(PostgreSQL) | NoSQL(比如MongoDB) |
|---|---|---|
| 数据模型 | 结构化的(数据表/一行行的数据) | 灵活的(文档类型,键值对类型) |
| 模式(Schema) | 需要提前定义好,严格遵循 | 动态可变的 |
| 拓展性 | 垂直拓展为主(更强大的服务器),可以采用只读副本 | 水平拓展为主(更多数量的服务器) |
| 一致性 | 强一致(ACID约束) | 可调的最终一致性(BASE) |
| 最佳场景 | 电商,金融等对数据一致要求严格的系统 | 社交媒体,大数据,物联网,分析类 |
我们为什么选择SQL路径
看看上面这张表,Dukaan应用适合的技术选择一目了然。
- 我们的数据是高度结构化的:比如每个订单都有一个顾客,已购商品清单,以及一个总价。一个商品总会有名字,价格,以及库存量。我们业务逻辑依赖于这样严格的约束关系。我们不需要NoSQL的灵活性,而是需要SQL的严格一致。
- 数据一致性至关重要:对于电商平台来说,用户信任的基础就在于每一个订单都能被正确处理,每次库存更新能够被准确无误,每笔付款信息都能正确的显示。PostgreSQL的ACID严格约束对于我们来说是不可获取的必需品。
- 我们的瓶颈在于读取数据,而不是写入数据:正如即将在第5章被探讨的那样,我们最大的挑战并不是需要每秒写入上百万的新增商品(很多数据写入的场景恰好是NosQL的主用武之地),而是如何满足数百万对现有商品信息读取的用户请求(这是一个读取数据很多的场景)。PostgreSQL对于这个问题有一个很棒而且成熟可靠的解决方案:制度副本。
我们并没有海量数据的烦恼。我们面对的是电商领域经典的业务难题。如果我们选用一个流行的NoSQL数据库,倒像是不合时宜地杀鸡用牛刀。PostgreSQL就是那个精准契合我们业务场景的可靠且强大的工具。我们相信采用PostgreSQL作为基础数据库足以满足业务增长的需求,甚至应对独角兽级别(10亿美金)的业务量也没问题。
第3章关键知识点总结
- 架构扩展的关键第一步是分离应用服务器以及数据库服务器。这样可以让各组件充分发挥潜能,不至于消耗在资源竞争上。
- 每一个问题解决都可能带来新的问题。转向分布式架构导致网络延时成为了必须考虑的性能瓶颈。
- 昂贵的网络请求能少则少。减少延时最有效的办法就是提高代码效率以减少并优化数据库的查询。可以尝试使用类似select_related以及prefetch_related这样的工具。
- 优化数据库连接。考虑使用类似PgBouncer这样的连接池以减少创建数据库连接的重复工作,这样可以帮助应用更具韧性,在高压下表现更稳健。