Category: Database

0

Facebook是如何加速SQL查询

在PB级别的数据上进行查询是一件事,如何在Facebook这种级别的产品上使用则是另外一件事。今年早期时候,他们把Alluxio分布式文件系统集成到了他们的数据架构上,实现了存储和计算的分离,以此用来加速查询。 Facebook很早就使用Apache hadoop,并且到现在还可以在Facebook的架构中看到他。它们已经把数据存储从Hadoop clusters中移开了,但是仍然使用HDFS在Warm Storage中访问数据,这是一个由Facebook开发的定制的分布式文件系统,用来在分离Hadoop之后进行数据存储的。 Facebook内部使用了很多Presto来进行SQL查询,A/B testing以及服务一些关键的仪表,比如每日的活跃用户(DAU)或者每月的平均用户等等。作为一个没有存储模块的计算单元,Presto对计算和存储分离的架构非常友好。 为了让SQL查询的延时在一个可以工作的范围(比如在一秒左右),几年之前,Facebook实现了一个数据Caching的策略。Dubbed Raptor,这个系统要求用户在Presto cluster的SSD上创建ETL pipeline来cache数据。 Raptor加速了查询的速度,因为很多查询都再也不用通过网络了,但是同时也带来了很多别的问题。 开始的时候,把计算和存储放在一起,就限制了公司去把他们分开来扩展,这显然是不好的。它也导致了数据的碎片化,从而降低了用户的体验,这主要是因为查询有时会hit warm storage,有时会hit 本地SSD的cache。而且它也是的数据的安全和隐私保护更加复杂,因为你不仅仅要保护Warm Storage中的数据,还需要保护本地SSD的数据。 去年秋天,Facebook开发实现Raptor的替代方案。它是基于Alluxio,这个新的系统的查询性能和Raptor类似,但是不需要在SSD中cache数据。 Alluxio是一个虚拟的分布式文件系统,它连接了多个计算引擎和后端存储系统。它是由Haoyuan在UC伯克利 AMPLab开发的。Facebook基于Alluxio开发了一个新的版本,让它可以在Java上运行。 Facebook使用ORC文件格式来存储数据,并且通过HDFC接口来让Presto访问。Alluxio的实现可以在SSD上工作,并且把数据存储在本地,从而加速访问,但是本地的cache却不再需要了,而且Alluxio也可以在没有SSD的情况下使用Warm storage来加速访问。 当Alluxio在上百个Facebook数据中心的节点上安装之后,用户就可以体验到和之前Raptor类似的查询性能。它们可以使用很多Join的查询来查询PB级别的数据,没有Alluxio或者Raptor之前,这些查询可能需要超过10s才能返回。在一些能够hit oft-queried表格的查询,Alluxio可以相比Prestor负载提高了30%到50%,这显然是一个不错的提升。 根据James七月份的报告,相比于Raptor,Alluxio cache减少了57%从远端数据存储单元读取的操作。Alluxio cache的hit rate查过了90%。 Jain说,现在还有一个问题,就是当有很大的数据请求过来的时候,就很容易让cache的hit rate降低,它们现在正在想办法解决这个问题。 这个方案的另外一个优点是金钱和安全,因为Presto计算单元和数据存储是分开的,这样可以分开进行提升,而不会有浪费。在安全性方面,也不需要再担心SSD上数据的安全,而只需要关注warm storage上数据的安全即可。 当然Raptor也没有完全被取代,不过预计在未来六个月会被完全取代。

0

MySQL数据库服务介绍

