NoSQL数据库 ——FoundationDB的键-值存储系统
FoundationDB是一个分布式的键-值存储系统,支持全局ACID事务操作,并且性能出众。在安装系统时,可以指定数据分发的级别。数据分发为容错性提供了支持:当某个服务器或网络的某部分产生故障时,数据库仍然可以正常操作,你的应用也不会受到影响。
键-值与SQL架构
我们开发的这套架构能够在键-值存储系统上支持多个层,每个层都能够在FoundationDB的基础上提供一套不同的数据模型,例如SQL数据库、文档数据库或图形数据库。许多使用者也自行创建了自定义的层。
下图中列出架构中的了关键部分。处于底层的是FoundationDB集群,无论集群的实际大小如何,对它的操作与一个单独的逻辑数据库并没有分 别。SQL层则以一种无状态的中间层方式运行在键-值存储系统之上。这一层通过SQL与应用程序进行通信,并使用FoundationDB的客户端API 与键-值存储系统进行通信。由于SQL层是无状态的,因此可以并行地运行任意数据的SQL层。
SQL层为键-值存储系统带来了如Google的F1般的能力
SQL层是对SQL与键-值存储API进行转换的一套逻辑严密的层。首先,SQL层会从一条SQL语句开始,将其转换为高效地键-值操作。这种方 式类似于编译器将代码转换为低级别的执行格式。并且,这种转换是完全符合ANSI SQL 92标准的。开发者可以将该功能与ORM、REST API进行接合,或者直接使用SQL层的命令行界面进行调用。从代码的角度来说,SQL层与键-值存储是完全分离的,它是通过FoundationDB的 Java绑定方式与键-值存储进行通信的。感兴趣的读者可以查看FoundationDB的SQL层在GitHub上的代码库,其代码是完全开源的。眼下能够和这套系统进行比较的是Google的F1,后者是一套基于该公司的Spanner技术所创建的SQL引擎。
如以下的简单图例所示,SQL层是由一系列组件所组成的。应用程序通过某种受支持的SQL客户端向SQL层发送查询语句,在解析之后转换为一棵计划 节点树。优化器(Optimizer)会计算佳的执行计划,并以一棵操作符树的方式表现出来,随后由执行框架(Execution Framework)运行。在执行阶段,对数据的请求将被发送到存储虚拟(Storage Abstraction)层,这一层通过使用Java的键-值API在数据与FoundationDB集群之间进行传输。数据库模型将存放在 Information Schema层中,这一层将被其它多个组件所调用。
将SQL数据映射到键-值存储系统
SQL层需要管理两种类型的数据,首先是信息Schema的元数据,它负责描述所创建的表与可用的索引。其次,它还需要存储实际的数据,包括表内容、索引及序列。我们首先来描述一下这些数据是如何保存在键-值存储系统中的。
本质上讲,每个键都是对应了某张表中的特定行的指针,而值则包含了该行的数据。键的分配是由Table-Group所决定的,它是包含了一个或多个 表的组。稍后会对这个概念的细节进行更深入的讲解。SQL层会通过使用键-值存储目录层为每个Table-Group创建一个目录,存储目录层是为用户管 理键空间的一个工具,它为每个独立的目录分配一个简短的字节数组,作为该目录的键。同时,它也维护着其它元数据,以实现通过名称进行查找的功能。
下面这个例子演示了如何创建目录的映射,通过以下语句分配键。
CREATE TABLE schema_a.table1(id INT PRIMARY KEY, c CHAR(10));
CREATE TABLE schema_a.table2(id INT PRIMARY KEY);
在键-值存储系统中有一些预定义的目录:
Directory | Tuple | Raw Key |
sql/ | (9) | \x15\x09 |
sql/data/ | (3) | \x15\x03 |
sql/data/table/ | (31) | \x15\x1F |
sql/data/table/schema_a/table1/ | (215) | \x15\xD7 |
sql/data/table/schema_a/table2/ | (247) | \x15\xF7 |