Postgres MVCC中的OLAP、OLTP、ZEAP和权衡

2020-10-08 11:53:00

Postgres世界目前最激动人心的发展之一是新的ZEAP存储引擎1的工作。最近,Postgres会议上的一些会议帮助明确了它和它旨在进行的优化。ZEAP有望在Postgres的运营方面取得重大进步,即使可能会有影响数据库某些用途的权衡。

您将不得不原谅在这里转弯抹角地谈论ZEAP,但我认为从更广泛的数据库上下文以及我们使用它们的目的来看待它会很有趣。

您可能听说过数据库管理员或热心关注OLAP和OLTP。对于外行来说,它们是冗长的术语,但就像许多过度使用的缩写一样,它们代表了相对简单的概念,并且作为两个重要概念的明确名称很有用:

OLAP是“在线分析处理”,指的是更复杂、更持久的分析查询的工作负载,旨在从数据集中收集洞察力,就像您在普通数据仓库中看到的那样。

OLTP是“在线事务处理”,指的是负责实时处理来自用户的大量短期事务的数据库。想一想您典型的生产应用程序。

FoundationDB将事务限制在5秒内,并且仅支持键/值存储。这实际上使OLAP变得不可能,并且专门针对OLTP。

RedShift能够将海量数据处理成有用的答案,但是对它的查询速度非常慢(大约几秒钟或更长时间),这使得它对OLAP有利,但对需要更快响应的OLTP不利。

MongoDB鼓励面向文档的存储(有意义的数据没有标准化),并使用自己开发的查询语言,其表现力只有SQL的一小部分。这使得它不适合于OLAP(并且只不太适合OLTP)。

一些传统的RDMS,如Postgres,并不是很专业,而且OLAP和OLTP都做得很好。用户可以用SQL编写极其复杂的OLAP查询(涉及连接、聚合、CTE等)。插入、更新、删除和简单的(索引良好的)选择一直都很快,通常只需几毫秒就能完成,这对于OLTP来说也是很棒的。

Postgres最严重和最长期的运营弱点之一就是臃肿。在其MVCC(多版本并发控制)模型中,已删除行和更新行的旧版本都与堆中的当前行一起保存,堆是存储表内容的物理存储。死行最终是由Vacuum收获的,但只有在任何正在运行的事务不再需要它们之后(不管时间有多长),并且Vacuum有机会运行之后(我之前已经在这里详细介绍了它的内部工作原理)。

这是一个优雅的实现-很容易推理,并且使需要它们的事务可以很容易地访问所有行版本,但它也有缺点。当旧事务迫使许多旧版本保留时,关系可能会变得“膨胀”,从而导致表的大小大大增加。膨胀的表使用速度较慢,因为事务需要遍历死行以检查它们是否可见。在所有可能看到这些行完成的事务完成之前,不能清除这些行。

我们可以说Postgres以牺牲OLTP为代价对OLAP进行了优化(即使这从来不是一个有意识的决定)。长期事务可以方便地访问同时的行版本,但是相同的功能会降低当前短期事务的性能。

ZEAP是一个新的存储引擎,它重新思考了Postgres中的MVCC是如何工作的。在ZEAAP中,行通常被原地更新,旧版本被新版本替换。旧版本不再停留在堆中,而是移动到当前页面中的“撤销日志”中,该日志充当历史记录。这个想法的灵感来自于其他已经使用类似技术的数据库,比如Oracle。

如果事务中止,将应用撤消日志中的旧版本,直到达到正确版本。类似地,需要旧版本的旧事务遵循撤销日志,直到找到正确的版本。与当前的堆一样,旧版本只需在需要时保留,并在旧事务结束时回收其空间。

从本质上讲,哲雅普改变了波斯格雷斯的MVCC中的权衡。“旧”堆通过访问工作量大致相同的新旧版本行,使所有事务处于平等的地位。ZEAP将旧版本移出了带外,使得当前版本很容易通过新事务访问,但旧版本通过旧版本访问成本更高。它以牺牲OLAP为代价对OLTP进行了更多的优化,这对运行Postgres的生产应用程序来说是个好消息。

目前的ZEAP实现计划包括引入“可插拔存储”,它允许在表级粒度(CREATETABLE MY_TABLE(...))选择存储引擎(CREATETABLE MY_TABLE(...)。使用zheap)2.一个很大的原因是,ZEAP太复杂了,不能批量引入,需要轻松地引入系统,但它也会给用户一些对他们想要进行的替换的控制。

最后,我还应该指出,虽然ZEAP对于解决臃肿问题非常有用,但它也会帮助解决Postgres的其他操作问题。索引中的“写入放大”(由Uber普及)变得不那么严重了,因为元组是就地更新的。仅当索引覆盖的列中有更改时才需要更新索引(以前,所有索引在每次更改之前都需要更新)。甚至有人说,哲普可能会消除对真空的需求,因为它可以懒惰地回收撤消日志中的插槽。有关更完整的细节,请参阅最近关于新引擎的一次演讲中的幻灯片。

1Zeeap仍在非常活跃的开发中,还没有计划在即将发布的Postgres中发布。