内核必须适用于广泛的工作负载;可以说,它并不总是像一些用户社区所希望的那样表现就不足为奇了。PostgreSQL关系型数据库管理系统项目是一个有时感觉有点冷的社区。应2014年“Linux存储、文件系统和内存管理”峰会组织者的邀请,PostgreSQL开发人员RobertHaas、AndresFreund和JoshBerkus到场讨论了他们最痛苦的问题和可能的解决方案。PostgreSQL是一个非常古老的系统,可以追溯到1996年;许多用户在各种操作系统上运行它。因此,PostgreSQL开发人员受到他们可以添加的特定于Linux的代码数量的限制。它基于协作进程,不使用线程。SystemV共享内存用于进程间通信。重要的是,PostgreSQL维护自己的内部缓冲区,但也使用I/O缓冲来读取和写入磁盘数据。这种缓冲组合导致了PostgreSQL用户遇到的一些问题。同步慢描述的第一个问题是数据如何从缓冲区高速缓存保存到磁盘。PostgreSQL使用一种他们称为“预写日志记录”的日志记录形式。更改首先写入日志;一旦日志安全地保存在磁盘上,就可以写回主数据库块。大部分工作是通过“检查点”过程完成的;它写入日志条目,然后将一批数据写回磁盘上的各种文件。具有日志功能的写入相对较小且顺序;它们运行良好,据Andres称,PostgreSQL开发人员对系统的这一部分在Linux上的运行情况非常满意。[RobertHaas]数据的写入是另一回事。检查点进程调节这些写入,以便I/O系统不会淹没其他一切。但是当它开始考虑调用fsync()以确保数据被安全写入,并且所有这些条件写入被立即推送到请求队列时,它会导致I/O风暴。按照他们的说法,问题不是fsync()太慢,而是太快了。它将如此多的数据导出到I/O系统,以至于其他所有内容(包括应用程序读取请求等)都被阻止。这给用户带来了痛苦,也给PostgreSQL开发人员带来了痛苦。TedTs'o询问将检查点进程限制为I/O可用带宽的特定百分比是否有帮助。但是Robert回应说I/O优先级应该更好;当其他进程不需要带宽时,检查点进程应该能够100%使用它。提出了使用I/O友好机制(它将控制CFQ调度程序中的I/O优先级),但这也有问题:它不适用于fsync()调用启动的I/O操作。即使写入来自检查点进程的数据(并非总是如此),当fsync()实际开始执行I/O时,也不会强制执行优先级。RicWheeler建议PostgreSQL开发人员需要更多地控制他们写入数据的速率;ChrisMason补充说,O_DATASYNC选项可用于在发出I/O请求时提供更精细的控制。这里的问题是这个实现需要PostgreSQL知道存储设备的速度。让我们将讨论带回I/O优先级。由于请求队列的维护是通过I/O调度器实现的,大多数PostgreSQL用户青睐的调度器往往会避免使用CFQ调度器(CompletelyFairQueuing绝对公平调度器),或者根本不实现I/O。/O优先机制。这还不是最坏的,即使是那些提供I/O优先级的地方,也会限制请求队列的长度。大量的数据刷新操作将很快填满队列,此时I/O优先级将失去大部分作用。如果没有空间容纳这些请求队列,高优先级的请求将被停用,无法达到预期的高优先级。看来I/O优先级并不能解决问题。正确的解决方案看起来仍然模糊和牵强。Ted表示,如果PostgreSQL的开发者能够提供一个通过运行数据库来构建这种I/O模式的小程序,并给出一种可以轻松重现这些问题的方法,那么内核开发者就可以尝试更多不同的方法来找到解决方案。这样的程序可能类似于PostgreSQL的初始配置脚本,但单个小程序是内核开发人员社区更愿意看到的。双缓冲技术PostgreSQL需要做自己的缓冲技术,因为在很多情况下它会因为各种原因使用I/O缓冲。这就导致了一个问题:数据库数据经常在内存中存储两次,一次在PostgreSQL缓冲区中,一次在页面缓存中。PostgreSQL在一定程度上大大增加了内存占用,这对一个完整的系统是不利的。应该有效消除大量内存浪费行为。考虑在PostgreSQL缓存中有一个脏缓冲区比内核在页面缓存中有数据更新的示例。PostgreSQL在flush这个脏数据的时候,pagecache被重写这个重要过程不会发生,所以数据会不同步。在这种情况下,如果PostgreSQL可以告诉内核删除页面缓存中的相应页面就好了,但现实是没有好的API可以做到这一点。根据Andres的说法,可以使用FADV_DONTNEED参数调用fadvise()函数,实际上这会导致读取指定的页面,很少有人能很好地理解这种行为,但他们都同意它不应该这样工作。在映射到文件处理之前,它们也不能使用madvise()函数。这样做,大量的工作进程可能会变得非常缓慢。这种做法看起来不错,但它也可能会向相反的方向移动一些页面。PostgreSQL可能想从它自己的缓冲区中删除一个干净的页面,但在页面缓存中保留一个副本。复制。可能是一个特殊的写操作,实际上不会引起I/O,或者可能是一个将物理页面转换为页面缓存的系统调用。表面上有相当多的讨论,但没有一个讨论能给出确定的结论。回归PostgreSQL用户经常遇到的另一个问题是最近的一些内核特性可能会导致执行性能问题。例如,透明大页面功能对PostgreSQL工作负载没有任何好处,而且速度要慢得多。很明显,很多时间花在了试图运行的紧凑代码上,但它们并没有真正产生空闲的大页面(Hugepages)。因此,在许多系统中,当透明巨页(transparenthugepage)功能被关闭时,可怕的性能问题就完全消失了。MelGorman的回答:如果压缩会影响性能,那它就是一个错误。话虽如此,他已经有一段时间没有发现透明大分页的任何缺陷了。此外,他说,已经发布了一个补丁,该补丁限制了在任何给定时间可以执行压缩的进程数量。然而,这个补丁的代码没有被合并,因为没有人的工作负载会遇到太多进程运行压缩的问题。也许是时候重新审视那个特定的补丁了,他想。另一个痛点来自区域回收功能,即使整个系统内存不足,它也会从内核中的某些区域回收页面。区域回收会减慢PostgreSQL工作负载。通常诀窍是简单地在PostgreSQL服务器上禁用此功能。Andres指出,他曾多次担任与区域回收相关的绩效问题的顾问。这对他来说是一个很好的赚钱方式。但如果这些问题能够得到解决,那将是一件好事。Mel说,区域回收模型的编写假设系统中的所有进程都适合单个NUMA节点。该假设不再有意义;它太过时了,他说,该选项的默认值已更改为“关闭”。看起来房间里没有人反对这个想法,所以在不久的将来可能会有所改变。***,PostgreSQL开发人员指出,一般来说,内核升级往往是可怕的。Linux内核的性能特征往往在一个版本与下一个版本之间有很大差异;这使得升级成为不确定的事情。有一些关于寻找新内核来运行PostgreSQL基准测试的讨论,但没有得出明确的结论。不过,总的来说,这两个项目的开发人员都对对话的结果感到满意;如果没有别的,这代表了两个项目之间的新水平的沟通。英文原文:PostgreSQLpainpoints翻译链接:http://www.oschina.net/translate/postgresql-pain-points
