1、进程管理web
企业级数据库服务器可能拥有数千个并发访问数据库的用户。某些用户可能执行只需较少处理能力的简单事务,而其余用户则可能执行涉及更多系统资源的复琐事务。 数据库性能经常基于诸如每小时的事务数或 X个并发链接下的最小响应时间等度量来讨论。这些性能约束由企业施加,以便确保客户的质量保证等级。因为对并发处理具备如此高的需求,企业级数据库服务器须要运行于大型 SMP服务器上。早期的 Linux内核并不很适合充当须要高并发度的数据库服务器。这些内核并无随着系统上的处理器数量的增长而提供良好的扩展性,由于早期内核的开发由单处理器机器所驱动。迁移至多处理器平台时须要许多全局内核锁的支持,不然会致使串行化问题。 其中最大的锁是用于保护单个未排序的运行队列的自旋锁(spin lock)。 在单处理器环境中, 单个队列足以调度全部可运行任务。然而, 在 SMP环境中, 单个运行队列并不够,这会成为一个瓶颈。随着处理器数量的增多,在运行队列上锁竞争的可能性也增长。另
外,因为该队列是未排序的,当锁被持有时调度器须要检查队列中的全部任务以便肯定每一个任务的良好度(每一个任务被赋予一个良好度取值, 用于肯定哪一个任务将是被调度至处理器上运行的最佳候选)。 这增长了锁持有时间, 从而增长了锁竞争的可能性或加重当前的竞争条件。在 Linux 2.5内核中, 这个惟一运行队列被删除并替换为基于 CPU的运行队列。拥有多个运行队列删除了对单个全局锁的需求并改进了总体的可扩展性。另外,每一个运行队列都维护一个优先级列表,有助于调度器选择要运行的最佳任务。这种优先排序能够减小队列上的锁持有时间,并进一步减小了锁竞争 。
数据库
2、内存管理缓存
管理大型企业的数据库须要在大型对称多处理(SymmetricalMultiprocessing,SMP)服务器上运行。这种服务器经常配置了海量物理内存。系统的大部份内存都被分配给数据库缓冲区 cache区域(称为数据库缓冲区)。数据库缓冲区用于缓存从磁盘读至内存中的表和索引数据页。因为磁盘访问相对于内存访问来讲是缓慢的操做,将更多内存分配给数据库缓冲区能够极大改进数据库性能。适当调优的数据库会占用大部分可用内存,而为其余正在运行的应用和操做系统只保留够用的内存大小。为数据库分配过多内存会剥夺其余应用可用的内存空间。 另外, 过分分配内存会致使过多的交换, 这对于数据库性能极为有害。 服务器
Linux内核如何管理物理内存对于数据库服务器的性能而言也很重要。在 IA-32体系结构中, 内核基于 4KB大小的页面管理内存。 另外一方面, 大多数当代的处理器都支持更大的页面(高达数兆字节)。对于许多应用来讲, 4KB页面大小是理想的。小页面能够减小内部分段,将数据换入和换出内存时会产生更小的开销,并确保使用中的虚存驻留于物理内存中。大部分数据库服务器对于其数据库缓冲区都使用大型共享内存段。其结果是须要大量页表项(PageTableEntrie, PTE)。这给内存管理器添加了很大的维护开销。 例如,倘若某个数据库服务器使用 4MB大小的共享内存段为其缓冲区分配 1GB共享内存。使用4KB页面大小的内核须要 262 144个 PTE, 这个庞大的页表数量会给内存管理器增添极大的维护开销。 固然, 上述数据是过度简化的计算值。 实际的 PTE数将远大于这个数值,由于 Linux没法对共享内存的页表进行共享。
Linux 2.6内核中提供了对更大页面的支持。进程能够从内存池中显式请求大页面。使用大页面能够减小当应用请求大型内存块时所需的 PTE数。所以, 维护 PTE所需的计算成本也得以减小。 对于前面的示例, 若是页面大小是 4MB而不是 4KB, 那么 1GB数据库缓冲区只须要 1 024个 PTE(这个计算也被过分简化)。大页面支持特性的另外一个优势是增长了 TLB(translation lookaside buffer)所覆盖的内存范围, 从而下降了 TLB不命中的几率。与页表访问相比较而言, TLB访问的速度极快,由于它是 CPU缓存区域。
3、I/O 管理
数据库性能严重依赖于高效快速的I/O操做。因为有可能要处理 TB量级的数据,任何 I/O瓶颈都会致使数据库服务器难以知足商业需求。 数据库管理员(DBA)一般花费大量时间和金钱对 I/O子系统进行优化,以便减小 I/O延迟并最大化 I/O吞吐率。早期 Linux内核存在着许多阻碍 I/O性能的缺陷,也缺少诸如原始 I/O、向量 I/O、异步I/O以及直接 I/O等特性, 这限制了 DBA对在其余平台上已知可以改善数据库性能的技术加以利用的能力。另外,功能上的匮乏,例如回弹缓冲和单个 I/O请求队列锁,增添了没必要要的系统成本并引入了串行化问题。 幸运的是, 这些问题在 Linux 2.6内核中或经过对2.4内核打补丁都已被消除。
一、回弹缓冲区
在早期的 Linux 内核(早期的 2.4及先前的内核版本)中,设备驱动程序没法直接访问高端内存中的虚址。换句话说,这些设备驱动程序没法对高端内存执行直接内存访问I/O。相反, 内核在低端内存中分配缓冲区,数据经过内核缓冲区在高端内存和设备驱动程序之间传输。 这个内核缓冲区一般称为回弹缓冲区(bouncebuffer), 该过程被称为回弹或回弹缓冲。因为数据库服务器的 I/O密集特征,回弹过程严重地下降了数据库服务器的性能。首先,回弹缓冲区会消耗低端内存,这可能致使内存短缺问题。其次,过量的回弹操做会引发系统占用时间较长, 致使数据库系统彻底变成 CPU绑定的。数据库服务器性能领域的一个主要进展便是在最近的内核中消除了回弹缓冲机制。
二、 原始I/O
Linux 2.4内核中引入的块设备原始(raw)I/O接口提供了从用户空间缓冲区直接执行I/O的能力,而没必要经过文件系统接口进行额外复制。 raw接口的使用避免了文件系统层次上的操做,所以可以极大改进数据库服务器的 I/O性能。然而,应该注意到,并不是全部的数据库工做负荷都可以受益于 raw I/O的使用。若是须要常常访问相同数据, raw I/O就没法利用文件系统缓冲区 cache。raw I/O接口使得 DBA在针对性能目标而进行数据库设计时具备更多的灵活性。 基于数据库服务器的 I/O特征, DBA可选择使用 raw接口以得到更快的 I/O操做,或者使用文件系统缓存机制并减小磁盘访问操做,或者组合使用上述两种机制,这依赖于对数据库中的表的访问方式 。
三、 向量I/O
Linux 2.6内核经过readv和writev接口提供了向量I/O(vectored I/O,也称scattered I/O)的完整实现。向量读操做接口 readv将磁盘上的连续页面读入内存中的非连续页面上;与之相反,向量写操做接口 writev经过单个函数调用将内存中的非连续页面写到磁盘上。这种 I/O机制有利于频繁执行大量串行 I/O操做的数据库服务器。若是没有正确的向量
读写实现,则执行串行 I/O的应用会完成如下操做之一:
- 执行数据库页面大小的 I/O操做。
- 执行大型块 I/O操做,并使用 memcpy函数在读/写缓冲区与数据库缓冲区之间复制数据页面。
在扫描
TB
量级
(
这是当前数据仓库的常见规模
)
的数据时,这两种方法都会产生昂贵的计算开销。
四、 异步I/O
异步I/O机制为应用提供了发出 I/O请求后无需阻塞并等待该 I/O完成的能力。该机制很适合数据库服务器。其余平台提供异步 I/O接口已有一段时间,但该特性在 Linux上还相对较新。在没有异步 I/O机制的状况下要提升 I/O吞吐率, 数据库服务器一般建立许多专门执行 I/O的进程或线程。因为大量进程/线程都在执行 I/O活动, 数据库应用再也不阻塞于单个 I/O请求上。 使用大量进程/线程方式的缺点是建立、 管理和调度这些进程/线程会产生额外的开销。
GNU C Library(GLIBC)异步 I/O接口经过用户级线程来执行阻塞 I/O操做。这种方法只是使得请求对于应用而言看起来是异步的,但与前面描述的方法并没有区别,也面临着一样的性能缺陷。为了消除该问题, Linux 2.6 内核中引入了内核异步 I/O(Kernel AsynchronousI/O, KAIO)接口。 KAIO在内核而不是用户空间中以线程方式实现异步 I/O
机制,确保了真正的异步性。
五、 直接I/O
直接 I/O具备可与原始 I/O相媲美的性能,又拥有文件系统的额外灵活性。所以对于但愿在保持数据库维护灵活性的同时又使用文件系统做为存储介质的数据库管理员来讲,直接I/O是具备吸引力的机制。
使用文件系统而不是 raw设备做为存储介质的主要吸引力是由于其易于调整数据库存储器的容量。只需添加更多的磁盘就能够增长文件系统的大小。 文件系统的另外一个优势是提供了许多可用的工具,例如, DBA可使用 fsck来帮助维护数据完整性。
将文件系统用做没有直接 I/O接口的存储介质也存在着一些缺点。其中之一就是缓冲区 cache守护进程所增长的开销,该进程会主动地将脏页面清空到磁盘上。这种活动所消耗的 CPU周期对于 CPU密集的数据库工做负荷来讲是宝贵资源;另外一个缺点与缓冲区cache不命中问题有关。若是数据不常常重用,其开销会很大。
对于大型数据库系统而言,会为数据库缓冲区分配内存。大型的数据库缓冲区下降了数据库应用的磁盘读写频率,也减小了文件系统缓冲区 cache可用的内存量。这会对服务器性能产生双面影响。首先, 缓冲区 cache守护进程更积极地将脏页面清空到磁盘上(页面更快地变脏)。 其次, 对于容量更小的缓冲区 cache, 数据驻留于其中的可能性要
小得多,这增长了缓冲区 cache不命中的可能性 。
六、块I/O
设备驱动程序以称为块的一组字节为单位来传输数据。块大小被设置为设备的扇区大小,一般为 512B(尽管许多硬件设备及其相关驱动程序能够处理更大的传输文件)。 每一个块在内存中都关联着一个缓冲区头部结构。当来自应用的读请求经过read调用到达时,设备驱动程序将读缓冲区划分红扇区大小的多个块,在与每一个块相关的缓冲区头部里填
充来自物理设备的数据,而后再将这些块接合为原始的读缓冲区。相似地,当来自应用的一个写请求到达时, 设备驱动程序将写缓冲区划分红扇区大小的块,并使用相关缓冲区头部的取值来更新磁盘上的物理数据。在 Lnux2.6内核中,原始 I/O的块大小为 4096B而不是 512B。 这个简单的变化经过减小原始 I/O操做所需的缓冲区头部数量, 改进了总体 I/O吞吐率和 CPU利用率。缓冲区头部更少的话,也能够下降维护其所需的内核开销,而大型块的使用减小了设备驱动程序针对一个 I/O请求须要执行的划分—接合操做数。
七、 I/O请求锁
Linux内核为每一个块设备都维护一个 I/O请求队列。 该队列以一种最大化系统性能的方式对 I/O请求进行排序。在 Lnux 2.2和早期的 2.4内核中,全部的请求队列由一个称为io_request_lock的全局自旋锁加以保护。对于在尤许多磁盘构成的 SMP机器上运行的数据库服务器来讲,这个 I/O请求锁会致使严重的串行化问题。
最近的内核版本里已从 SCSI子系统中删除了这个全局锁(io_request_lock)。在其位置上,每一个 I/O请求队列都由本身的 request_queue_lock锁加以保护。 I/O请求的串行化现象仍会出现,但只发生在单个请求队列上,而不会发生在 SCSI子系统中的全部请求队列上。
4、 小结
从 Linux 2.4版本转换至 2.6版本后出现的大量内核变化改进了数据库服务器性能。诸如多个运行队列等特性的引入经过删除系统中的串行点加强了 SMP扩展性。诸如向量I/O、异步 I/O和直接 I/O等变化所提供的内核服务已在其余平台上证实有助于提升数据库性能。这些改进特性多数已包含在 SUSE或 RHEL基于 2.4内核的发行版本中。随着Linux不断地向数据库服务器领域扩展,更多的性能瓶颈将会显现出来,从而持续推进内核开发以改进性能,而且在此过程当中使得 Linux成为各种数据库应用工做负荷的一种更有吸引力的解决方案。