多核处理器下数据库系统日志管理器优化技术探讨

摘要

传统数据库的设计假设磁盘为主要存储设备,其性能取决于基于I/O代价模型的优化。然而,当前数据库运行的平台已逐渐转移到由多核处理器、大内存和以闪存为代表的低延迟存储所构成的新型硬件平台上。在大多数情况下,工作数据集能够全部加载到内存或者闪存等高速存储器中。这样,数据库的性能瓶颈由传统的I/O转移到了CPU上。而传统数据库的加锁操作、闩锁竞争、日志管理以及缓冲区管理在设计时均未考虑到多核处理器的使用,因而成为了限制CPU利用率的明显瓶颈。改变传统数据库的优化重点以适应硬件的发展对应用而言是十分必要的。本文针对当前新的应用背景,主要围绕数据库中日志管理器、在多核平台下已有的优化技术进行详细介绍和归纳总结。

背景

摩尔定律揭示了集成电路上晶体管集成度的增长规律,摩尔定律首先表现为CPU主频的持续增长,然后又表现为CPU核心数量的持续增长。CPU的频率持续逐年增长,加上其指令执行的并行度也在增加,使得单线程的工作性能不断提高。早在2002年,CPU的频率就已经达到3GHZ。然而,高频率的CPU带来的是更多的能耗,现实应用中不一定会带来高的性价比,因而阻止CPU主频的进一步发展。这个问题使得近年来CPU的发展方向产生了转变。为了进一步优化CPU的性能,生产商倾向于在单个CPU上增加更多的处理核心。CPU开始转向使用并行多线程和片上多处理器技术,以替代单处理流的高度复杂CPU技术。生产商不再竞争速度而是转向提高并行度。按照最近多核的发展趋势,单个CPU上的核数基本每两年翻一倍。大部分研究人员预测,CPU的核数会继续增长一段时间。为了更好地利用新CPU的并行处理能力,工程师需要修改或重新设计软件系统。而基础软件,包括操作系统、web服务器和数据库等,则最先遇到复杂的多核架构带来的扩展性问题。

从一开始,数据库存储引擎的研究就是定位在高负载下的高性能和可靠性。一方面,数据的可靠性和一致性大都通过在共享数据结构上的封锁机制实现;另一方面,在现代多核架构下,性能的提升必须通过利用更高程度的并行性。如何解决这两者之间的矛盾是一个很大的挑战。现实中,关系数据库系统大部分是基于优化I/O和面向单处理器的陈旧设计思想,并不适合多核处理器的架构。

以事务处理为主的数据库系统多数依赖并发取得高吞吐率。并发是通过多线程或者多进程实现的。理想情况下,随着硬件上下文的增加他们应该具备良好的扩展性,特别是针对以读为主工作负载。实际上,为了维护一致性和持久性,数据库系统大量使用共享数据结构和同步原语。在高度并行的环境下,对共享数据进行频繁的原子更新不得不由线程串行地执行。因此,用于保护共享数据结构的同步原语会导致很大的同步开销。这些同步原语大量存在于共享内存缓冲区、锁表、索引与日志管理器中。此外,丰富的硬件上下文使得并行线程竞争硬件资源,例如,高速缓存的争用将降低缓存命中率从而增加内存访问延迟。另外,传统的封锁方式例如阻塞和忙等待策略在多核环境下效率低下。增加的并行度还会导致更大异构的工作负载,这给索引数据结构里的读写同步控制原语也造成更多的压力。总之,所有这些原因导致了运行在多核架构上的数据库系统的性能瓶颈。近年来,学者们提出许多不同的思想和方法,用于重新构建多核环境下的数据库系统。

本文主要对数据库的日志管理器的多核优化技术做整理归纳。

日志管理器优化技术

日志管理器是数据库系统的一个重要部件。几乎所有的数据库系统都使用集中式的预先写日志策略避免在系统崩溃的时候带来的数据的损坏和丢失已提交工作,以保证事务的持久性。由于其集中式的设计和对I/O的依赖使得它很容易成为性能瓶颈。较长的日志刷新时间、由日志带来的锁竞争、日志缓冲区上的竞争都会影响系统的扩展性。日志操作给系统带来的延迟主要是四类:1) 系统必须保证事务提交之前日志必须写到非易失性存储介质;因为磁盘的访问时间是毫秒级别的,日志刷盘通常为事务中执行时间最长的部分;此外,当很多小的I/O请求使得记录日志的设备例如SSD上达到饱和状态时,写日志的延迟为串行执行时间;2)在写日志的过程中,事务一直持有写锁,直到I/O结束;在很多工作负载中,这都会造成瓶颈,特别是锁竞争激烈的场景;3)日志刷盘除了I/O延迟以外还有其他开销;在等待I/O完成的过程中,事务不能继续执行,代理线程必须被挂起,直到I/O完成;与I/O延迟不同,上下文切换和调度决策会消耗CPU时间,不能重叠执行其它任务;多核硬件环境下同时运行的线程很多,这使得操作系统调度器会负载过重;4)除了锁的竞争和上下文切换的开销,许多线程同时想要执行日志插入操作;集中式的日志缓冲区有明显的临界区,其上的竞争显然也会影响系统的扩展性。

