GMTC全球大前端技术大会(北京站)门票9折特惠截至本周五,点击立减¥480 了解详情
写点什么

探讨 NuoDB 数据库的架构—1

2013 年 9 月 06 日

介绍

传统的关系型数据库适用于垂直伸缩(scale-up)的架构。换句话说,为了处理更多的负载,你需要换个更强大的计算机。在几年前,这意味着要想支持水平伸缩(scale-out)的架构,大家就得放弃 SQL,或者采用分区、Active-Passive 复制等技巧。在灵活、富有逻辑的数据库上实现真正的 ACID 编程模型是不太可能的。正是这种局势引发了 NewSQL 运动,NuoDB 的出现也是为了解决这个问题。

NuoDB 是针对云伸缩设计的关系型数据库。怎么理解呢?NuoDB 是一种真正的 SQL 服务:它拥有 ACID 事务的所有属性,支持标准的 SQL 语言,具备真正的关系型逻辑。而且从一开始,NuoDB 的设计就能让它以云服务伸缩的方式进行伸缩。

这里不再对“云伸缩”进行定义。如果你真的感兴趣,可以到我们的技术博客上了解什么是云伸缩,文章里有详细的定义。简单来说,就是你需要一个水平伸缩的模型,不过我觉得它还应该是敏捷、易用、可自动化、安全、高可用的。本文就是从这个观点出发的。

需要注意的是,NuoDB“只是”个软件。这意味着无论是在笔记本电脑上,还是在私有云抑或公有云上,NuoDB 都运行在Linux、Mac、Windows 或Solaris 上。你可以在Amazon Web Services 或Google Compute Engine 里使用NuoDB,或是把它和OpenStack 集成起来,也可以在笔记本电脑上作为本地Windows 服务运行。NuoDB 很灵活,你可以随便测试、开发,然后以你自己的方式部署到任意地方。

本文将介绍NuoDB 是什么,怎样的架构能让它应对现今的一些挑战,以及它能帮你解决什么问题。看完本文,你就能了解NuoDB 的关键概念和架构的不同之处了。你也能理解一些实际部署和管理的功能,对自己的NuoDB 数据库进行伸缩。

三层架构

了解NuoDB 最简单的方式就是了解它的三层架构。NuoDB 包括管理层、事务层和存储层。我们后面再介绍管理层,先看看事务层和存储层。

要想让关系型系统可伸缩,把事务和存储分割开是关键之所在。传统的SQL 数据库都会对硬盘上的数据表示(页)和内存里的B 树结构进行同步。这种紧耦合是有效的,但对IOPS(每秒I/O 操作次数)的影响非常大,因此很难水平伸缩。把这些角色分离开的架构可以水平伸缩,几乎不会影响磁盘吞吐量等数据。

NuoDB 的持久化和事务处理是完全独立的两个任务,这意味着你可以对这些层分别伸缩、分别处理故障。对事务吞吐量进行水平伸缩?不用增加磁盘就可以做到。想拥有独立的归档,防止数据中心出现故障?达到目标的同时也不会影响事务性能。这种分离不仅有利于系统的伸缩,也更利于随需伸缩、根据你的需求进行调配。

事务层负责原子性、一致性和隔离性,但并不关心持久性。这也说明事务层位于内存中,它运行速度快,任何内容都可以失败,在任何时候关闭都不会丢失数据或一致性。事务层也是个缓存层(特别是能随需缓存,我们一会儿介绍),你不需要在 NuoDB 数据库之上添加其他的缓存逻辑。

显而易见,存储层负责 ACID 中的 D(持久性)。存储层始终处于活跃状态,并和所有数据保持一致。它负责在提交的时候持久化数据,事务在缓存中命中失败的情况下访问数据。

需要注意的是,NuoDB 里的“提交”是可调节的。你可以在某种程度上牺牲性能和高可用性,因为它们处于不同的层。要理解调节提交协议的做法和原因,我需要解释一下这些层究竟是什么样的。

对等协调

这两个数据库层由多个进程组成,这些进程可以跨任意数量的主机运行。每个单独可执行的进程都以事务引擎(Transaction Engine,TE)或存储管理器(Storage Manager,SM)两种模式的其中之一运行。所有的进程都是对等的,没有单独的协调器或故障点,也没有主机特定的配置。默认情况下,所有对等的进程都会通过加密的会话互相认证和通讯。