MySQL团队现在把它引入到了Oracle Cloud架构上(OCI),这个服务是100%由MySQL服务开发,管理和支持的。 MySQL数据库服务和你所了解的MySQL几乎是一样的,只是说现在在云平台上支持了而已。它会自动执行很多耗时的任务,比如MySQL instance provisioning,补丁和升级,以及备份和恢复。用户可以很方便地扩展MySQL,检测云资源以及实现安全策略。用户的应用可以通过标准的MySQL protocol来访问MySQL数据库。典型的管理任务可以通过OCI web控制台,REST API, CLI或者DevOps工具进行自动化,集成操作。 MySQL数据库服务在多个OCI region中可以使用,这样可以很方便符合你所在地的政府和区域要求。当然更多的区域支持也正在实现中。 由MySQL开发团队创建 一个最大的优势就是MySQL数据库服务是由MySQL开发团队开发管理和支持的。我们来看看这为什么很重要: MySQL数据库服务是由MySQL社区和商业版同一个团队开发和维护的。 这个服务是一直最新的,包含最新的安全更新。 可以得到所有的最新的功能,包括使用最新的X-Protocol和X DevAPi实现的NoSQL Document Store。 MySQL数据库服务由MySQL专家配置的默认config。当然也支持用户来自定义化。 因为MySQL服务是在云上,你可以有最大的灵活性来使用你的部署策略。 用户可以使用MySQL本地replication和MySQL Shell来快速和方便地把workloads移到云上。 不像其他的云数据库服务,它们的服务支持都是有限的。MySQL数据库的服务支持是不需要额外花费的。 MySQL数据库服务是基于Oracle Cloud架构进行创建的,继承了所有Oracle cloud的特性,所以可以放心运行各种关键和核心的任务。 价格:只有Amazon RDS的三分之一不到 MySQL数据库服务大概是目前主流云提供商最便宜的选择了 — Amazon RDS, Microsoft...

MongoDB 4.4 最新特性介绍 0

MongoDB 4.4 最新特性介绍

MongoDB 4.4就要发布了,本文就来介绍一些这个版本的一些最新的功能。 MongoDB 4.4中改进的功能 对冲读取 MongoDB可以并行处理读请求,然后从最有效的节点来获取结果,从而可以减少应用的延时。 可定义的共享秘钥 在scale过程中修改数据分布的时候会在共享秘钥中加入后缀。 镜像读取 这个功能可以对副本的cache预先warm,从而可以减少计划的维护或者outage的时候主选举消耗。 聚合增强 聚合增强有了很多方面的改进,包括定义和汇总聚合表达式,从不同的mongo collection中组合数据到一个结果中,字符串处理以及数组处理的新操作。下面是一些加强: $out $out现在可以把输出collection的结果到不同的数据库,而早期的版本只能输出到同一个数据库中。 $indexStats $indexStats在新的版本中有了一些新的域,包括下面这些: Building 这是一个Boolean的flag,用来表示正在建立的索引 Spec 每一个索引的规格文档 Shard 分片的名字 $merge $merge可以在要升级的同一个collection中输出。另外,可以在一个collection中数据并显示在pipeline上,比如$lookup。 $planCacheStates的改变 $planCacheStates现在可以同时在mongod和mongos instance上运行。另外,$planCacheStats在运行的时候有一个新的域我们称之为host域。PlanCache.list()是$planCacheStats聚合阶段的包装。 $collStats改变 $collStats在扩充文档中已经可以接收查询统计信息。另外Collection扫描有下面这些域: 域名字 描述 nonTailble 一个64位整数,用来表示多个查询上的一个collection...

0

关系型数据库进阶之Log Manager

我们在之前的文章中聊到,数据库为了提高它的性能,会把数据存在memory buffer中。但是这里有一个问题,就是假如一个已经committed的transaction crash掉了,你因为这个crash丢掉了memory中的数据,那就会出现了Durability的问题。当然你也可以把所有的数据都写到磁盘中,但是同样的问题,假如写到一半就crash了,这里就会发生原子性的问题。 所以这里的我们的原则是任何通过transaction进行写的修改都要么是全部完成要么就是什么都不做。 为了解决这个问题,有两个方法: Shadow copies/pages: 每一个transaction都创建它自己的数据库(或者部分数据库)备份,然后在这个备份上进行操作。假如有错误,这个备份就移除掉。假如成功了,就切换到这个备份上,而把旧的备份删除掉。 Transaction log:transaction log是一个存储空间。在把数据写到磁盘之前,数据库把相关的信息写到transaction info中,因此即使有crash或者cancel的时候,数据库也知道怎么来完成或者移除响应的没有完成的transaction。 WAL Shadow copies/pages的思想其实很好,唯一的问题就是在大的数据库中,会额外浪费很多磁盘的空间。这也是为什么现在主流的数据库都是用transaction log来解决这个问题。Transaction log必须存储在一个稳定的存储空间中。 大多数数据库(至少Oracle, SQL Server,DB2, PostgreSQL, MySQL以及SQLite)都使用Write-Ahead Logging protocol (WAL)来处理transaction log。这个protocol主要有三个规则: 每一个对数据库的修改都产生一个log记录,并且log记录必须在数据写到磁盘前写到transaction log中。 log记录必须按照顺序写,也就是说发生在记录A先发生,那么记录A就必须先写。 当一个transaction committed了,这个commit的顺序必须在transaction介绍前写到transaction log中 这些工作都是在log manager中处理的,他位于cache...