为了提高日志管理器的扩展性,必须设法提高日志的I/O效率,并且减少日志临界区的数量和缩短关键路径的长度。

成组提交技术通过将许多小的日志刷盘的请求组合到单个I/O操作减缓磁盘的压力,减少I/O等待时间。成组提交技术能够减少磁盘访问次数和增大写入的磁盘块,进而减少磁头转动获得更好的响应时间。但是成组提交技术不能消除不必要的上下文切换开销,因为过多的事务会阻塞来自日志管理器的挂起通知。异步提交技术结合了成组提交技术的优点将许多日志刷盘的请求组合到一起,并且允许事务结束而不用等待刷新日志操作完成。这个优化将日志刷盘操作从关键路径上完全移除,但是牺牲了事务持久性这个特性,也就是说,已提交工作有可能由于系统崩溃而丢失。

有研究人员针对多核平台优化了的写日志操作。他们重新审视了提前锁释放技术(Early Lock Release,ELR),并在四个不同延迟的非易失性设备上测试了ELR的有效性。ELR技术是指事务在commit记录到达磁盘之前可以释放锁,减少持有锁的时间。在ELR技术下,只有提交事务需要等待I/O结束。不存在其它事务需要等待提交事务的锁而与提交事务一起等待I/O结束。实验结果表明在越慢的设备上,ELR获得收益越好。即使是在像SSD上的快速磁盘设备,ELR也可以获得比较好的收益(短事务的执行时间比I/O要短得多)。另外,数据的偏斜程度也对ELR造成影响。如果数据偏斜度小,对锁的竞争不激烈,ELR减缓锁的竞争效果不大。如果数据的偏斜度大,锁的竞争很激烈,即使在没有等待日志刷盘的情况下, ELR效果也不好。按照80%的访问都是集中在20%的数据上的原则,对应数据的偏斜度为0.85左右,这时候锁的竞争程度刚好是ELR的优化点。针对多核平台上过多的调度而导致的系统瓶颈和上下文切换带来的开销,流水线方式写日志是一种新的记录日志的方法。流水线刷新日志类似异步提交方式不用在等待I/O的时候将线程挂起,从而不会有上下文切换的开销。但是不同于异步提交方式,流水线刷新不将结果返回给客户端,而是转而执行其它事务。守护进程在完成日志刷盘动作以后,通知代理线程/进程返回继续执行后续事务。实验表明,流水线刷新和ELR组合的效果能够达到异步提交的性能,而且在系统崩溃的时候具有可恢复性。

为减缓多核情况下日志缓冲区上的竞争,技术人员设计了三种新的日志缓冲区管理方法。传统的写日志缓冲区需要以下三个步骤:1)首先获取写日志缓冲区上的排他锁。如果当时正好有其它的服务子线程在写日志缓冲区,则此子线程必须等待直到获得写日志缓冲区上的写锁; 2)线程将日志记录复制到相应的日志缓冲区 3)释放缓冲区上的锁。由于它的简单性,这种方法具有吸引力。这个方法的缺点是:即使是缓冲区从来不会重叠的情况下,填充日志缓冲区的操作也是串行化执行。图1(B)展示了由于单一的长日志记录会给后续的线程造成比较大的延迟。日志记录由一个头部加上任意长度的值组成。日志记录结构体空间的申请是可复合的,也就是两个连续的日志记录的缓冲区申请也可以由一个头部加上任意长度的属性值组成。可以利用这种空间的可复合性将线程对日志缓冲区的填充按组进行。每一个组都有一个组织者。