每个 TE 都负责接受 SQL 客户端的连接,并处理查询。缓存保存在 TE 的进程空间里。SM 和 TE 通过简单的对等协调协议互相通讯。当 TE 在本地缓存命中失败的时候,它可以从任意对等进程里获取所需的对象,这通常意味着,如果有另一个 TE 的缓存里有这个对象,就去那个 TE 里取,这比 SM 从持久存储里查询数据要快多了。

这个简单、灵活的进程模型简化了启动、水平伸缩和迁移。举例来说,假设你想要一个尽可能简单的 NuoDB 数据库。你在同一台主机上启动了单独的 TE 和 SM。这时你就有了一个运行的、完全 ACID 的数据库,但它们都在同一台主机上。你可以在笔记本电脑上这样测试,但这么做就不太适用于真正的部署环境了。

接下来你可以在第二台主机上安装软件,发消息让它启动一个新的 TE。新的 TE 会和已有的进程互相验证,把一些根元素加载到自己的缓存里,然后报告说自己已经做好了准备、能处理事务负载了。从发消息到 TE 准备好开始工作,整个过程花费的时间通常都不会超过一百毫秒。在两个独立的主机上运行 TE 就可以让数据库的事务吞吐量翻一番,也能增加故障的恢复能力。

美中不足的是我们只处理了持久性的一个方面。接下来,你可以搭建第三台主机,发送消息让它启动第二个 SM。第二个 SM 会自动和运行的系统同步,准备好之后就可以积极参与数据库的处理了。至此,数据库持久性的另一个方面也就处理好了。一样很简单。

最后,让我们看看如何在不同的主机上搭建第一个 TE 和 SM。你可以猜到,联机第四台主机,在这台新主机上启动一个 TE 或者一个 SM,当它准备好之后关闭原先的 TE 或 SM(无论你在新主机上启动的是什么)。你完成的是数据库组件的实时迁移,不会损失可用性。因为整个服务没有关闭过。这也配置出一个完全冗余的数据库,因为任何主机都可能失败,但你仍然有一份完整的数据归档,并能进行事务处理。

所有的工作都完成得轻松、迅速,因为 NuoDB 建立在一个基于进程、对等的简单模型之上。此外,也因为有简单的随需缓存 Schema,以及真正被缓存和分享的数据格式。但数据格式并不是真正的 SQL 结构。我们称它为原子(Atom)。

一切都是原子

虽然 NuoDB 确实是个关系型数据库,但它的内部结构并不是。TE 的前端使用 SQL,也知道如何优化事务。但这层之下所有对象的逻辑操作我们都叫做原子(Atom)。原子本质上是自我协调的对象,表示信息的特定类型(比如数据、索引、Schema 等)。即使是内部的元数据,也存储为原子。

原子是数据块,但不应该把它们看成是关系型数据库里传统的页。在某种程度上,原子实际上是缓存和存储层之间进行网络协调时真正的对等实体。原子包含任意的数据块,我们选用原子大小来最大限度地提高通讯效率、缓存里对象的数量、跟踪变化的复杂性等等。

除了数据库内容,原子也可以用来表示目录(Catalog)。目录是 NuoDB 处理其他原子的方式,本质上是一个分布式、自引导的查找服务。当 TE 启动的时候,它需要获取一个叫做主目录(Master Catalog)的原子。这是根原子,从它出发可以找到其他所有的原子。在前面的例子里,第二个 TE 会从第一个 TE 的缓存里获取一个原子,能这么做的原因是目录会告诉 TE 哪里能找到所需的原子。正是这种简单的启动机制让新的 TE 轻松、快速地在线。

原子只是一种很好的数据组织方式。原子能大大简化内部通信和缓存,因为我们不用考虑具体的 SQL 结构。所有内容都包含在相同的通用结构里,并用一致的方式识别。

内部状态的这种视图也有利于整个数据库的一致性。因为元数据、目录数据都和数据库数据一样,存储在相同的原子结构里,所有的变化都发生在同一个事务的上下文里。所以我们要是在一个 SQL 操作的上下文里修改一些元数据或目录数据,那所有的修改要么全部发生,要么全部不发生。不用担心会有一些不一致的修改影响数据和状态的准确性。

