暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

从LINUS对DIO的狠话谈起

白鳝的洞穴 2022-07-06
889



数据库系统是不是能够从DIRECT IO上受益的争论实际上已经持续了二十多年了,不过现在还有一些人认为DIRECT IO对数据库系统不一定有效。今天就遇到一位这样的朋友和我讨论这个问题,用来佐证他的观点来自于一位大佬-Linus Torvalds 。
上面这段来自2002年Linus的对DIO的狠话,甚至被写入了那个时代LINUX针对open 的MAN page里了。如果有人手头还有2.4.X的LINUX,可以试一下man 2 open,看看是不是能在bugs一节中找到这句著名的狠话。
在当时Linus看来,数据库的IO应该完全交给Linux,而不应该自己去写什么绕过OS缓冲的IO访问。他认为Linux的FILE CACHE可以十分完美的解决数据库读写IO的性能问题。Linus说这句话的底气来自于Linux成功的为WEB应用解决了IO性能问题,通过预读、文件缓冲机制上不断的优化,成功的降低了Linux的物理IO数量,从而让不那么好的底层存储硬件不再成为阻碍WEB应用大规模并发访问的绊脚石。
不过Linus的狠话并没有让Oracle等数据库厂商放弃DIO,在Solaris、Aix等系统上,DIO已经在高负载场景下发挥了巨大的作用,只要不断的优化磁盘存储层与DB CACHE之间的算法,DIO肯定会表现出更高的效率。虽然如此,这种争论一直在持续着,而且每次争论的时候都会把2002年Linus的这段话拿出来作为圣言。很多测试用例也无不证明着Linus的话的正确性,不使用DIO之后,很多场景下表现出更高的QPS。
Linus当初的想法十分朴素,Linux在IO方面做了大量的优化设计,无论是预读、文件缓冲、脏块回写策略,都提供了强大的能力,通过不同的调校,可以适用于各种不同IO负载的场景。而如果使用DIO,那么应用需要直接和设备进行交互,要通过MMAP从设备拷贝数据到应用程序自己的BUFFER中,而对于BUFFER也需要严格的设计边界对齐,每次拷贝的数量必须以BLOCK为单位,无法以字节为单位读写数据。并且DIO如果不结合异步IO来使用,其效率肯定大打折扣。因此Linus认为数据库厂商使用DIO来绕过Linux为他们的应用负载优化的IO算法是一群傻猴子一样毫无逻辑。
事实上然和需求都来自于应用场景本身,数据库通过一套自己的DB BUFFER来减少SQL访问数据时的物理IO,通过不断优化DB BUFFER,提高DB BUFFER中的数据块的引用率来提高数据库的性能,这是数据库的核心功能之一,是肯定会花大力气来做的。而直接与设备直接按采用DIO访问,虽然平均每个IO可能比Linux的BUFFER IO要略低,不过每次物理IO的延时都是相对稳定的。如果数据库使用了DB CACHE和FILE CACHE的DOUBLE BUFFER机制,那么一次物理IO很可能来自于物理IO,也可能来自于FILE CACHE,两次IO的延时差异很大。
在DOUBLE BUFFER的情况下,数据库访问IO的延时对于数据库来说是不确定的,数据库访问的快慢是无法真实掌控的,相当于数据库把命交给了操作系统。这种情况就导致了SQL执行效率的不稳定,同一条SQL,可能在多次执行中,采用相同的执行计划,访问相同的数据,而执行时间差异较大。这种情况在大负载,高并发环境下很容易重现。哪怕使用FILE CACHE比使用DIO获得了更大的QPS,不过如果你观察每次执行的时间,会发现差异远高于DIO。因为PG数据库的数据文件访问是不使用DIO的,因此在PG中很容易出现这样的情况,有些国产数据库选型测试中,甚至有人针对多次执行的时间计算方差和标准差,作为测试的评分标准,从而打击不使用DIO的数据库产品。能想到这样的测试用例的人,肯定对DIO的研究是很深的。
而DOUBLE BUFFER另外的一个不利因素是数据库需要权衡DB CACHE和FILE BUFFER所使用的内存,无法把所有的内存都用于DB CACHE,从而可控的提升DB CACHE的访问效率,减少因为CACHE替换带来的开销。大多数不使用DIO的数据库产品,在加大DB CACHE之后获得的性能提升十分不明显,也正是因为这个原因。
实际上,针对DOUBLE BUFFER的优缺点网上的争论也很多,针对不同的应用场景,测试出来的效果也相去甚远。这是因为数据库应用极其复杂,在某些场景下,数据库厂家很好的处理了了IO,使用DIO效果更好,有些场景下,DIO的效果反而没有LINUX自身的IO效率高。主要是因为采用DIO采用的是一种稳定的“慢”,单次IO的平均延时大多数情况下不如linux的缓冲IO,但是很稳定。
从另外一个角度来看DIO,就是现在除了PG数据库和某些国产数据库,大多数数据库产品都倾向于使用DIO了。MYSQL的innodb现在已经全面拥抱DIO,在默认的刷盘模式中使用了DIO,并且在8.0的较新版本里,对于innodb_flush_method里增加了O_DIRECT_NO_FSYNC选项,进一步优化DIO操作,在不修改文件元数据的情况下,连刷新元数据的FSYNC都不做了,从而进一步提升高并发下数据写入的性能。这个参数选项是十分有效的,很多测试都证明了这一点。可能Linus现在也在后悔当初说了这段话吧,自从2002年之后,Linus就很少就DIO发表意见了,而且在现在的LINUX版本中,这段话也应从man page里删除了。
PG数据库目前WALWRITER是可以使用DIO的,不过数据文件读写并没有使用DIO,这和PG数据库的发展历史是有关的。PG数据库最初的脏块写入时由BACKEND完成的,到了8.0才分出了BGWRITER,用于帮助BACKEND写脏块。不过这个改造并不彻底,当BGWRITER写脏块的速度不够快的时候,backend还是可以搭把手的。到了9.2版本,有哪位BGWRITER不总是那么高效,CHECKPOINTER被引入了,有点令人感到不解的是,CHECKPOINTER不仅仅做CKPT,还会帮助BGWRITER写脏数据。我一直觉得这是一个十分失败的设计。解决写脏数据的效率不足的问题,不是增加帮手才最好,最好的是把写脏数据这种脏活彻底从BACKEND中剥离出来,专门交给多个BGWRITER去做,这些BGWRITER采用分区的方式,自己写自己自留地里的脏块。现在这种多头写脏数据的方式,在业务高峰期,LWLOCK或者SPINLOCK上会消耗太多,反而是得不偿失的。
正是因为PG的这个特点,导致了PG写脏数据的代码十分分散,想要统一修改为使用DIO,其难度是很大的,久而久之,这个问题也就变成了PG的几个跳票严重的功能提升之一了。
既然DOUBLE BUFFER问题暂时还解决不了,那么是不是这个问题就一定会对此类数据库产生很大的性能影响呢?其实也不是的,一方面现代硬件在IO能力上大大提高,如果能够确保底层IO不出现瓶颈,那么这个问题还不会变得十分严重。另外在操作系统层面调整脏块刷新的策略,使之与你的应用负载相匹配,从而让数据库运行的更为平稳,也可以缓解这个问题。
文章转载自白鳝的洞穴,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论