一个组只有组织者才要竞争缓冲区上的锁,且一个组只有最后离开的线程需要等待锁的释放。组织者在等待互斥变量的时候,后面到来的请求可以“回退”到一个数组将他们的请求组合到一起。如图1(C)所示,组内日志缓冲区的填充可以并行执行,但组之间仍然串行执行。由于日志缓冲的填充不具有串行特征,只要满足以LSN的顺序将日志写回即可。因此,线程申请的锁可以在获得缓冲区以后马上释放。因此将缓冲区填充与锁的持有解耦合。缓冲区的填充可以按流水线的方式进行:下一个缓冲区的填充可以立刻开始,只要线程获得日志缓冲区空间。如图1(D)所示,将锁的持有与缓冲区的填充解耦合可以消除长日志记录对缓冲区填充的影响。前面讨论的两种方法具有互补性,因此将两种方法组合 一起日志缓冲区上的竞争限制在某一个常数下,同时也消除日志记录的大小对刷新日志的影响。

<small>图1. 日志记录写入日志缓冲区算法图示<big>

总结

优化日志管理器可以显著提升数据库系统的性能。有相应的实验表明,经过以上优化,数据库系统的性能可以提升10%-30%左右。

值得一提的是随着像固态硬盘的新闪存产品开始进入主流的计算机市场,闪存技术被认为是磁盘技术的替代。最近也有相关研究利用闪存技术提高数据库系统性能。固态硬盘可以显著提高事务写日志的性能。他们的做法主要关注以下四点1)突破带宽限制,利用多闪存设备,并行化I/O提高刷新日志操作性能;2)解决由于设备擦除操作而引起的不同的写延迟;3)高效的系统恢复处理;4)将闪存设备与磁盘设备结合起来获得更好的日志操作和系统恢复性能。

文章来自:腾讯架构师

原创声明,本文系作者授权云+社区-专栏发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

编辑于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏张善友的专栏

为首次部署MongoDB做好准备:容量计划和监控

如果你已经完成了自己新的MongoDB应用程序的开发,并且现在正准备将它部署进产品中,那么你和你的运营团队需要讨论一些关键的问题: 最佳部署实践是什么? 为了...

2368
来自专栏张戈的专栏

Linux下用dd命令测试硬盘的读写速度

这也是一个老方法了,只是今天用到了,就过来记录下。总觉得公司服务器磁盘不给力,有时候 vim 编辑的时候都会卡顿,IO 经常 90%+,很纳闷,就测试了一下磁盘...

3653
来自专栏非著名程序员

可能是 Android 平台上最快的图片压缩框架

这款图片压缩框架,是 ghnor 作者在 Luban 的算法策略上,丰富了外围的 api,提供更多的可配参数,多线程压缩和不同细粒度的任务控制。 它不仅可以同步...

19610
来自专栏葡萄城控件技术团队

.NET 新标准介绍

本文介绍如何使用 .NET 标准,更容易地实现向 .NET Core 迁移。文中会讨论计划包含的 APIs,跨构架兼容性如何工作以及这对 .NET Core 意...

1778
来自专栏Golang语言社区

系统架构之一(RPG游戏常用架构)

RPG游戏经典的系统架构设计 : ? bigword 游戏引擎就是使用这种架构,我认识的很多rpg游戏公司的同事也大致采用了这种架构方式。 loginapp :...

3596
来自专栏北京马哥教育

自动化代码发布系统实现

日常运维问题 在我日常运维工作中,代码发布可能是最普遍的一项工作之一,尤其是网页代码的更新,碎片化发布需求非常频繁。在前期开发人员比较少时,还可以由自己 来上服...

4708
来自专栏CSDN技术头条

微软发布新的Visual C++代码优化器

微软在5月4日发布了新的高级代码优化器,服务于Visual C++的后端编译器。提高了代码性能,可以压缩代码体积,将编译器带入了一个新的境界。 Visual C...

1916
来自专栏Bug生活2048

.net core 3.0就要来了

在前几天的微软 Build 2018 开发者大会上,.NET 团队发布了 .NET Core 的下一个主要版本 3.0 的规划蓝图。.Net Core 3 的首...

712
来自专栏程序你好

.NET Core 3和对Windows桌面应用程序的支持

在今天的微软Build Live大会上,微软.Net Core团队公开了.net Core3的开发计划的预览。.Net Core 3 的亮点是支持Windows...

1144
来自专栏SDNLAB

SDN实战团分享(三十一):Nutanix超融合之架构设计

超融合平台 针对于超融合的概念有着不同的理解,因为组件不同(虚拟化、网络等)而理解不同。然而,核心的概念如下:天然地将两个或多个组件组合到一个独立的单元 中。在...

3277

扫码关注云+社区