最后,把所有的数据都看作原子能让持久性变得相当容易。因为数据库的内容只是命名对象的一个集合,我们的持久层仅仅是一个键值对的存储。从理论上来说,它可以是任何存储。在 NuoDB v1.1 里,我们支持所有的文件系统、Amazon S3 接口和 Hadoop HDFS。在以后的版本里我们会支持更多的存储系统。在一个单一的数据库里,你甚至可以混合使用多种存储机制,举例来说,你可以同时使用本地文件系统和 S3 服务存储你的数据库。

多版本并发控制

原子结构是架构里强大、简化的一部分,有助于我们进行伸缩,但要是没有处理冲突、保证一致性的方法,NuoDB 还是不能支持 ACID 语义。针对这个问题,我们使用了多版本并发控制(Multi-Version Concurrency Control,MVCC)。MVCC 和全局锁管理器、分布式事务协调器不同,它对数据进行了版本化,将整个数据库看作更新的追加集合。

MVCC 对分布式数据库进行水平伸缩的时候有很多优良的特性。首先,在数据发生变化的时候,我们实际上给数据创建了一个新的“挂起”版本(事务提交之前一直是“挂起”状态)。缓存里可以有多个“挂起”版本,以及当前的“标准”版本,所以缓存里就不会再修改内容了。这样的话,回滚就变得不那么重要了(事务不会提交,所以“挂起”的更改会被丢弃),反过来看,更新消息的处理就是乐观的了。

这些消息的处理不仅仅是乐观的,在 NuoDB 里通常还是异步的。也就是说,当一个事务试图修改数据时,事务会立即发送关联的消息(下面会详细介绍),然后再继续处理。如果在事务准备提交之前,TE 已经知道允许修改,那就不会有消息传递的开销了。否则事务会阻塞,只能等到最后再弄清楚是否允许提交。结合异步和乐观行为,以及宽松的消息批处理,NuoDB 在云环境里的预期延迟峰值较小、不可预期的网络行为也较少。

版本控制的第二个好处是,它为可见性提供了清晰的模型。在缺省模式下,NuoDB 提供快照隔离级别。换句话说,从事务开始的时刻起,就存在一致的数据视图了,你也能获取到这个一致的数据视图。我们也支持读提交隔离级别和 SQL 操作 select-for-update,但我觉得分布式数据库里真正实用的还是快照隔离级别。

在实践中,就是指某个 TE 上的一个事务能读取一些数据,那另一个 TE 上的事务就可以修改那个数据,而不会出现冲突。只要所有的内容(除了与第一个事务交互的)相对于这个对象的版本来说是一致的,那就保持了一致性。MVCC 能让系统知道所有“挂起”和“已提交”的版本,所以只需要很少的全局协调消息和冲突解决,系统就能维护一个始终一致的视图。

需要协调的是“写 - 写”冲突。对于这一点,NuoDB 挑选一些主机作为对象的 Chairman(主持人)。Chairman 只是一个新奇的名称,它实际上是在两个事务更新同一个对象的时候决定由哪个事务更新。能扮演对象 Chairman 的只能是缓存里有给定对象的 TE,所以对象如果只缓存在一个 TE 里,那所有的协调都在本地进行。关闭某个 TE,或者从它的缓存里找不到对象的时候,不需要通讯就可以挑选出下一个 Chairman。

最后,MVCC 在系统性能上也有更重要的优势。SM 不仅维护着数据库的归档内容,而且可以维护日志(推荐大家使用这个功能)。NuoBD 是一个版本化的系统,日志只以追加的方式保存一组修改信息,往往非常小。这种方式能提高记日志的效率,添加一个有日志记录的 SM 对一般事务整体的运行时也不会有太大的影响。

更新消息的发送是乐观的,不仅如此,更新也会在事务提交前写入日志。如果事务没提交,我们会进行标注,在整体处理日志的时候,未提交事务关联的更新并不会纳入归档内容的批量修改中。所以日志不仅仅是内存中的协调器(可以是乐观的),也是数据的持久化。有一个细节很重要,版本化是针对原子内的记录的,而不是原子本身。原子可以包含很多记录,也可以是粗粒度的,以便有效减少冲突。

在这篇文章的第二部分,我们会分析事务系统的实现原理、管理层的作用、所有组件的协同工作方式,以及 NuoDB 以后的规划。