0

关系型数据库进阶之Transaction manager

在前面的文章中,我们介绍了查询管理,查询优化以及数据管理,本文就来继续介绍Transaction manager相关的内容。它主要是用来保证每一个query都在它自己的transaction中执行。不过在此之前,我们需要理解一下ACID transaction。 ACID ACID transaction是一个工作单元,它主要包含4个方面: 原子性:transaction是“要么完成所有,要么什么也不做”,哪怕这个操作需要10个小时来执行。假如transaction crash,那么所有的state都需要roll back到之前的状态。 隔离性:假如有两个transactionA和B一起执行,不管A是在transactionB之前还是中间还是之后完成,结果都是一样。 耐用性:当transaction committed(成功完成),不管发生什么数据都会保存到数据库。 一致性:只有有效的数据才会写到数据库,一致性是和原子性以及隔离性相关。 在同一个transaction中,你可以运行多个SQL query来读,创建,更新和删除数据。但是当她们使用同样的数据的时候,就会造成混乱。我们来看下面这个例子: Transaction 1 从account A中取出100块钱,并存到account B中 Transaction 1 从account A中取出50块钱,并存到account B中。 我们来从这个例子中看看ACID中各个属性: 原子性:不管发生什么,你都不能从account A中取出100块钱,而不存到account B中去。 隔离性:需要确保假如T1, T2同时发生,最终account A被取出150块并且account B收入150块。而不会发生别的,比如account B只收入50块之类的。...

0

关系型数据库进阶之数据管理

我们在前面已经介绍了客户端管理,查询管理,今天来介绍数据管理。 在这一步中,查询管理会执行相应的查询,这个时候就需要从表和index中得到数据了。它需要数据管理来获取数据,不过这里有两个问题: 关系型数据库使用的是transaction的模式,所以你不能够在任何时候都得到数据,因为同时可能有别人在使用或者修改数据。 数据的获取是数据库中所有操作最慢的操作,所以数据管理需要足够聪明,来把数据保存在内存buffer中。 本文我们就会来讨论关系型数据库是如何处理这两个问题的。 Cache管理 就像我们前面几篇文章提到的一样,数据库的瓶颈就在于磁盘I/O,所以为了改进性能,需要使用cache管理器。 Query的执行器并不是从文件系统直接获取数据,而是通过cache manager来请求数据。Cache manager有一个memory的cache,我们称之为buffer pool。显然动态地从cache请求数据会增加数据获取的速度。一般来说memory相比磁盘来说会快100到100K倍,当然这还取决于决定的硬件和读写方式。 但是这里就会有另外一个问题,就是cache manager需要在query执行之前就获取到相应的数据,否则就还需要访问磁盘来数据。 预获取 query执行器其实是知道它所需要的数据,因为它知道整个query的所有流程。基于此,我们可以让query执行器处理第一部分数据的时候,就要去cache manager去预加载第二部分的数据,然后当它处理第二部分的数据的时候,就让cache manager去预加载第三部分的数据,这样循环下去。 Cache manager会把所有的数据保存在它的buffer pool中,为了检查相关数据是否还需要,cache manager在所有的cache数据中加入了一个额外的信息(我们称之为latch)。 当然有时候query执行器也不知道它下面要什么数据,这个时候就会使用一些特殊的预加载(比如,query执行器要数据1,3,5,那么它很有可能在未来需要数据7,9,11)或者顺序获取(这种情况下,cache manager就继续加载磁盘中后面的数据)。 为了探测预获取的效率,数据库提供一个称之为buffer/cache hit ratio的指标,这个指标会显示当请求一个数据的时候,有多少次是可以直接在cache中获取而不需要访问磁盘。 但是另外一个问题就是memory的大小毕竟有效,所以假如要加载新的数据,那么就得去除一些旧的数据,而这些加载和去除都是需要磁盘以及网络I/O消耗的。假如有一个查询经常执行,那么我们就会频繁地加载和去除相关的数据,这显然是不太合理的,那该如何处理呢?现代的数据库使用一种称之为buffer替换的策略。 buffer替换策略 现代的数据库(至少SQL Server, MySQL, Oracle和DB2)基本都使用LRU算法。 LRU就是Least Recently...