作者简介

Seth Proctor是 NuoDB 公司的 CTO,在可伸缩系统的研究、设计和实现上有超过十五年的经验。这些经验来自于网络、语言、操作系统、安全、数据库和分布式环境等领域,然后凝结成了 NuoDB 产品。在 NuoDB 之前,Seth 就职于 Nokia,负责内部私有云的架构。再往前,Seth 在 Sun 公司的研究实验室工作,和产品组、大学进行合作。

Seth 拥有八项跨多个技术领域的先进专利。还有五项专利正在等待批准,这五项专利都是 NuoDB 去中心化数据库部署中提升数据库效率和最终用户灵活度相关的。你可以从 www.nuodb.com 联系到他。

查看英文原文: Exploring the Architecture of the NuoDB Database, Part 1

2013 年 9 月 06 日 00:384479
用户头像

发布了 151 篇内容, 共 53.3 次阅读, 收获喜欢 14 次。

关注

评论

发布
暂无评论
发现更多内容

满足消费者仪式感要求,木莲庄酒店做得很到位

InfoQ_967a83c6d0d7

架构师训练营第十一周作业

Hanson

薪水真的不是工作的全部

escray

学习 面试 面试现场

区块链支付系统开发方案,usdt支付跑分系统搭建

WX13823153201

区块链支付系统开发

云原生技术采用增加,全球60%后端开发人员都在使用容器

BoCloud博云

Kubernetes 容器 云原生 CaaS 博云

开源流数据公司 StreamNative 推出 Pulsar 云服务,推进企业“流优先”进程

Apache Pulsar

Apache Pulsar 消息系统 消息中间件

用户注册密码保存与校验(golang版)

2流程序员

大数据技术思想入门(五):分布式计算特点

抖码算法

Java 大数据 hadoop 分布式

升级的华为云“GaussDB”还能战否?

华为云开发者社区

MySQL 数据库 开源 Elastic Stack GaussDB

架构师训练营第十一周总结

Hanson

安全系列之——主流Hash散列算法介绍和使用

诸葛小猿

hash 散列函数 md5 sha1 murmurhash

分手快乐 祝你快乐 你可以找到更好的

escray

学习 面试 面试现场

week11 作业

Geek_196d0f

在木莲庄酒店和孩子一起体验“团队作战”的乐趣!

InfoQ_967a83c6d0d7

Apache 软件基金会顶级项目 Pulsar 达成新里程碑:全球贡献者超 300 位!

Apache Pulsar

Apache Apache Pulsar 消息系统 消息中间件

架构师训练营 第11周

大丁💸💵💴💶🚀🐟

让这家有12万名员工、1.7万种产品的钢铁厂平滑上云的黑科技是什么?

华为云开发者社区

大数据 云服务 华为云 非对称加密 KYON

年薪80万技术专家,面试通过后,被发现简历造假!合并8年前多段工作,惨遭警告和淘汰!

程序员生活志

程序员 面试 职场

原创 | 使用JPA实现DDD持久化-O/R阻抗失配(1/2)

编程道与术

Java hibernate DDD JDBC jpa

Flink状态管理-8

小知识点

大数据 flink scal

计算机网络基础(二十一)---传输层-TCP连接的四次挥手

书旅

TCP 四次挥手 TCP/IP 协议族

如何在面试中表现你所没有的能力

escray

学习 面试 面试现场

“DNAT+云链接+CDN”加速方案,助力出海企业落地生长

华为云开发者社区

CDN 网络 华为云 企业出海 网络加速

易实战Spring Boot 2 资源汇总 从入门到精通 内含实战github代码 毫无保留分享

John(易筋)

redis Spring Boot 2 RestTemplate thymeleaf HikariCP

代理,一文入魂

cxuan

Java 后端 代理

游戏夜读 | 什么才值得纪念?

game1night

oeasy教您玩转linux010105详细手册man

o

Docker商业版受限,胖容器是个选择

BoCloud博云

Docker 容器 博云 胖容器

ARTS挑战打卡的100天,我学到了这些

老胡爱分享

ARTS 打卡计划

week11 小结

Geek_196d0f

性能相关,进程调度

Linuxer

探讨NuoDB数据库的架构—1-InfoQ