0

关系型数据库进阶之查询优化二

在前面的文章中我们介绍了查询优化的基础,着重介绍的两个表的JOIN的优化。本文就来看看我们在实际中更常见到的多表JOIN的优化。 现在我们来假设有五个表进行join,我们需要从不同的表中得到一个人的不同信息,比如地址,mail,mobiles等等,简单的QUERY如下所示: 作为查询优化器需要找到最佳的查询数据的方法,这里有两个问题: 每一个join需要使用什么类型的JOIN?我们有三种可能的JOIN (Hash Join,merge  Join, Nested Join) 先做哪个JOIN再做哪个JOIN? 下面这个是一个简单的示意图,有四个表,三个JOIN的情况,显然五个表的情况会更加复杂。 好的,那我们该怎么做呢? 1)暴力解法 遍历所有的可能性,然后找到最佳的方法。在上面的例子中,每一种join有三个可能(HASH, MERGE, NESTED),对于给定顺序的JOIN就有3^4中可能,而JOIN的顺序也是不定的,四个JOIN其实有(2*4)!/(4+1)!种可能的排序,这样一来,这个五个表的JOIN有 3^4*(2*4)!/(4+1)!种可能。 也就意味着,有27216中可能的计划。假如说merge join有0,1,2 B+ tree index,那么这种可能性就变成210000种了。而这还只是一个简单的JOIN。 2)只试验一些计划,然后选择其中最好的 因为可能性太多了,那么我们随机选择其中一些,然后计算他们的cost,选择其中最好的。 3)应用一些规则,来减少可能的计划 这里通常有两种规则: 使用一些简单的逻辑规则去除一些没有用的可能性,只是说这种去除不是很多。比如“nested loop join的inner relation必须是最小的数据集“ 使用一些有侵略性的规则来减少可能性。比如“假如一个relation很小,那么使用nested loop而不使用merge join和hash join”...

0

关系型数据库进阶之查询优化

在前面几篇文章中,我们已经介绍了总体构架,客户端管理和查询管理。在查询管理中,有一个很重要的部分我们没有介绍,那就是查询优化,这也是本文所要介绍的内容。 所有的现代数据库都是基于cost进行优化的(Cost Based Optimization, CBO)。总体的思想就是看每一个操作的cost是多少,然后找出一个cost最小的路径来执行这些操作并获取结果。 本文会首先以最常的三种join为例来进行介绍,看看哪怕是简单的join,它背后的优化是如何进行工作的。在这些例子中,我们关注时间复杂度,这个其实和真实的数据库优化器的计算是有所不同的,它真实会关注CPU消耗,磁盘I/O消耗以及内存的需求。时间复杂度和CPU消耗其实是差不多的,我们这种懒人就直接使用时间复杂度来进行分析了。当然有时候我们还需要考虑磁盘的I/O消耗,因为很多时候真正的瓶颈就是在于磁盘I/O而不是CPU的使用率。 JOIN的操作 我们会来看三个最常见的join操作,merger Join, Hash Join以及Nested Loop Join。在正式开始之前,我们来引入两个名词,outer relation和inner relation,很简单outer relation就是join左边的数据集,inner relation就是join右边的数据集。比如A JOIN B, 我们把A称之为outer relation而B称之为inner relation。并且假设outer relation有N个元素,inner relation有M个元素。我们可以很容易知道A JOIN B和B JOIN A其实是不太相同的。 Nested loop join Nested loop join是最简单的一种情况...

0

关系型数据库进阶之查询管理

在前面几篇文章中,我们已经介绍了总体架构以及客户端管理,今天我们来继续介绍查询管理。 毫无疑问,查询管理是数据库的核心中的核心,也是最重要最难的地方。这个部分,哪怕是写的不好的query也会被转换成尽量快的方式来进行执行,在执行之后会把结果在返回给客户端管理。主要有一下几个步骤: 解析query,看是否有效 重写相应的query,去除一些没有必要的操作,主要是做预优化 优化相应的查询,主要是提高性能,转化成高效的执行计划和数据访问计划 编译计划 最后,执行计划 我们主要来讨论一下前三个部分,因为他们基本就是query manager最核心的地方了。 query解析 所有的SQL语句都会发送到解析器来进行语法的检查。query语句中的任何语法错误都会导致query的结束,比如你把SELECT写成了SLECT,那么语句就会在这里的检查结束并报错。当然也不是仅仅这些简单的检查,还包括一些复杂的,比如你把WHERE写到了SELECT之前,那么这里也会报错。 紧接着会检查相关metadata,包括: 相应的表是否存在 相应的域是否在表中存在 对应的操作在对应的列数据类型上是否有效(比如你不可以把一个整数和字符串相比较,或者你不能在整数上执行substring()操作等) 做完这些检查后,它会检查你是否有相应的表格的读写权限。 假如这些检查都ok,那么相应的SQL query会被转换成内部的表示形式(通常是一个tree),然后会被送到query rewriter中。 Query重写 在Query解析之后,会把相应的内部表示形式传到Query重写这里,那么这里需要的操作就是: 预优化query 避免不必要的操作 帮助优化器找到最佳的方案 Query的重写其实就是把一系列预定义的规则在这个query上运行,假如这个query符合相应的规则,那么就根据这个规则进行重写。下面是一些可选规则: View的合并:假如你在query中使用view,那么就会把view的代码合并到相应的SQL语句中 子查询的展平:有子查询之后,是非常难进行优化的,所以这里会尽量把子查询展平了用来取代相应的子查询。举例如下: 这个语句会被转换成下面这个语句: 去除不必要的操作:比如你使用了DISTINCE,但是你又有一个UNIQUE的限制来保证数据不会重复,那么DISTINCT的关键词就会被去除。 消除冗余连接:比如你有两个一样的join条件,只是有一个条件被隐藏在一个view中或者别的不容易注意的地方,那么这个同样的join条件其实就是冗余的,这里会去除掉。 常数的算术评估:假如你写了一些需要计算的公式,那么它就会在这一步中计算。比如WHERE AGE > 10...

0

关系型数据库进阶之客户端管理

在上一篇文章中我们介绍了数据库的总体架构,今天我们将和大家来一起分析一下其核心组件中的重要组成部分:客户端管理。 客户端管理,顾名思义它是用来处理和客户端之间的信息交互的。客户端可以是一个web的server或者一个终端的用户/应用。客户端可以通过各种不同的方式来访问数据库,比如JDBC, ODBC, OLE-DB等等。 当连接数据库的时候,会执行下面这些步骤: 客户端管理首先检查你的权限和认证,看你是否有相应的访问数据库的权限。这些权限都是通过DBA来设置的。 然后,它会检查看是否有可用的进程(或者线程)来管理你的query 再检查看相应的数据库是否处于很重的负载情况下。 得到相应的资源,这里会有一个timeout,假如一定时间还没有得到资源,则会timeout,并且关闭相应的连接以及返回一个可读的错误信息。 发送query到相应的query manager,你的query就被执行了 Query 的过程并不是说全部返回,可能是一部分一部分返回的,所以它会把部分的返回值保存在一个buffer中,并且开始把它们分步发送回客户端。 假如有什么问题,它会断开连接,然后给出一个清晰的错误解释,并释放相关的资源 这就是整个数据库的客户端管理流程,其实还是蛮简单的,下一篇我们将会具体介绍更为核心的Query Manager部分。 参考文章:http://coding-geek.com/how-databases-work/