MySQL的操作系统和硬件优化讨论小家电维修

MySQL服务器性能受制于整个系统最薄弱的环节,承载它的操作系统和硬件往往是限制因素。磁盘大小、可用内存和CPU资源、网络,以及所有连接它们的组件,都会限制系统的最终容量。因此,需要小心地选择硬件,并对硬件和操作系统进行合适的配置。例如,若工作负载是I/O密集型的,一种方法是设计应用程序使得最大限度地减少MySQL的I/O操作。然而,更聪明的方式通常是升级I/O子系统,安装更多的内存,或重新配置现有的磁盘。

硬件的更新换代非常迅速,所以本章有关特定产品或组件的内容可能将很快变得过时。像往常一样,我们的目标是帮助提升对这些概念的理解,这样对于即使没有直接覆盖到的知识也可以举一反三。这里我们将通过现有的硬件来阐明我们的观点。

许多不同的硬件都可以影响MySQL的性能,但我们认为最常见的两个瓶颈是CPU和I/0资源。当数据可以放在内存中或者可以从磁盘中以足够快的速度读取时,CPU可能出现瓶颈。把大量的数据集完全放到大容量的内存中,以现在的硬件条件完全是可行的。

另一方面,I/O瓶颈,一般发生在工作所需的数据远远超过有效内存容量的时候。如果应用程序是分布在网络上的,或者如果有大量的査询和低延迟的要求,瓶颈可能转移到网络上,而不再是磁盘I/O。

<服务器性能剖析>中提及的技巧可以帮助找到系统的限制因素,但即使你认为已经找到了瓶颈,也应该透过表象去看更深层次的问题。某一方面的缺陷常常会将压力施加在另一个子系统,导致这个子系统出问题。例如,若没有足够的内存,MySQL可能必须刷出缓存来腾出空间给需要的数据——然后,过了一小会,再读回刚刚刷新的数据(读取和写入操作都可能发生这个问题)。本来是内存不足,却导致出现了I/O容量不足。当找到一个限制系统性能的因素时,应该问问自己,“是这个部分本身的问题,还是系统中其他不合理的压力转移到这里所导致的?”

还有另外一个例子:内存总线的瓶颈也可能表现为CPU问题。事实上,我们说一个应用程序有“CPU瓶颈”或者是“CPU密集型”,真正的意思应该是计算的瓶颈。接下来将深入探讨这个问题。

在升级当前硬件或购买新的硬件时,应该考虑下工作负载是不是CPU密集型。

可以通过检查CPU利用率来判断是否是CPU密集型的工作负载,但是仅看CPU整体的负载是不合理的,还需要看看CPU使用率和大多数重要的査询的I/O之间的平衡,并注意CPU负载是否分配均匀。本章稍后讨论的工具可以用来弄清楚是什么限制了服务器的性能。

当遇到CPU密集型的工作时,MySQL通常可以从更快的CPU中获益(相对更多的CPU)。

当我们讨论CPU的时候,为保证本文易于阅读,对某些术语将不会做严格的定义。现在一般的服务器通常都有多个插槽(Socket),每个插槽上都可以插一个有多个核心的CPU(有独立的执行单元),并且每个核心可能有多个“硬件线程”。这些复杂的架构需要有点耐心去了解,并且我们不会总是明确地区分它们。不过,在一般情况下,当谈到CPU速度的时候,谈论的其实是执行单元的速度,当提到的CPU数量时,指的通常是在操作系统上看到的数量,尽管这可能是独立的执行单元数量的多倍。

这几年CPU在各个方面都有了很大的提升。例如,今天的IntelCPU速度远远超过前几代,这得益于像直接内存连接(directlyattachedmemory)技术以及PCIe卡之类的设备互联上的改善等。这些改进对于存储设备尤其有效,例如Fusion-io和Virident的PCIe闪存驱动器。

所以多和快哪个更重要?一般来说两个都想要。从广义上来说,调优服务器可能有如下两个目标:

低延时(快速响应)

要做到这一点,需要髙速CPU,因为每个査询只能使用一个CPU。

高吞吐

如果能同时运行很多査询语句,则可以从多个CPU处理査询中受益。然而,在实践中,还要取决于具体情况。因为MySQL还不能在多个CPU中完美地扩展,能用多少个CPU还是有极限的。在旧版本的MySQL中(MySQL5.1以后的版本已经有一些提升),这个限制非常严重。在新的版本中,则可以放心地扩展到16或24个CPU,或者更多,取决于使用的是哪个版本(Percona往往在这方面略占优势)。

如果有多路CPU,并且没有并发执行査询语句,MySQL依然可以利用额外的CPU为后台任务(例如清理InnoDB缓冲、网络操作,等等)服务。然而,这些任务通常比执行査询语句更加轻量化。

MySQL复制也能在高速CPU下工作得非常好,而多CPU对复制的帮助却不大。如果工作负载是CPU密集型,主库上的并发任务传递到备库以后会被简化为串行任务,这样即使备库硬件比主库好,也可能无法保持跟主库之间的同步。也就是说,备库的瓶颈通常是I/O子系统,而不是CPU。

如果有一个CPU密集型的工作负载,考虑是需要更快的CPU还是更多CPU的另外一个因素是査询语句实际在做什么。在硬件层面,一个査询可以在执行或等待。处于等待状态常见的原因是在运行队列中等待(进程已经是可运行状态,但所有的CPU都忙)、等待闩锁(Latch)或锁(Lock)、等待磁盘或网络。那么你期望査询是等待什么呢?如果等待闩锁或锁,通常需要更快的CPU;如果在运行队列中等待,那么更多或者更快的CPU都可能有帮助。(也可能有例外,例如,査询等待InnoDB日志缓冲区的Mutex,直到I/O完成前都不会释放——这可能表明需要更多的I/O容量)。

再次说明,在理论上这可能更好地工作:不管査询是读取不同的表还是相同的表,InnoDB都会有一些全局共享的数据结构,而MyISAM在每个缓冲区都有全局锁。而且不仅仅是存储引擎,服务器层也有全局锁。以前InnoDB承担了所有的骂名,但最近做了一些改进后,暴露了服务器层中的其他瓶颈。例如臭名昭著的L0CK_open互斥量(Mutex),在MySQL5.1和更早版本中可能就是个大问题,另外还有其他一些服务器级别的互斥量(例如査询缓存)。

可能99%以上的MySQL实例(不含嵌入式使用)都运行在Intel或者AMD芯片的x86架构下。这里基本都是针对这种情况。

64位架构现在都是默认的了,32位CPU已经很难买到了。MySQL在64位架构上工作良好,尽管有些事暂时不能利用64位架构来做。因此,如果使用的是较老旧版本的MySQL,在64位服务器上可能要小心。例如,在MySQL5.0发布的早期时候,每个MyISAM键缓冲区被限制为4GB,由一个32位整数负责寻址。(可以创建多个键缓冲区来解决这个问题。)

确保在64位硬件上使用64位操作系统!最近这种情况已经不太常见了,但以前经常可以遇到,大多数主机托管提供商暂时还是在服务器上安装32位操作系统,即使是64位CPU。32位操作系统意味着不能使用大量的内存:尽管某些32位系统可以支持大量的内存,但不能像64位系统一样有效地利用,并且在32位系统上,任何一个单独的进程都不能寻址4GB以上的内存。

多CPU在联机事务处理(OLTP)系统的场景中非常有用。这些系统通常执行许多小的操作,并且是从多个连接发起请求,因此可以在多个CPU上运行。在这样的环境中,并发可能成为瓶颈。大多数Web应用程序都属于这一类。

实际上有两种类型的数据库并发问题,需要不同的方法来解决,如下所示。

逻辑并发问题

应用程序可以看到资源的竞争,如表或行锁争用。这些问题通常需要好的策略来解决,如改变应用程序、使用不同的存储引擎、改变服务器的配置,或使用不同的锁定提示或事务隔离级别。

内部并发问题

比如信号量、访问InnoDB缓冲池页面的资源争用,等等。可以尝试通过改变服务器的设置、改变操作系统,或使用不同的硬件解决这些问题,但通常只能缓解而无法彻底消灭。在某些情况下,使用不同的存储引擎或给存储引擎打补丁,可以帮助缓解这些问题。

MySQL的“扩展模式”是指它可以有效利用的CPU数量,以及在压力不断增长的情况下如何扩展,这同时取决于工作负载和系统架构。通过“系统架构”的手段是指通过调整操作系统和硬件,而不是通过优化使用MySQL的应用程序。CPU架构(RISC、CISC、流水线深度等)、CPU型号和操作系统都影响MySQL的扩展模式。这也是为什么说基准测试是非常重要的:一些系统可以在不断增加的并发下依然运行得很好,而另一些的表现则糟糕得多。

有些系统在更多的处理器下甚至可能降低整体性能。这是相当普遍的情况,我们了解到许多人试图升级到有多个CPU的系统,最后只能被迫恢复到旧系统(或绑定MySQL进程到其中某些核心),因为这种升级反而降低了性能。在MySQL5.0时代,Google的补丁和PerconaServer出现之前,能有效利用的CPU核数是4核,但是现在甚至可以看到操作系统报告多达80个“CPU”的服务器。如果规划一个大的升级,必须要同时考虑硬件、服务器版本和工作负载。

某些MySQL扩展性瓶颈在服务器层,而其他一些在存储引擎层。存储引擎是怎么设计的至关重要,有时更换到一个不同的引擎就可以从多处理器上获得更多效果。

我们看到在世纪之交围绕处理器速度的战争在一定程度上已经平息,CPU厂商更多地专注于多核CPU和多线程的变化。CPU设计的未来很可能是数百个处理器核心,四核心和六核心的CPU在今天是很常见的。不同厂商的内部架构差异很大,不可能概括出线程、CPU和内核之间的相互作用。内存和总线如何设计也是非常重要的。归根结底,多个内核和多个物理CPU哪个更好,这是由硬件体系结构决定的。

第二个复杂之处是boost技术,这个技术改变了我们对CPU模式的看法。我们曾经以为四核2GHzCPU有四个同样强大的核心,不管其中有些是闲置或非闲置。因此,一个完美的可扩展系统,当它使用所有四个内核的时候,可以预计得到四倍的提升。但是现在已经不是这样了,因为当系统只使用一个核心时,处理器会运行在更高的时钟速度上,例如3GHz。这给很多的规划容量和可扩展性建模的工具出了一个难题,因为系统性能表现不再是线性的变化了。这也意味着,“空闲CPU”并不代表相同规模的资源浪费,如果有一台服务器上只运行了备库的复制,而复制执行是单线程的,所以有三个CPU是空闲的,因此认为可以利用这些CPU资源执行其他任务而不影响复制,可能就想错了。

配置大量内存最大的原因其实不是因为可以在内存中保存大量数据:最终目的是避免磁盘I/O,因为磁盘I/O比在内存中访问数据要慢得多。关键是要平衡内存和磁盘的大小、速度、成本和其他因素,以便为工作负载提供高性能的表现。在讨论如何做到这一点之前,暂时先回到基础知识上来。

计算机包含一个金字塔型的缓存体系,更小、更快、更昂贵的缓存在顶端,如图9-1所示。

在数据库服务器上尤其明显,其行为往往非常符合我们刚才提到的预测算法所做的预测。设计良好的数据库缓存(如InnoDB缓冲池),其效率通常超过操作系统的缓存,因为操作系统缓存是为通用任务设计的。数据库缓存更了解数据库存取数据的需求,它包含特殊用途的逻辑(例如写入顺序)以帮助满足这些需求。此外,系统调用不需要访问数据库中的缓存数据。

这些专用的缓存需求就是为什么必须平衡缓存层次结构以适应数据库服务器特定的访问模式的原因。因为寄存器和芯片上的高速缓存不是用户可配置的,内存和存储是唯一可以改变的东西。

数据库服务器同时使用顺序和随机I/O,随机I/O从缓存中受益最多。想像有一个典型的混合工作负载,均衡地包含单行査找与多行范围扫描,可以说服自己相信这个说法。典型的情况是“热点”数据随机分布。因此,缓存这些数据将有助于避免昂贵的磁盘寻道。相反,顺序读取一般只需要扫描一次数据,所以缓存对它是没用的,除非能完全放在内存中缓存起来。

顺序读取不能从缓存中受益的另一个原因是它们比随机读快。这有以下两个原因:

顺序I/O比随机I/O快。

顺序操作的执行速度比随机操作快,无论是在内存还是磁盘上。假设磁盘每秒可以做100个随机I/O操作,并且可以完成每秒50MB的顺序读取(这大概是消费级磁盘现在能达到的水平)。如果每行100字节,随机读每秒可以读100行,相比之下顺序读可以每秒读560000行——是随机读的5000倍,或几个数量级的差异。因此,在这种情况下随机I/O可以从缓存中获得很多好处。

顺序访问内存行的速度也快于随机访问。现在的内存芯片通常每秒可以随机访问约250000次100字节的行,或者每秒500万次的顺序访问。请注意,内存随机访问速度比磁盘随机访问快了2500倍,而内存中顺序访问只有磁盘10倍的速度。

存储引擎执行顺序读比随机读快。

一个随机读一般意味着存储引擎必须执行索引操作。(这个规则也有例外,但对InnoDB和MyISAM都是对的)。通常需要通过B树的数据结构査找,并且和其他值比较。相反,连续读取一般需要遍历一个简单的数据结构,例如链表。这样就少了很多工作,反复这样操作,连续读取的速度就比随机读取要快了。

最后,随机读取通常只要査找特定的行,但不仅仅只读取一行——而是要读取一整页的数据,其中大部分是不需要的。这浪费了很多工作。另一方面,顺序读取数据,通常发生在想要的页面上的所有行,所以更符合成本效益。

综上所述,通过缓存顺序读取可以节省一些工作,但缓存随机读取可以节省更多的工作。换句话说,如果能负担得起,增加内存是解决随机I/O读取问题最好的办法。

如果有足够的内存,就完全可以避免磁盘读取请求。如果所有的数据文件都可以放在内存中,一旦服务器缓存“热”起来了,所有的读操作都会在缓存命中。虽然还是会有逻辑读取,不过物理读取就没有了。但写入是不同的问题。写入可以像读一样在内存中完成,但迟早要被写入到磁盘,所以它是需要持久化的。换句话说,缓存可延缓写入,但不能像消除读取一样消除写入。

事实上,除了允许写入被延迟,缓存可以允许它们被集中操作,主要通以下两个重要途径:

多次写入,一次刷新

一片数据可以在内存中改变很多次,而不需要把所有的新值写到磁盘。当数据最终被刷新到磁盘后,最后一次物理写之前发生的修改都被持久化了。例如,许多语句可以更新内存中的计数器。如果计数器递增100次,然后写入到磁盘,100次修改就被合并为一次写。

I/O合并

许多不同部分的数据可以在内存中修改,并且这些修改可以合并在一起,通过一次磁盘操作完成物理写入。

这就是为什么许多交易系统使用预写日志(WAL)策略。预写日志采用在内存中变更页面,而不马上刷新到磁盘上的策略,因为刷新磁盘通常需要随机I/0,这非常慢。相反,如果把变化的记录写到一个连续的日志文件,这就很快了。后台线程可以稍后把修改的页面刷新到磁盘;并在刷新过程中优化写操作。

写入从缓冲中大大受益,因为它把随机I/O更多地转换到连续I/O。异步(缓冲)写通常是由操作系统批量处理,使它们能以更优化的方式刷新到磁盘。同步(无缓冲)写必须在写入到磁盘之后才能完成。这就是为什么它们受益于RAID控制器中电池供电的回写(Write-Back)高速缓存。

每个应用程序都有一个数据的“工作集”——就是做这个工作确实需要用到的数据。很多数据库都有大量不在工作集内的数据。

可以把数据库想象为有抽屉的办公桌。工作集就是放在桌面上的完成工作必须使用的文件。桌面是这个比喻中的主内存,而抽屉就是硬盘。

就像完成工作不需要办公桌里每一张纸一样,也不需要把整个数据库装到内存中来获得最佳性能——只需要工作集就可以。

工作集大小的不同取决于应用程序。对于某些应用程序,工作集可能是总数据大小的1%,而对于其他应用,也可能接近100%。当工作集不能全放在内存中时,数据库服务器必须在磁盘和内存之间交换数据,以完成工作。这就是为什么内存不足可能看起来却像I/O问题。有时没有办法把整个工作集的数据放在内存中,并且有时也并不真的想这么做(例如,若应用需要大量的顺序I/O)。工作集能否完全放在内存中,对应用程序体系结构的设计会产生很大的影响。

应该依据最常用的页面集来考虑工作集,而不是最频繁读写的页面集。这意味着,确定工作集需要在应用程序内有测量的模块,而不能仅仅看外部资源的利用,例如I/O访问,因为页面的I/O操作跟逻辑访问页面不是同一回事。例如,MySQL可能把一个页面读入内存,然后访问它数百万次,但如果査看strace,只会看到一个I/O操作。缺乏确定工作集所需的检测模块,最大的原因是没有对这个主题有较多的研究。

工作集包括数据和索引,所以应该采用缓存单位来计数。一个缓存单位是存储引擎工作的数据最小单位。

找到一个良好的内存/磁盘比例最好的方式是通过试验和基准测试。如果可以把所有东西放入内存,你就大功告成了——后面没有必要再为此考虑什么。但大多数的时候不可能这么做,所以需要用数据的一个子集来做基准测试,看看将会发生什么。测试的目标是一个可接受的缓存命中率。缓存未命中是当有査询请求数据时,数据不能在内存中命中,服务器需要从磁盘获取数据。

让我们考虑下工作集是如何影响高速缓存命中率的。首先重要的一点,要认识到工作集不仅是一个单一的数字而是一个统计分布,并且缓存命中率是非线性分布的。例如,有10GB内存,并且缓存未命中率为10%,你可能会认为只需要增加11%以上的内存(正确的数字是11%而不是10%。10%的未命中率对应90%的命中率,所以你需要用10GB除以90%,就是11.111GB。),就可以降低缓存的未命中率到0。但实际上,诸如缓存单位的大小之类的问题会导致缓存效率低下,可能意味着理论上需要50GB的内存,才能把未命中率降到1%。即使与一个完美的缓存单位相匹配,理论预测也可能是错误的:例如数据访问模式的因素也可能让事情更复杂。解决1%的缓存未命中率甚至可能需要500GB的内存,这取决于具体的工作负载!

有时候很容易去优化一些可能不会带来多少好处的地方。例如,10%的未命中率可能导致80%的CPU使用率,这已经是相当不错的了。假设增加内存,并能够让缓存未命中率下降到5%,简单来说,将提供另外约6%的数据给CPU。再简化一下,也可以说,把CPU使用率增加到了84.8%。然而,考虑到为了得到这个结果需要购买的内存,这可不一定是一个大胜利。在现实中,因为内存和磁盘访问速度之间的差异、CPU真正操作的数据,以及许多其他因素,降低缓存未命中率到5%可能都不会太多改变CPU使用率。

这就是为什么我们说,你应该争取一个可接受的缓存命中率,而不是将缓存未命中率降低到零。没有一个应该作为目标的数字,因为“可以接受”怎么定义,取决于应用程序和工作负载。有些应用程序有1%的缓存未命中都可以工作得非常好,而另一些应用实际上需要这个比例低到0.01%才能良好运转。(“良好的缓存未命中率”是个模糊的概念,其实有很多方法来进一步计算未命中率。)

最好的内存/磁盘的比例还取决于系统上的其他组件。假设有16GB的内存、20GB的数据,以及大量未使用的磁盘空间系统。该系统在80%的CPU利用率下运行得很好。如果想在这个系统上放置两倍多的数据,并保持相同的性能水平,你可能会认为只需要让CPU数量和内存量也增加到两倍。然而,即使系统中的每个组件都按照增加的负载扩展相同的量(一个不切实际的假设),这依然可能会使得系统无法正常工作。有20GB数据的系统可能使用了某些组件超过50%的容量——例如,它可能已经用掉了每秒I/O最大操作数的80%。并且在系统内排队也是非线性的。服务器将无法处理两倍的负载。因此,最好的内存/磁盘比例取决于系统中最薄弱的组件。

如果无法满足让足够的数据在内存中的目标——例如,估计将需要500GB的内存才能完全让CPU负载起当前的I/O系统——那么应该考虑一个更强大的I/O子系统,有时甚至要以牺牲内存为代价,同时应用程序的设计应该能处理I/O等待。

这听起来似乎有悖常理。毕竟,我们刚刚说过,更多的内存可以缓解I/O子系统的压力,并减少I/O等待。为什么要加强I/O子系统呢,如果只增加内存能解决问题吗?答案就在所涉及的因素之间的平衡,例如读写之间的平衡,每个I/O操作的大小,以及每秒有多少这样的操作发生。例如,若需要快速写日志,就不能通过增加大量有效内存来避免磁盘写入。在这种情况下,投资一个髙性能的I/O系统与带电池支持的写缓存或固态存储,可能是个更好的主意。

作为一个简要回顾,从传统磁盘读取数据的过程分为三个步骤:

1.移动读取磁头到磁盘表面上的正确位置。

2.等待磁盘旋转,所有所需的数据在读取磁头下。

3.等待磁盘旋转过去,所有所需的数据都被读取磁头读出。

其他一些因素也可以影响磁盘的选择,哪个重要取决于应用。假设正在为一个在线应用选择磁盘,例如一个受欢迎的新闻网站,有大量小的磁盘随机读取。可能需要考虑下列因素:

存储容量

对在线应用来说容量很少成为问题,因为现在的磁盘通常足够大了。如果不够,用RAID把小磁盘组合起来是标准做法。

传输速度

现代磁盘通常数据传输速度非常快,正如我们前面看到的。究竟多快主要取决于主轴转速和数据存储在磁盘表面上的密度,再加上主机系统的接口的限制(许多现代磁盘读取数据的速度比接口可以传输的快)。无论如何,传输速度通常不是在线应用的限制因素,因为它们一般会做很多小的随机査找。

主轴转速

现在常见的转速是7200RPM、10000RPM,以及15000RPM。转速不管对随机査找还是顺序扫描都有很大影响。

物理尺寸

和CPU—样,MySQL如何扩展到多个磁盘上取决于存储引擎和工作负载。InnoDB能很好地扩展到多个硬盘驱动器。然而,MyISAM的表锁限制其写的可扩展性,因此写繁重的工作加在MyISAM上,可能无法从多个驱动器中收益。虽然操作系统的文件系统缓冲和后台并发写入会有点帮助,但MyISAM相对于InnoDB在写可扩展性上有更多的限制。

和CPU—样,更多的磁盘也并不总是更好。有些应用要求低延迟需要的是更快的驱动器,而不是更多的驱动器。例如,复制通常在更快的驱动器上表现更好,因为备库的更新是单线程的。

固态存储设备采用非易失性闪存芯片而不是磁性盘片组成。它们也被称为NVRAM,或非易失性随机存取存储器。固态存储设备没有移动部件,这使得它们表现得跟硬盘驱动器有很大的不同。

目前MySQL用户感兴趣的技术可分为两大类:SSD(固态硬盘)和PCIe卡。SSD通过实现SATA(串行髙级技术附件)接口来模拟标准硬盘,所以可以替代硬盘驱动器,直接插入服务器机箱中的现有插槽。PCIe卡使用特殊的操作系统驱动程序,把存储设备作为一个块设备输出。PCIe和SSD设备有时可以简单地都认为是SSD。

下面是闪存性能的快速小结。高质量闪存设备具备:

最重要的事情是提升随机I/O和并发性。闪存记忆体可以在髙并发下提供很好的随机I/O性能,这正是范式化的数据库所需要的。设计非范式化的Schema最常见的原因之一是为了避免随机I/O,并且使得査询可能转化为顺序I/O。

硬盘驱动器使用旋转盘片和可移动磁头,其物理结构决定了磁盘固有的局限性和特征。对固态存储也是一样,它是构建在闪存之上的。不要以为固态存储很简单,实际上比硬盘驱动器在某些方面更复杂。闪存的限制实际上是相当严重的,并且难以克服,所以典型的固态设备都有错综复杂的架构、缓存,以及独有的“法宝”。

闪存的最重要的特征是可以迅速完成多次小单位读取,但是写入更有挑战性。闪存不能在没有做檫除操作前改写一个单元(Cell),并且一次必须擦除一个大块——例如,512KB。擦除周期是缓慢的,并且最终会磨损整个块。一个块可以容忍的檫除周期次数取决于所使用的底层技术。

垃圾收集对理解闪存很重要。为了保持一些块是干净的并且可以被写入,设备需要回收脏块。这需要设备上有一些空闲空间。无论是设备内部有一些看不到的预留空间,或者通过不写那么多数据来预留需要的空间——不同的设备可能有所不同。无论哪种方式,设备填满了,垃圾收集就必须更加努力地工作,以保持一些块是干净的,所以写放大的倍数就增加了

因此,许多设备在被填满后会开始变慢。到底会慢多少,不同的制造商和型号之间有所不同,依赖于设备的架构。有些设备为髙性能而设计,即使写得非常满,依然可以保持高性能。但是,通常一个100GB的文件在160GB和320GB的SSD上表现完全不同。速度下降是由于没有空闲块时必须等待擦写完成所造成的。写到一个空闲块只需要花费数百微秒,但是擦写慢得多——通常需要几个毫秒。

有两种主要的闪存设备类型,当考虑购买闪存存储时,理解两者之间的不同是很重要的。这两种类型分别是单层单元(SLC)和多层单元(MLC)。

SLC的每个单元存储数据的一个比特:可以是0或1。SLC相对更昂贵,但非常快,并且擦写寿命高达100000个写周期,具体值取决于供应商和型号。这听起来好像不多,但在现实中一个好的SLC设备应该持续使用大约20年左右,甚至比卡上安装的控制器更耐用和可靠。缺点则是存储密度相对较低,所以不能在每个设备上得到那么多空间。

MLC每个单元存储2个比特、3个比特的设备也有。这使得通过MLC设备获得更高的存储密度(更大的容量)成为可能。成本更低了,但是速度和耐擦写性也下降了。一个不错的MLC设备可能被定为10000个写循环周期。

可以在大众市场上购买到这两种类型的闪存设备,它们之间的竞争有助于闪存的发展。目前,SLC仍持有“企业”级服务器的存储解决方案的声誉,通常被视为消费级的MLC设备,一般使用在笔记本电脑和数码相机等地方。然而,这种情况正在改变,出现了一种新兴的所谓企业级MLC(eMLC)存储。

然而,这并不是一个不可逾越的工程问题。厂商正在制造一些有越来越多隐藏容量的设备,因此有足够的内部冗余。尽管闪存厂商非常注意保护自己的商业秘密,还是有传言称,某些设备可能有比它标称大小多出高达两倍的存储空间。使MLC芯片更耐用的另一种方法是通过固件逻辑。平衡磨损和重映射的算法是非常重要的。

寿命的长短取决于真实的容量,固件逻辑等——所以最终是因供应商而异的。我们听说过在几个星期里密集使用导致设备报废的报告!

当然,我们感兴趣的是阶段C的性能,所以基准测试只需要测量这个部分的运行过程。这意味着基准测试要做的不仅仅是基准测试:还需要先进行一下预热,然后才能进行基准测试。但是,定义预热的终点和基准测试的起点会非常棘手。

设备、文件系统,以及操作系统通过不同方式提供TRIM命令的支持,这个命令标记空间准备重用。有时当删除所有文件时设备会被TRIM。如果在基准测试运行的情况下发生,设备将重置到阶段A,然后必须重新执行A和B之间的运行阶段。另一个因素是设备被填充得很满或者不满时,不同的性能表现。一个可重复的基准测试必须覆盖到所有这些因素。

通过上述分析,可知基准测试的复杂性,所以就算厂商如实地报告测试结果,但对于外行来说,厂商的基准测试和规格说明书依然可能有很多“坑”。

通常可以从供应商那得到四个数字。这里有一个设备规格的例子:

1.设备读取性能最髙达520MB/S。

2.设备写入性能最高达480MB/s。

3.设备持续写入速度可以稳定在420MB/S。

4.设备每秒可以执行70000个4KB的写操作。

如果再次复核这些数字,你会发现峰值4KB写入达到70000个IOPS(每秒输入/输出操作),这么算每秒写入大约只有274MB/s,这比第二点和第三点中说明的高峰写入带宽少了很多。这是因为达到峰值写入带宽时是用更大的块,例如64KB或128KB。用更小的块大小来达到峰值IOPS。

大部分应用不会写这么大的块。InnoDB写操作通常是16KB或512字节的块组合到一起写回。因此,设备应该只有274MB/S的写出带宽——这是阶段A的情况,在垃圾回收器开启和设备达到长期稳定的性能等级前!

SSD模拟SATA硬盘驱动器。这是一个兼容性功能:替换SATA硬盘不需要任何特殊的驱动程序或接口。

关于SSD的好处是,它们有大量的品牌和型号相对是比较便宜的,同时它们比硬盘快了很多。最大的缺点是,它们并不总是像硬盘一样可靠,这取决于品牌和型号。直到最近,大多数设备都没有板载电池,但大多数设备上有一个写缓存来缓冲写入。写入缓存在没有电池备份的情况下并不能持久化,但是在快速增长的写负载下,它不能关闭,否则闪存存储无法承受。所以,如果禁用了驱动器的高速缓存以获得真正持久化的存储,将会更快地耗完设备寿命,在某些情况下,这将导致保修失效。

通常,使用SSD都是值得的。但底层技术的挑战是不容易解决的。很多厂家做出的驱动器在髙负载下很快就崩溃了,或不提供持续一致的性能。一些低端的制造商有一个习惯,每次发布新一代驱动器,就声称他们已经解决了老一代的所有问题。这往往是不真实的,当然,如果关心可靠性和持续的高性能,“企业级”的设备通常值得它的价钱。

用SSD做RAID

然而,即使支持闪存的控制器,也不一定真的就对闪存支持很好。例如,Vadim对Adaptec5805Z控制器进行了基准测试,他用了多种驱动器做RAID10,16个并发操作500GB的文件。结果是很糟糕的:95%的随机写延迟在两位数的毫秒,在最坏的情况下,超过一秒钟。(期望的应该是亚毫秒级写入。)

这种特定的比较,是一家客户为了看到MicronSSD是否会比64GB的IntelSSD更好而做的,该比较是基于相同的配置的。当为英特尔驱动器进行基准测试时,我们发现了相同的性能特征。因此,我们尝试了一些其他驱动器的配置,不管有没有SAS扩展器,看看会发生什么。表9-1显示了这个结果。

这些结果都没有达到我扪对这么多驱动器的期望。在一般情况下,RAID控制器的性能表现,只能满足对68个驱动器的期望,而不是几十个。原因很简单,RAID控制器达到了瓶颈。这个故事的重点是,在对硬件投入巨资前,应该先仔细进行基准测试——结果可能与期望的有相当大的区别。

相对于SATASSD,PCIe设备没有尝试模拟硬盘驱动器。这种设计是好事:服务器和硬盘驱动器之间的接口不能完全发挥闪存的性能。SAS/SATA互联带宽比PCIe要低,所以PCIe对髙性能需求是更好的选择。PCIe设备延迟也低得多,因为它们在物理上更靠近CPU。

没有什么比得上从PCIe设备上获得的性能。缺点就是它们太贵了。

所有我们熟悉的型号都需要一个特殊的驱动程序来创建块设备,让操作系统把它认成一个硬盘驱动器。这些驱动程序使用着混合磨损均衡和其他逻辑的策略;有些使用主机系统的CPU和内存,有些使用板载的逻辑控制器和RAM(内存)。在许多场景下,主机系统有丰富的CPU和RAM资源,所以相对于购买一个自身有这些资源的卡,利用主机上的资源实际上是更划算的策略。

有许多家供应商在生产PCIe闪存卡。对MySQL用户来说最著名的厂商是Fusion-io和Virident,但是像TexasMemorySystems、STEC和OCZ这样的厂商也有用户。SLC和MLC都有相应的PCIe卡产品。

然而这些都不适合一般的MySQL市场。它们的目标更针对其他数据库,如Oracle,可以用来做共享存储集群。一般情况下,MySQL在如此大规模的场景下,不能有效利用如此强大的存储优势,因为在数十个TB的数据下MySQL很难良好地工作——MySQL对这样一个庞大的数据库的回答是,拆分、横向扩展和无共享(Shared-nothing)架构。

虽然专业化的解决方案可能能够利用这些大型存储设备——例如Infobdght可能成为候选人。ScaleDB可以部署在共享存储(Shared-storage)架构,但我们还没有看到它在生产环境应用,所以我们不知道其工作得如何。

固态存储最适合使用在任何有着大量随机I/O工作负载的场景下。随机I/O通常是由于数据大于服务器的内存导致的。用标准的硬盘驱动器,受限于转速和寻道延迟,无法提供很高的IOPS。闪存设备可以大大缓解这种问题。

当然,有时可以简单地购买更多内存,这样随机工作负载就可以转移到内存,I/O就不存在了。但是当无法购买足够的内存时,闪存也可以提供帮助。另一个不能总是用内存解决的问题是,髙吞吐的写入负载。增加内存只能帮助减少写入负载到磁盘,因为更多的内存能创造更多的机会来缓冲、合并写。这允许把随机写转换为更加顺序的I/O。

然而,这并不能无限地工作下去,一些事务或插入繁忙的工作负载不能从这种方法中获益。闪存存储在这种情况下却也有帮助。

单线程工作负载是另一个闪存的潜在应用场景。当工作负载是单线程的时候,它是对延迟非常敏感的,固态存储更低的延迟可以带来很大的区别。相反,多线程工作负载通常可以简单地加大并行化程度以获得更高的吞吐量。MySQL复制是单线程工作的典型例子,它可以从低延迟中获得很多收益。在备库跟不上主库时,使用闪存存储往往可以显著提高其性能。

闪存也可以为服务器整合提供巨大的帮助,尤其是PCIe方式的。我们已经看到了机会,把很多实例整合到一台物理服务器——有时髙达10或15倍的整合都是可能的。

然而闪存也可能不一定是你要的答案。一个很好的例子是,像InnoDB日志文件这样的顺序写的工作负载,闪存不能提供多少成本与性能优势,因为在这种情况下,闪存连续写方面不比标准硬盘快多少。这样的工作负载也是髙吞吐的,会更快耗尽闪存的寿命。在标准硬盘上存放日志文件通常是一个更好的主意,用具有电池保护写缓存的RAID控制器。

有时答案在于内存/磁盘的比例,而不只是磁盘。如果可以买足够的内存来缓存工作负载,就会发现这更便宜,并且比购买闪存存储设备更有效。

虽然有很多因素需要在闪存、硬盘和RAM之间权衡,在存储层次结构中,这些设备没有被当作一个整体处理。有时可以使用磁盘和内存技术的结合,这就是Flashcache。

Flashcache是这种技术的一个实现,可以在许多系统上发现类似的使用,例如Oracle数据库、ZFS文件系统,甚至许多现代的硬盘驱动器和RAID控制器。下面讨论的许多东西应用广泛,但我们将只专注于Flashcache,因为它和厂商、文件系统无关。

Flashcache是一个Linux内核模块,使用Linux的设备映射器(DeviceMapper)。它在内存和磁盘之间创建了一个中间层。这是Facebook开源和使用的技术之一,可以帮助其优化数据库负载。

Flashcache创建了一个块设备,并且可以被分区,也可以像其他块设备一样创建文件系统,特点是这个块设备是由闪存和磁盘共同支撑的。闪存设备用作读取和写入的智能高速缓存。

虚拟块设备远比闪存设备要大,但是没关系,因为数据最终都存储在磁盘上。闪存设备只是去缓冲写入和缓存读取,有效弥补了服务器内存容量的不足(意思就是内存放不下要缓存的数据时,换出到Flashcache上,Flashache的闪存设备可以帮助继续缓存,而不会立刻落到磁盘。)。

这种性能有多好呢?Flashcache似乎有相对较高的内核开销。(设备映射并不总是像看起来那么有效,但我们还没深入调査找出原因。)但是,尽管Flashcache理论上可能更髙效,但最终的性能表现并不如底层的闪存存储那么好,不过它仍然比磁盘快很多,所以还是值得考虑的方案。

我们用包含数百个基准测试的一系列测试来评估Flashcache的性能,但是我们发现在人工模拟的工作负载下,测出有意义的数据是非常困难的。于是我们得出结论,虽然并不清楚Flashcache通常对写负载有多大好处,但是对读肯定是有帮助的。于是它适合这样的情况使用:有大量的读I/0,并且工作集比内存大得多。

除了实验室测试,我们有一些生产环境中应用Flashcache的经验。想到的一个例子是,有个4TB的数据库,这个数据库遇到了很大的复制延迟。我们给系统加了半个TB的ViridentPCIe卡作为存储。然后安装了Flashcache,并且把PCIe卡作为绑定设备的闪存部分,复制速度就翻了一倍。

当闪存卡用得很满时使用Flashcache是最经济的,因此选择一张写得很满时其性能不会降低多少的卡非常重要。这就是为什么我们选择Virident卡。

应该使用Flashcache吗?根据具体情况可能会有所不同,所以我们认为在这一点上,如果你觉得不确定,最好得到专家的意见。理解Flashcache的机制和它们如何影响你的数据库工作集大小是很复杂的,在数据库下层(至少)有三层存储:

有可能还有更多层次:例如,SAN或RAID控制器的缓存。

现在,假设有以下的存储设备:一个很大的RAID卷,可以执行1000IOPS,以及一个可以达到100000I0PS的更小的闪存设备。闪存设备不足以存放所有的数据——假设只有128GB-因此单独使用闪存不是一种可能的选择。如果用闪存设备做Flashcache,就可以期望缓存命中远远快于磁盘检索,但Flashcache整体比单独使用闪存设备要慢。我们坚持用数字说话,如果90%的请求落到Flashcache设备,相当于达到50000I0PS。

这个思维实验的结果是什么呢?有两个要点:

1.系统使用Flashcache比不使用的性能要好很多,因为大多数在缓冲池未命中的页面访问都被缓存在闪存卡上,相对于磁盘可以提供快得多的访问速度。(99%的工作集可以完全放在闪存卡上。)

2.Flashcache设备上有90%的命中率意味着有10%没有命中。因为底层的磁盘只能提供1000I0PS,因此整个Flashcache设备可以支持10000的I0PS。为了明白为什么是这样的,想象一下如果我们要求不止于此会发生什么:10%的I/O操作在缓存中没有命中而落到了RAID卷上,则肯定要求RAID卷提供超过1000I0PS,很显然是没法处理的。因此,即使Flashcache比闪存卡慢,系统作为一个整体仍然受限于RAID卷,不止是闪存卡或Flashcache。

归根到底,Flashcache是否合适是一个复杂的决定,涉及的因素很多。一般情况下,它似乎最适合以读为主的I/O密集型负载,并且工作集太大,用内存优化并不经济的情况。

如果在闪存上运行MySQL,有一些配置参数可以提供更好的性能。InnoDB的默认配置从实践来看是为硬盘驱动器定制的,而不是为固态硬盘定制的。不是所有版本的InnoDB都提供同样等级的可配置性。尤其是很多为提升闪存性能设计的参数首先出现在PerconaServer中,尽管这些参数很多已经在Oracle版本的InnoDB中实现,或者计划在未来的版本中实现。

改进包括:

增加InnoDB的I/O容量

闪存比机械硬盘支持更高的并发量,所以可以增加读写I/O线程数到10或15来获得更好的结果。也可以在200020000范围内调整innodb_io_capacity选项,这要看设备实际上能支撑多大的IOPS。尤其是对Oracle官方的InnoDB这个很有必要,内部有更多算法依赖于这个设置。

让InnoDB日志文件更大

把一些文件从闪存转移到RAID

除了把InnoDB日志文件设置得更大,把日志文件从数据文件中拿出来,单独放在一个带有电池保护写缓存的RAID组上而不是固态设备上,也是个好主意。这么做有几个原因。一个原因是日志文件的I/O类型,在闪存设备上不比在这样一个RAID组上要快。InnoDB写日志是以512字节为单位的顺序I/O写下去,并且除了崩溃恢复会顺序读取,其他时候绝不会去读。这样的I/O操作类型用闪存设备是很浪费的。并且把小的写入操作从闪存转移到RAID卷也是个好主意,因为很小的写入会增加闪存设备的写放大因子,会影响一些设备的使用寿命。大小写操作混合到一起也会引起某些设备延时的增加。

基于相同的原因,有时把二进制日志文件转移到RAID卷也会有好处。并且你可能会认为ibdata1文件也适合放在RAID卷上,因为ibdata1文件包含双写缓冲(DoublewriteBuffer)和插入缓冲(InsertBuffer),尤其是双写缓冲会进行很多重复写入。在PerconaServer中,可以把双写缓冲从ibdata1文件中拿出来,单独存放到一个文件,然后把这个文件放在RAID卷上。

禁用预读

预读通过通知和预测读取模式来优化设备的访问,一旦认为某些数据在未来需要被访问到,就会从设备上读取这些数据。实际上在InnoDB中有两种类型的预读,我们发现在多种情况下的性能问题,其实都是预读以及它的内部工作方式造成的。在许多情况下开销比收益大,尤其是在闪存存储,但我们没有确凿的证据或指导,禁用预读究竟可以提高多少性能。

在MySQL5.1的InnoDBPlugin中,MySQL禁用了所谓的“随机预读”,然后在MySQL5.5又重新启用了它,可以在配置文件用一个参数配置。PerconaServer能让你在旧版本里也一样可以配置为random或linearread-ahead(线性预读)。

配置InnoDB刷新算法

这决定InnoDB什么时候、刷新多少、刷新哪些页面,这是个非常复杂的主题,这里我们没有足够的篇幅来讨论这些具体的细节。这也是个研究比较活跃的主题,并且实际上在不同版本的InnoDB和MySQL中有多种有效的算法。

标准InnoDB算法没有为闪存存储提供多少可配置性,但是如果用的是PerconaXtraDB(包含在PerconaServer和MariaDB中),我们建议设置innodb_adaptive_checkpoint选项为keep_average,不要用默认值estimate。这可以确保更持续的性能,并且避免服务器抖动,因为estimate算法会在闪存存储上引起抖动。我们专门为闪存存储开发了keep_average,因为我们意识到对于闪存设备,把希望操作的大量I/O推到设备上,并不会引起瓶颈或发生抖动。

另外,建议为闪存设备设置:innodb_flush_neighbor_pages=0。这样可以避免InnoDB尝试查找相邻的脏页一起刷写。这个算法可能会导致更大块的写、更髙的延迟,以及内部竞争。在闪存存储上这完全没必要,也不会有什么收益,因为相邻的页面单独刷新不会冲击性能。

禁用双写缓冲的可能

相对于把双写缓存转移到闪存设备,可以考虑直接关闭它。有些厂商声称他们的设备支持16KB的原子写入,使得双写缓冲成为多余的。如果需要确保整个存储系统被配置得可以支持16KB的原子写入,通常需要0_DIRECT和XFS文件系统。

没有确凿的证据表明原子操作的说法是真实的,但由于闪存存储的工作方式,我们相信写数据文件发生页面写一部分的情况是大大减少的,并且这个收益在闪存设备上比在传统磁盘上要高得多,禁用双写缓冲在闪存存储上可以提髙MySQL整体性能差不多50%,尽管我们不知道这是不是100%安全的,但是你可以考虑下这么做。

限制插入缓冲大小

插入缓冲(在新版InnoDB中称为变更缓冲(ChangeBuffer))设计来用于减少当更新行时不在内存中的非唯一索引引起的随机I/O。在硬盘驱动器上,减少随机I/O可以带来巨大的性能提升。对某些类型的工作负载,当工作集比内存大很多时,差异可能达到近两个数量级。插入缓冲在这类场景下就很有用。

然而,对闪存就没有必要了。闪存上随机I/O非常快,所以即使完全禁用插入缓冲,也不会带来太大影响,尽管如此,可能你也不想完全禁用插入缓存。所以最好还是启用,因为I/O只是修改不在内存中的索引页面的开销的一部分。对闪存设备而言,最重要的配置是控制最大允许的插入缓冲大小,可以限制为一个相对比较小的值,而不是让它无限制地增长,这可以避免消耗设备上的大量空间,并避免ibdata1文件变得非常大的情况。在mysql5.5之前时候,标准InnoDB还不能配置插入缓存的容量上限,但是在PerconaXtraDB(PerconaServer和MariaDB都包含XtraDB)里可以。MySQL5.6里也会增加一个类似的变量。

除了上述的配置建议,我们还提出或讨论了其他一些闪存优化策略。然而,不是所有的策略都非常容易明白,所以我们只是提到了一部分,最好自己研究在具体情况下的好处。首先是InnoDB的页大小。我们发现了不同的结果,所以我们现在还没有一个明确的建议。好消息是,在PerconaServer中不需要重编译也能配置页面大小,在MySQL5.6中这个功能也可能实现。以前版本的MySQL需要重新编译服务器才能使用不同大小的页面,所以大部分情况都是运行在默认的16KB页面。当页面大小更容易让更多人进行实验时,我们期待更多非标准页面大小的测试,可能能从中得到很多重要的结论。

可能已经提醒过了,我们提到的很多功能和优化在标准版本的InnoDB中是无效的。我们希望并且相信我们引入PerconaServer和XtraDB中的改进点,最终将会被广大用户接受。与此同时,如果正使用Oracle官方MySQL分发版本,依然可以对服务器采取措施为闪存进行优化。建议使用innodb_file_per_table,并且把数据文件目录放到闪存设备。然后移动ibdata1和日志文件,以及其他所有日志文件(二进制日志、复制日志,等等),到RAID卷,正如我们之前讨论的。这会把随机I/O集中到闪存设备上,然后把大部分顺序写入的压力尽可能转移出闪存,因而可以节省闪存空间并且减少磨损。

另外,所有版本的MySQL服务器,都应该确认超线程开启了。当使用闪存存储时,这有很大的帮助,因为磁盘通常不再是瓶颈,任务会更多地从I/O密集变为CPU密集。

为备库选择硬件与为主库选择硬件很相似,但是也有些不同。如果正计划着建一个备库做容灾,通常需要跟主库差不多的配置。不管备库是不是仅仅作为一个主库的备用库,都应该强大到足以承担主库上发生的所有写入,额外的不利因素是备库只能序列化串行执行。

备库硬件主要考虑的是成本:需要在备库硬件上花费跟主库一样多的成本吗?可以把备库配置得不一样以便从备库上获得更多性能吗?如果备库跟主库工作负载不一样,可以从不一样的硬件配置上获得隐含的收益吗?

这一切都取决于备库是否只是备用的,你可能希望主库和备库有相同的硬件和配置,但是,如果只是用复制作为扩展更多读容量的方法,那备库可以有多种不同的捷径。例如,可能在备库使用不一样的存储引擎,并且有些人使用更便宜的硬件或者用RAID0代替RAID5或RAID10。也可以取消一些一致性和持久性的保证让备库做更少的工作。

这些措施在大规模部署的情况下具有很好的成本效益,但是在小规模的情况下,可能只会使事情变得更加复杂。在实践中,似乎大多数人都会选择以下两种策略为备库选择硬件:主备使用相同的硬件,或为主库购买新的硬件,然后让备库使用主库淘汰的老硬件。

在备库很难跟上主库时,使用固态硬盘有很大的意义。很好的随机I/O性能有助于缓解单个复制线程的影响。

存储引擎通常把数据和索引都保存在一个大文件中,这意味着用RAID(RedundantArrayofInexpensiveDisks,磁盘冗余阵列)存储大量数据通常是最可行的方法。RAID可以帮助做冗余、扩展存储容量、缓存,以及加速。但是从我们看到的一些优化案例来说,RAID上有多种多样的配置,为需求选择一个合适的配置非常重要。

这里raid的配置以及类型就不做介绍了。

RAID配置(除了RAID0)都提供了冗余。这很重要,但很容易让人低估磁盘同时发生故障的可能性。千万不要认为RAID能提供一个强有力的数据安全性保证。

这就是为什么做RAID阵列的监控如此重要。大部分控制器提供了一些软件来报告阵列的状态,并且需要持续跟踪这些状态,因为不这么做可能就会忽略了驱动器失效。你可能丧失恢复数据和发现问题的时机,当第二块硬盘损坏时,已经晚了。因此应该配置一个监控系统来提醒硬盘或者RAID卷发生降级或失效了。

对阵列积极地进行定期一致性检査,可以减少潜在的损坏风险。某些控制器有后台巡检(BackgroundPatrolRead)功能,当所有驱动器都在线服务时,可以检査媒介是否有损坏并且修复,也可以帮助避免此类问题的发生。在恢复时,非常大型的阵列可能会降低检査速度,所以创建大型阵列时一定要确保制定了相应的计划。

也可以添加一个热备盘,这个盘一般是未使用状态,并且配置为备用状态,有硬盘坏了之后控制器会自动把这块盘恢复为使用状态。如果依赖于每个服务器的可用性,这是一个好主意。对只有少数硬盘驱动器的服务器,这么做是很昂贵的,因为一个空闲磁盘的成本比例比较高,但如果有多个磁盘,而不设一个热备盘,就是愚蠢的做法。请记住,更多的磁盘驱动器会让发生故障的概率迅速增加。

除了监控硬盘失效,还应该监控RAID控制器的电池备份单元以及写缓存策略。如果电池失效,大部分控制器默认设置会禁用写缓存,把缓存策略从WriteBack改为WriteThrough。这可能导致服务器性能下降。很多控制器会通过一个学习过程周期性地对电池充放电,在这个过程中缓存是被禁用的。RAID控制器管理工具应该可以浏览和配置电池充放电计划,不会让人措手不及。

也许希望把缓存策略设为WriteThrouhg来测试系统,这样就可以知道系统性能的期望值。也许需要计划电池充放电的周期,安排在晚上或者周末,重新配置服务器修改innodb_flush_log_at_trx_commit和sync_binlog变量,或者在电池充放电时简单地切换到另一台服务器。

操作系统、文件系统和操作系统看到的驱动器数量之间的相互作用可以是复杂的。Bug、限制或只是错误配置,都可能会把性能降低到远远低于理论值。

如果有10块硬盘,理想中应该能够承受10个并行的请求,但有时文件系统、操作系统或RAID控制器会把请求序列化。面对这个问题一个可行的办法是尝试不同的RAID配置。例如,如果有10个磁盘,并且必须使用镜像冗余,性能也要好,可以考虑下面几种配置:

哪个选项是最好的?这依赖于系统中所有的组件如何相互协作。不同的配置可能获得相同的结果,也可能不同。

我们已经提醒了多种配置可能导致串行化。例如,ext3文件系统每个inode有一个单一的Mutex,所以当InnoDB是配置为innodb_flush_method=0_DIRECT(常见的配置)时,在文件系统会有inode级别的锁定。这使得它不可能对文件进行I/O并发操作,因而系统表现会远低于其理论上的能力。

我们见过的另一个案例,请求串行地发送到一个10块盘的RAID10卷中的每个设备,使用ReiserFS文件系统,InnoDB打开了innodb_file_per_table选项。尝试在硬件RAID1的基础上用软件RAID0做成RAID10的方式,获得了五倍多的吞吐,因为存储系统开始表现出五个硬盘同时工作的特性,而不再是一个了。造成这种情况的是一个已经被修复的Bug,但是这是一个很好的例证,说明这类事情可能发生。

串行化可能发生在任何的软件或硬件堆栈层。如果看到这个问题发生了,可能需要更改文件系统、升级内核、暴露更多的设备给操作系统,或使用不同的软件或硬件RAID组合方式。应该检査你的设备的并发性以确保它确实是在做并发I/O。

最后,当准备上线一种新服务器时,不要忘了做基准测试!这会帮助你确认能获得所期望的性能。例如,若一个硬盘驱动器每秒可以做200个随机读,一个有8个硬盘驱动器的RAID10卷应该接近每秒1600个随机读。如果观察到的结果比这个少得多,比如说每秒500个随机读,就应该研究下哪里可能有问题了。确保基准测试对I/O子系统施加了跟MySQL—样的方式的压力——例如,使用0_DIRECT标记,并且如果使用没有打开innodb_file_per_table选项的InnoDB,要用一个单一的文件测试I/O性能。通常可以使用来验证新的硬件设置都是正确的。

RAID条带块大小

这只是理论上的观点。在实践中,许多RAID控制器在大条带下工作得不好。例如,控制器可能用缓存中的缓存单元大小作为块大小,这可能有浪费。控制器也可能把块大小、缓存大小、读取单元的大小(在一个操作中读取的数据量)匹配起来。如果读的单位太大,RAID缓存可能不太有效,最终可能会读取比真正需要的更多的数据,即使是微小的请求。

当然,在实践中很难知道是否有数据会跨越多个驱动器。即使块大小为16KB,与InnoDB的页大小相匹配,也不能让所有的读取对齐16KB的边界。文件系统可能会把文件分成片段,每个片段的大小通常与文件系统的块大小对齐,大部分文件系统的块大小为4KB。一些文件系统可能更聪明,但不应该指望它。

RAID缓存

RAID缓存就是物理安装在RAID控制器上的(相对来说)少量内存。它可以用来缓冲硬盘和主机系统之间的数据。下面是RAID卡使用缓存的几个原因:

缓存读取

控制器从磁盘读取数据并发送到主机系统后,通过缓存可以存储读取的数据,如果将来的请求需要相同的数据,就可以直接使用而无须再次去读盘。

这实际上是RAID缓存一个很糟糕的用法。为什么呢?由于操作系统和数据库服务器有自己更大得多的缓存。如果数据在这些上层缓存中命中了,RAID缓存中的数据就不会被使用。相反,如果上层的缓存没有命中,就有可能在RAID缓存中命中,但这个概率是微乎其微的。因为RAID缓存要小得多,几乎肯定会被刷新掉,被其他数据填上去了。无论哪种方式,缓冲读都是浪费RAID缓存的事。

缓存预读数据

如果RAID控制器发现连续请求的数据,可能会决定做预读操作——就是预先取出估计很快会用到的数据。在数据被请求之前,必须有地方放这些数据。这也会使用RAID缓存来放。预读对性能的影响可能有很大的不同,应该检查确保预读确实有帮助。如果数据库服务器做了自己的智能预读(例如InnoDB的预读),RAID控制器的预读可能就没有帮助,甚至可能会干扰所有重要的缓冲和同步写入。

缓冲写入

内部操作

某些RAID的操作是非常复杂的——尤其是RAID5的写入操作,其中要计算校验位,用来在发生故障时重建数据。控制器做这类内部操作需要使用一些内存。

这也是RAID5在一些RAID控制器上性能差的原因:为了好的性能需要读取大量数据到内存。有些控制器不能较好地平衡缓存写和RAID5校验位操作所需要的内存。

一般情况下,RAID控制器的内存是一种稀缺资源,应该尽量用在刀刃上。缓存读取通常是一种浪费,但是缓冲写入是加速I/O性能的一个重要途径。许多控制器可以选择如何分配内存。例如,可以选择有多少缓存用于写入和多少用于读取。对于RAID0、RAID1和RAID10,应该把控制器缓存100%分配给写入用。对于RAID5,应该保留一些内存给内部操作。通常这是正确的建议,但并不总是适用——不同的RAID卡需要不同的配置。

写入缓冲对同步写入非常有用,例如事务日志和二进制日志(sync_binlog设置为1)调用的fsync(),但是除非控制器有电池备份单元(BBU)或其他非易失性存储,否则不应该启用RAID缓存。不带BBU的情况下缓冲写,在断电时,有可能损坏数据库,甚至是事务性文件系统。然而,如果有BBU,启用写入缓存可以提升很多日志刷新的工作的性能,例如事务提交时刷新事务日志。

最后要考虑的是,许多硬盘驱动器有自己的缓存,可能有“假”的fsync()操作,欺骗RAID控制器说数据已被写入物理介质。有时可以让硬盘直接挂载(而不是挂到RAID控制器上),让操作系统管理它们的缓存,但这并不总是有效。这些缓存通常在做fsync()操作时被刷新,另外同步I/O也会绕过它们直接访问磁盘,但是再次提醒,硬盘驱动器可能会骗你。应该确保这些缓存在fsync()时真的刷新了,否则就禁用它们,因为磁盘缓存没有电池供电(所以断电会丢失)。操作系统或RAID固件没有正确地管理硬盘管理已经造成了许多数据丢失的案例。

SAN(StorageAreaNetwork)和NAS(Network-AttachedStorage)是两个外部文件存储设备加载到服务器的方法。不同的是访问存储的方式。访问SAN设备时通过块接口,服务器直接看到一块硬盘并且可以像硬盘一样使用,但是NAS设备通过基于文件的协议来访问,例如NFS或SMB。SAN设备通常通过光纤通道协议(FCP)或iSCSI连接到服务器,而NAS设备使用标准的网络连接。还有一些设备可以同时通过这两种方式访问,比如NetAppFiler存储系统。.

在接下来的讨论中,我们将把这两种类型的存储统一称为SAN。在后面的阅读应该记住这一点。主要区别在于作为文件还是块设备访问存储。

SAN允许服务器访问非常大量的硬盘驱动器——通常在50块以上——并且通常配置大容量智能高速缓存来缓冲写入。块接口在服务器上以逻辑单元号(LUN)或者虚拟卷(除非使用NFS)出现。许多SAN也允许多节点组成集群来获得更好的性能或者增加存储容量。

目前新一代SAN跟几年前的不同。许多新的SAN混合了闪存和机械硬盘,而不仅仅是机械硬盘了。它们往往有大到TB级或以上的闪存作为缓存,不像旧的SAN,只有相对较小的缓存。此外,旧的SAN无法通过配置更大的缓存层来“扩展缓冲池”,而新的SAN有时可以。因此,相比之下新的SAN可以提供更好的性能。

我们已经测试了多个SAN厂商的多种产品。表9-3展示了一些低并发场景下的典型测试结果。

具体的SAN厂商名字和配置做了保密处理,但是可以透露的是这些都不是便宜的SAN。测试都是用同步的16KB操作,模拟InnoDB配置在0_DIRECT模式时的操作方式。

从表9-3中可以得出什么结论?我们测试的系统不是都可以直接比较的,所以盯着这些好看的数据点来看不能客观地做出评价。然而,这些结果很好地说明了这类设备的总体性能表现,SAN可以承受大量的连续写入,因为可以缓冲并合并I/O。SAN提供顺序读取没有问题,因为可以做预读并从缓存中提出数据。在随机写上会慢一些,因为写入操作不能较好地合并。因为读取通常在缓存中无法命中,必须等待硬盘驱动器响应,所以SAN很不适合做随机读取。最重要的是,服务器和SAN之间有传输延迟。这是为什么通过NFS连接SAN时,提供的每秒随机读还不如一块本地磁盘的原因。

某些SAN,例如NetAppFilet存储,通常通过NFS访问,而不是通过光纤或者iSCSI。这曾经是我们希望避免的情况,但是NFS今天比以前好了很多。通过NFS可以获得相当好的性能,尽管需要专门配置网络。SAN厂商提供的最佳实践指导可以帮助了解怎样配置。

主要考虑的事情是NFS协议自身怎样影响性能。许多文件元信息操作,通常在本地文件系统或者SAN设备(非NAS)的内存中执行,但是在NAS上可能需要一次网络来回发送。例如,我们提醒过把二进制日志存在NFS上会损害服务器性能,即使关闭Sync_binlog也无济于事。

也可以通过SMB协议访问SAN或者NAS,需要考虑的问题类似:可能有更多的网络通信,会对延迟产生影响。对传统桌面用户这没什么影响,他们通常只是在挂载的驱动器上存储电子表格或者其他文档,或者只是为了备份复制一些东西到另一台服务器。但是用作MySQL读写它的文件,就会有严重的性能问题。

这些都是些典型的例子,哪些工作放在SAN上不合适:执行大量的随机I/O的单线程任务。在当前版本的MySQL中,复制是另一个单线程任务。因此,备库的数据存储在SAN上,可能更容易落后于主库。批处理作业也可能运行得更慢。在非高峰时段或周末执行一个一次性的延迟敏感的操作是可以的,但是服务器的很多部分依然需要很好的性能,例如拷贝、二进制日志,以及InnoDB的事务日志上总是需要很好的小随机I/O性能。

嗯,这是个长期存在的问题——在某些情况下,数百万美元的问题。有很多因素要考虑,以下我们列出其中的几个。

备份

集中存储使备份更易于管理。当所有数据都存储在一个地方时,可以只备份SAN,只要确保已经确认过了所有的数据都在。这简化了问题,例如“你确定我们要备份所有的数据吗?”此外,某些设备有如连续数据保护(CDP)以及强大的快照功能等功能,使得备份更容易、更灵活。

简化容量规划

存储整合还是服务器整合

高可用

有时人们认为SAN是高可用解决方案。之所以会这样认为,可能是因为对高可用的真实含义的理解出现了分歧。

根据我们的经验,SAN经常与故障和停机联系在一起,这不是因为它们不可靠——它们没什么问题,也确实很少出故障——只是因为人们都不愿意相信这样的工程奇迹其实也会坏的,因而缺乏这方面的准备。此外,SAN有时是一个复杂的、神秘的黑盒子,当出问题的时候没有人知道该如何解决,并且价格昂贵,难以快速构建管理SAN所需的专业知识。大多数的SAN都对外缺乏可见性(就是个黑盒子),这也是为什么不应该只是简单地信任SAN管理员、支持人员或管理控制台的原因。我们看到过所有这三种人都错了的情况:当SAN出了问题,如出现硬盘驱动器故障导致性能下降的案例。这是另一个推荐使用sysbench的理由:sysbench可以快速地完成一个I/O基准测试以证明是否是SAN的问题。

服务器之间的交互

共享存储可能会导致看似独立的系统实际上是相互影响的,有时甚至会很严重。例如,我们知道一个SAN用户有个很粗放的认识,当开发服务器上有I/O密集型操作时,会引起数据库服务器几乎陷于停顿。批处理作业、ALTERTABLE、备份——任何一个系统上产生大量的I/O操作都可能会导致其他系统的I/O资源不足。有时的影响远远比直觉想象的糟糕,一个看似不起眼的操作可能会导致严重的性能下降。

成本

成本是什么?管理和行政费用?每秒I/O操作数(IOPS)中每个I/O操作的成本?标价?

有充分的理由使用SAN,但无论销售人员说什么,至少从MySQL需要的性能类型来看,SAN不是最佳的选择。(选择一个SAN供应商并跟它们的销售谈,你可能听到他们一般也是同意的,然后告诉你他们的产品是一个例外。)如果考虑性价比,结论会更加清楚,因为闪存存储或配置有电池支持写缓存的RAID控制器加上老式硬盘驱动器,可以在低得多的价格下提供更好的性能。

关于这个话题,不要忘了让销售给你两台SAN的价格。至少需要两台,否则这台昂贵的SAN可能会成为故障中的单点。

有许多“血泪史”可以引以为戒,这不是试图吓唬你远离SAN。我们知道的SAN用户都非常地爱这些存储!如果正在考虑是否使用SAN,最重要的事情是想清楚要解决什么问题。SAN可以做很多事情,但解决性能问题只是其中很小的一部分。相比之下,当不要求很多髙性能的随机I/0,但是对某些功能感兴趣的话,如快照、存储整合、重复数据删除和虚拟化,SAN可能非常适合。

因此,大多数Web应用不应该让数据库使用SAN,但SAN在所谓的企业级应用很受欢迎。企业通常不太受预算限制,所以能够负担得起作为“奢侈品”的SAN。(有时SAN甚至作为一种身份的象征!)

我们迟早都会碰到文件应该放哪的问题,因为MySQL创建了多种类型的文件:

MySQL没有提供复杂的空间管理功能。默认情况下,只是简单地把每个Schema的文件放入一个单独的目录。有少量选项来控制数据文件放哪。例如,可以指定MyISAM表的索引位置,也可以使用MySQL5.1的分区表。

如果正在用InnoDB默认配置,所有的数据和文件都放在一组数据文件(共享表空间)中,只有表定义文件放在数据目录。因此,大部分用户把所有的数据和文件放在了单独的卷。

然而,有时使用多个卷可以帮助解决I/O负载高的问题。例如,一个批处理作业需要写入很多数据到一张巨大的表,将这张表放在单独的卷上,可以避免其他查询的I/O受到影响。理想的情况下,应该分析不同数据的I/O访问类型,才能把数据放在适当的位置,但这很难做到,除非已经把数据放在不同的卷上。

你可能已经听过标准建议,就是把事务日志和数据文件放在不同的卷上面,这样日志的顺序I/O和数据的随机I/O不会互相影响。但是除非有很多硬盘(20或更多)或者闪存存储,否则在这样做之前应该考虑清楚代价。

二进制日志和数据文件分离的真正的优势,是减少事故中同时丢失数据和日志文件的可能性。如果RAID控制器上没有电池支持的写缓存,把它们分开是很好的做法。

将日志放在独立的卷是否可以提升性能?通常情况下是的,但是从成本的角度来看这个问题,是否真的值得这么做,答案往往是否定的,尽管很多人不这么认为。

原因是:为事务日志提供专门的硬盘是很昂贵的。假设有六个硬盘驱动器,最常规的做法是把所有六块盘放到一个RAID卷,或者分成两部分,四个放数据,两个放事务日志。不过如果这样做,就减少了三分之一的硬盘放数据文件,这会导致性能显著地下降。此外,专门提供两个驱动器,对负载的影响也微不足道(假设RAID控制器有电池支持的写缓存)。

另一方面,如果有很多硬盘,投入一些给事务日志可能会从中受益。例如,一共有30块硬盘,可以分两块硬盘(配置为一个RAID1的卷)给日志,能让日志写尽可能快。对于额外的性能,也可以在RAID控制器中分配一些写缓存空间给这个RAID卷。

成本效益不是唯一考虑的因素。可能想保持InnoDB的数据和事务日志在同一个卷的另一个原因是,这种策略可以使用LVM快照做无锁的备份。某些文件系统允许一致的多卷快照,并且对这些文件系统,这是一个很轻量的操作,但对于ext3有很多东西需要注意。

另外一个常见的场景是分离出临时目录的文件,MySQL做filesorts(文件排序)和使用磁盘临时表时会写到临时目录。如果这些文件不会太大的话,最好把它们放在临时内存文件系统,如tmpfs。这是速度最快的选择。如果在你的系统上这不可行,就把它们放在操作系统盘上。

典型的磁盘布局是有操作系统盘、交换分区和二进制日志的盘,它们放在RAID1卷上。还要有一个单独的RAID5或RAID10卷,放其他的一切东西。

就像延迟和吞吐量是硬盘驱动器的限制因素一样,延迟和带宽(实际上和吞吐量是同一回事)也是网络连接的限制因素。对于大多数应用程序来说,最大的问题是延时。典型的应用程序都需要传输很多很小的网络包,并且每次传输的轻微延迟最终会被累加起来。

网络物理隔离也是很重要的因素。城际网络相比数据中心的局域网的延迟要大得多,即使从技术上来说带宽是一样的。如果节点真的相距甚远,光速也会造成影响。例如,在美国的西部和东部海岸都有数据中心,相隔约3000公里。光的速度是186000米每秒,因此一次通信不可能低于16毫秒,往返至少需要32毫秒。物理距离不仅是性能上的考虑,也包括设备之间通信的考虑。中继器、路由器和交换机,所有的性能都会有所降级。再次,越广泛地分隔开的网络节点,连接的不可预知和不可靠因素越大。

尽可能避免实时的跨数据中心的操作是明智的。如果不可能做到这一点,也应该确保应用程序能正常处理网络故障。例如,我们不希望看到由于Web服务器通过丢包严重的网络连接远程的数据中心时,由于Apache进程挂起而新建了很多进程的情况发生。

在本地,请至少用千兆网络。骨干交换机之间可能需要使用万兆以太网。如果需要更大的带宽,可以使用网络链路聚合:连接多个网卡(NIC),以获得更多的带宽。链路聚合本质上是并行网络,作为高可用策略的一部分也很有帮助。

如果需要非常高的吞吐量,也许可以通过改变操作系统的网络配置来提髙性能。如果连接不多,但是有很多的査询和很大的结果集,则可以增加TCP缓冲区的大小。具体的实现依赖于操作系统,对于大多数的linux系统,可以改变/etc/sysctl.conf中的值并执行sysctl-p或者使用文件系统写入一个新的值到/proc/sys/net里面的文件。搜索“TCPtuningguide”,可以找到很多好的在线教程。

然而,调整设置以有效地处理大量连接和小査询的情况通常更重要。比较常见的调整之一,就是要改变本地端口的范围。系统的默认值如下:

[root@server~]#cat/proc/sys/net/ipv4/ip_local_port_range3276861000有时你也许需要改变这些值,调整得更大一些。例如:

[root@server~]#echo102465535>/proc/sys/net/ipv4/ip_local_port_range如果要允许更多的连接进入队列,可以做如下操作:

GNU/Linux如今是髙性能MySQL最常用的操作系统,但是MySQL本身可以运行在很多操作系统上。

Solaris是SPARC硬件上的领跑者,在x86硬件上也可以运行。Solaris常用在要求高可靠的应用上面。Solaris在某些方面的易用性可能没有GNU/Linux的名气大,但确实是一个坚固的操作系统,包含许多先进的功能。尤其是Solaris10增加了ZFS文件系统,包含了很多先进的故障排除工具(如DTrace)、良好的多线程性能,以及称为SolarisZones的虚拟化技术,有助于资源管理。

FreeBSD是另一种选择。它历来与MySQL配合有一些问题,大多时候都涉及到线程支持,但新的版本要好得多。如今,看到MySQL在FreeBSD上大规模部署的场景并不是什么稀罕事。ZFS也可以在FreeBSD上使用。

通常用于开发和桌面应用程序的MySQL选择的是Windows。也有企业级的MySQL部署在Windows上,但一般的企业级MySQL更多的还是部署在类UNIX操作系统上。我们不希望引起任何有关操作系统的争论,需要指出的是在异构操作系统环境中使用MySQL是不存在问题的。在类UNIX的操作系统上运行的MySQL服务器,同时在Windows上运行Web服务器,然后通过高品质的.NET连接器(这是MySQL免费提供的)进行连接,这是一个非常合理的架构。从UNIX连接到Windows上的MySQL服务器和连接到另一台UNIX上的MySQL服务器一样简单。

文件系统的选择非常依赖于操作系统。在许多系统中,如Windows就只有一到两个选择,而且只有一个(NTFS)真的是能用的。比较而言,GNU/Linux则支持多种文件系统。

如果使用ext3或者其继承者ext4,有三个选项来控制数据怎么记日志,这可以放在/etc/fstab中作为挂载选项:

data=writeback

这个选项意味着只有元数据写入日志。元数据写入和数据写入并不同步。这是最快的配置,对InnoDB来说通常是安全的,因为InnoDB有自己的事务日志。唯一的例外是,崩溃时恰好导致.frm文件损坏了。

这里给出一个使用这个配置可能导致问题的例子。当程序决定扩展一个文件使其更大,元数据(文件大小)会在数据实际写到(更大的)文件之前记录并写下操作情况。结果就是文件的尾部——最新扩展的区域——会包含垃圾数据。

data=ordered

这个选项也只会记录元数据,但提供了一些一致性保证,在写元数据之前会先写数据,使它们保持一致。这个选项只是略微比writeback选项慢,但是崩溃时更安全。在此配置中,如果我们再次假设程序想要扩展一个文件,该文件的元数据将不能反映文件的新大小,直到驻留在新扩展区域中的数据被写到文件中了。

data=journal

此选项提供了原子日志的行为,在数据写入到最终位置之前将记录到日志中。这个选项通常是不必要的,它的开销远远高于其他两个选项。然而,在某些情况下反而可以提高性能,因为日志可以让文件系统延迟把数据写入最终位置的操作。

/dev/sda2/usr/lib/mysqlext3noatime,nodiratime,data=writeback01还可以调整文件系统的预读的行为,因为这可能也是多余的。例如,InnoDB有自己的预读策略,所以文件系统的预读就是重复多余的。禁用或限制预读对Solaris的UFS尤其有利。使用0_DIRECT选项会自动禁用预读。

一些文件系统可能不支持某些需要的功能。例如,若让InnoDB使用0_DIRECT刷新方式,文件系统能支持DirectI/O是非常重要的。此外,一些文件系统处理大量底层驱动器比其他的文件系统更好,举例来说XFS在这方面通常比ext3好。最后,如果打算使用LVM快照来初始化备库或进行备份,应该确认选择的文件系统和LVM版本能很好地协同工作。

表9-4某些常见文件系统的特性总结。

我们通常建议客户使用XFS文件系统。ext3文件系统有太多严重的限制,例如inode只有一个互斥变量,并且fsync()时会刷新所有脏块,而不只是单个文件。很多人感觉ext4文件系统用在生产环境有点太新了,不过现在似乎正日益普及。

可以用下面的命令来査看系统所有支持的以及当前在用的调度策略:

$cat/sys/block/sda/queue/schedulernoopdeadline[cfq]这里sda需要替换成想査看的磁盘的盘符。在我们的例子中,方括号表示正在使用的调度策略。cfq之外的两个选项都适合服务器级的硬件,并且在大多数情况下,它们工作同样出色。noop调度适合没有自己的调度算法的设备,如硬件RAID控制器和SAN。deadline则对RAID控制器和直接使用的磁盘都工作良好。我们的基准测试显示,这两者之间的差异非常小。重要的是别用cfq,这可能会导致严重的性能问题。

不过这个建议也需要有所保留的,因为磁盘调度策略实际上在不同的内核有很多不一样的地方,千万不能望文生义。

MySQL每个连接使用一个线程,另外还有内部处理线程、特殊用途的线程,以及所有存储引擎创建的线程。在MySQL5.5中,Oracle提供了一个线程池插件,但目前尚不清楚在实际应用中能获得什么好处。

无论哪种方式,MySQL都需要大量的线程才能有效地工作。MySQL确实需要内核级线程的支持,而不只是用户级线程,这样才能更有效地使用多个CPU。另外也需要有效的同步原子,例如互斥变量。操作系统的线程库必须提供所有的这些功能。

GNU/Linux提供两个线程库:LinuxThreads和新的原生POSIX线程库(NPTL)。LinuxThreads在某些情况下仍然使用,但现在的发行版已经切换到NPTL,并且大部分应用已经不再加载LinuxThreads。NPTL更轻量,更高效,也不会有那些LinuxThreads遇到的问题。

FreeBSD会加载许多线程库。从历史上看,它对线程的支持很弱,但现在已经变得好多了,在一些测试中,甚至优于SMP系统上的GNU/Linux。在FreeBSD6和更新版本,推荐的线程库是libthr,早期版本使用的linuxthreads,是FreeBSD从GNU/Linux上移植的LinuxThreads库。

通常,线程问题都是过去的事了,现在GNU/Linux和FreeBSD都提供了很好的线程库。

Solaris和Windows—直对线程有很好的支持,尽管直到5.5发布之前,MyISAM都不能在Windows下很好地使用线程,但5.5里有显著的提升。

当操作系统因为没有足够的内存而将一些虚拟内存写到磁盘就会发生内存交换。内存交换对操作系统中运行的进程是透明的。只有操作系统知道特定的虚拟内存地址是在物理内存还是硬盘。

内存交换对MySQL性能影响是很糟糕的。它破坏了缓存在内存的目的,并且相对于使用很小的内存做缓存,使用交换区的性能更差。MySQL和存储引擎有很多算法来区别对待内存中的数据和硬盘上的数据,因为一般都假设内存数据访问代价更低。

因为内存交换对用户进程不可见,MySQL(或存储引擎)并不知道数据实际上已经移动到磁盘,还会以为在内存中。

结果会导致很差的性能。例如,若存储引擎认为数据依然在内存,可能觉得为“短暂”的内存操作锁定一个全局互斥变量(例如InnoDB缓冲池Mutex)是0K的。如果这个操作实际上引起了硬盘I/O,直到I/O操作完成前任何操作都会被挂起。这意味着内存交换比直接做硬盘I/O操作还要糟糕。

在GNU/Linux上,可以用vmstat(在下一部分展示了一些例子)来监控内存交换。最好查看si和so列报告的内存交换I/O活动,这比看swpd列报告的交换区利用率更重要。swpd列可以展示那些被载入了但是没有被使用的进程,它们并不是真的会成为问题。我们喜欢si和so列的值为0,并且一定要保证它们低于每秒10个块。

绝不要让系统的虚拟内存溢出!对交换空间利用率做好监控和报警。如果不知道需要多少交换空间,就在硬盘上尽可能多地分配空间,这不会对性能造成冲击,只是消耗了硬盘空间。有些大的组织清楚地知道内存消耗将有多大,并且内存交换被非常严格地控制,但是对于只有少量多用途的MySQL实例,并且工作负载也多种多样的环境,通常不切实际。如果后者的描述更符合实际情况,确认给服务器一些“呼吸”的空间,分配足够的交换空间。

在特别大的内存压力下经常发生的另一件事是内存不足(OOM),这会导致踢掉和杀掉一些进程。在MySQL进程这很常见。在另外的进程上也挺常见,比如SSH,甚至会让系统不能从网络访问。可以通过设置SSH进程的oom_adj或oom_score_adj值来避免这种情况。

可以通过正确地配置MySQL缓冲来解决大部分内存交换问题,但是有时操作系统的虚拟内存系统还是会决定交换MySQL的内存。这通常发生在操作系统看到MySQL发出了大量I/0,因此尝试增加文件缓存来保存更多数据时。如果没有足够的内存,有些东西就必须被交换出去,有些可能就是MySQL本身。有些老的Linux内核版本也有一些适得其反的优先级,导致本不应该被交换的被交换出去,但是在最近的内核都被缓解了。

有些人主张完全禁用交换文件。尽管这样做有时在某些内核拒绝工作的极端场景下是可行的,但这降低了操作系统的性能(在理论上不会,但是实际上会的)。同时这样做也是很危险的,因为禁用内存交换就相当于给虚拟内存设置了一个不可动摇的限制。如果MySQL需要临时使用很大一块内存,或者有很耗内存的进程运行在同一台机器(如夜间批量任务),MySQL可能会内存溢出、崩溃,或者被操作系统杀死。

操作系统通常允许对虚拟内存和I/O进行一些控制。我们提供过一些GNU/Linux上控制它们的办法。最基本的方法是修改/proc/sys/vm/swappiness为一个很小的值,例如0或1。这告诉内核除非虚拟内存完全满了,否则不要使用交换区。下面是如何检査这个值的例子:

$cat/proc/sys/vm/swappiness60这个值显示为60,这是默认的设置(范围是0100)。对服务器而言这是个很糟糕的默认值。这个值只对笔记本适用。服务器应该设置为0:

$echo0>/proc/sys/vm/swappiness另一个选项是修改存储引擎怎么读取和写入数据。例如,使用innodb_flush_method=0_DIRECT,减轻I/O压力。DirectI/O并不缓存,因此操作系统并不能把MySQL视为增加文件缓存的原因。这个参数只对InnoDB有效。你也可以使用大页,不参与换入换出。这对MyISAM和InnoDB都有效。

另一个选择是使用MySQL的memlock配置项,可以把MySQL锁定在内存。这可以避免交换,但是也可能带来危险:如果没有足够的可锁定内存,MySQL在尝试分配更多内存时会崩溃。这也可能导致锁定的内存太多而没有足够的内存留给操作系统。

很多技巧都是对于特定内核版本的,因此要小心,尤其是当升级的时候。在某些工作负载下,很难让操作系统的行为合情合理,并且仅有的资源可能让缓冲大小达不到最满意的值。

操作系统会提供一些帮助发现操作系统和硬件正在做什么的工具。在这一节,我们会展示一些例子,包括关于怎样使用两个最常用的工具——iostat和vmstat。如果系统不提供它们中的任何一个,有可能提供了相似的替代品。因此,我们的目的不是让大家熟练使用如iostat和vmstat,而是告诉你用类似的工具诊断问题时应该看什么指标。

除了这些,操作系统也许还提供了其他的工具,如mpstat或者sar。如果对系统的其他部分感兴趣,例如网络,你可能希望使用ifconfig(除了其他信息,它能显示发生了多少次网络错误)或者netstat。

默认情况下,vmstat和iostat只是生成一个报告,展示自系统启动以来很多计数器的平均值,这其实没什么用。然而,两个工具都可以给出一个间隔参数,让它们生成增量值的报告,展示服务器正在做什么,这更有用。(第一行显示的是系统启动以来的统计,通常可以忽略这一行。)

先看一个vmstat的例子。用下面的命令让它每5秒钟打印出一个报告:

$vmstat5procs-----------memory-------------swap-------io-----system------cpu----rbswpdfreebuffcachesisobiboincsussyidwa00263225728231767402440052752111310186300263227808231807382480024302226620970可以用Ctrl+C停止vmstat。可以看到输出依赖于所用的操作系统,因此可能需要阅读一下手册来解读报告。

刚启动不久,即使采用增量报告,第一行的值还是显示自系统启动以来的平均值,第二行开始展示现在正在发生的情况,接下来的行会展示每5秒的间隔内发生了什么。每一列的含义在头部,如下所示:

procs

r这一列显示了多少进程正在等待CPU,b列显示多少进程正在不可中断地休眠(通常意味着它们在等待I/0,例如磁盘、网络、用户输入,等等)。

memory

swpd列显示多少块被换出到了磁盘(页面交换)。剩下的三个列显示了多少块是空闲的(未被使用)、多少块正在被用作缓冲,以及多少正在被用作操作系统的缓存。

swap

这些列显示页面交换活动:每秒有多少块正在被换入(从磁盘)和换出(到磁盘)。它们比监控swpd列重要多了。

io

这些列显示有多少块从块设备读取(bi)和写出(bo)。这通常反映了硬盘I/O。

system

这些列显示了每秒中断(in)和上下文切换(cs)的数量。

cpu

vmstat的输出跟系统有关,所以如果看到跟我们展示的例子不同的输出,应该阅读系统的vmstat(8)手册。一个重要的提示是:内存、交换区,以及I/O统计是块数而不是字节。在GNU/Linux,块大小通常是1024字节。

现在让我们转移到iostat。默认情况下,它显示了与相同的CPU使用信息。我们通常只是对I/O统计感兴趣,所以使用下面的命令只展示扩展的设备统计:

$iostat-dx5Device:rrqm/swrqm/sr/sw/srsec/swsec/savgrq-szavgqu-szawaitsvctm%utilsda1.62.82.51.8138.836.940.70.123.26.02.6与vmstat—样,第一行报告显示的是自系统启动以来的平均值(通常删掉它节省空间),然后接下来的报告显示了增量的平均值,每个设备一行。

有多种选项显示和隐藏列。官方文档有点难以理解,因此我们必须从源码中挖掘真正显示的内容是什么。说明的列信息如下:

rrqm/s和wrqm/s

每秒合并的读和写请求。“合并的”意味着操作系统从队列中拿出多个逻辑请求合并为一个请求到实际磁盘。

r/s和w/s

每秒发送到设备的读和写请求。

rsec/s和wsec/s

每秒读和写的扇区数。有些系统也输出为rkB/s和wkB/s,意为每秒读写的千字节数。

为了简洁,我们省略了那些指标说明。

avgrq-sz

请求的扇区数。

avgqu-sz

在设备队列中等待的请求数。

await

磁盘排队上花费的毫秒数。很不幸,iostat没有独立统计读和写的请求,它们实际上不应该被一起平均。当你诊断性能案例时这通常很重要。

svctm

%Util

concurrency=(r/s+w/s)*(svctm/1000)这是一个iostat的输出示例:

Device:rrqm/swrqm/sr/sw/srsec/swsec/savgrq-szavgqu-szawaitsvctm%utilsda1053112988203236905210127113996把数字带入并发公式,可以得到差不多9.6的并发性。这意味着在一个采样周期内,这个设备平均要服务9.6次的请求。例子来自于一个10块盘的RAID10卷,所以操作系统对这个设备的并行请求运行得相当好。另一方面,这是一个出现串行请求的设备:

Device:rrqm/swrqm/sr/sw/srsec/swsec/savgrq-szavgqu-szawaitsvctm%utilsdc8102800316401127399并发公式展示了这个设备每秒只处理一个请求。两个设备都接近于满负荷利用,但是它们的性能表现完全不一样。如果设备一直都像这些例子展示的一样忙,那么应该检査一下并发性,不管是不是接近于设备中的物理盘数,都需要注意。更低的值则说明有如文件系统串行的问题,就像我们前面讨论的。

我们展示vmstat和iostat(是因为它们部署最广泛,并且vmstat通常默认安装在许多类UNIX操作系统上。然而,每种工具都有自身的限制,例如莫名奇妙的度量单位、当操作系统更新统计时取样间隔不一致,以及不能一次性看到所有重要的点。如果这些工具不能符合需求,你可能会对dstat和collectl感兴趣。

我们也喜欢用mpstat来观察CPU统计;它提供了更好的办法来观察CPU每个工作是如何进行的,而不是把它们搅在一块。有时在诊断问题时这非常重要。当分析硬盘I/O利用的时候,blktrace可能也非常有用。

还有一个pt-diskstats,这是PerconaToolkit的一部分。它解决了一些对iostat的抱怨,例如显示读写统计的方式,以及缺乏对并发量的可见性。它也是交互式的,并且是按键驱动的,所以可以放大缩小、改变聚集、过滤设备,以及显示和隐藏列。即使没有安装这个工具,也可以通过简单的Shell脚本来收集一些硬盘统计状态,这个工具也支持分析这样采集出来的文本。可以抓取一些硬盘活动样本,然后发邮件或者保存起来,稍后分析。实际上,之前介绍的pt-stalk、pt-collect、pt-sift三件套,都被设计得可以跟pt-diskstats很好地配合。

$vmstat5procs-----------memory-------------swap-------io------system------cpu----rbswpdfreebuffcachesisobiboincsussyidwa102740880192564606813719952002788110471423145088944311074088019692461441370294400290714073150423045905237174088020460462641368385200355415567151324182885331027408802229246324136703960026401635115201743688443注意,这里也有合理数量的上下文切换(在CS列),除非每秒超过100000次或更多,一般都不用担心上下文切换。当操作系统停止一个进程转而运行另一个进程时,就会产生上下文切换。

例如,一査询语句在MyISAM上执行了一个非覆盖索引扫描,就会先从索引中读取元素,然后根据索引再从磁盘上读取页面。如果页面不在操作系统缓存中,就需要从磁盘进行物理读取,这就会导致上下文切换中断进程处理,直到I/O完成。这样一个査询可以导致大量的上下文切换。

如果我们在同一台机器观察iostat的输出(再次剔除显示启动以来平均值的第一行),可以发现磁盘利用率低于50%:

$iostat-dx5Device:rrqm/swrqm/sr/sw/srsec/swsec/savgrq-szavgqu-szawaitsvctm%utilsda03859544582063345467136147dm-0005443162063345328184047Device:rrqm/swrqm/sr/sw/srsec/swsec/savgrq-szavgqu-szawaitsvctm%utilsda02898523631767260906737145dm-0005232611767260908155045这台机器不是I/O密集型的,但是依然有相当数量的I/O发生,在数据库服务器中这种情况很少见。另一方面,传统的Web服务器会消耗大量CPU资源,但是很少发生I/0,所以Web服务器的输出不会像这个例子。

$vmstat5procs-----------memory-------------swap-------io------system------cpu----rbswpdfreebuffcachesisobiboincsussyidwa57740632226844321213466436006738172221738166481931563577406322274843396134654360061501702517311671318421581874063222380434161346419200458221820169315211164245656740632221164351213463484005955211581732161871742356这台机器的iostat输出显示硬盘一直很忙:

$iostat-dx5Device:rrqm/swrqm/sr/sw/srsec/swsec/savgrq-szavgqu-szawaitsvctm%utilsda053962026267319481876612141101dm-000202601673194813085790101Device:rrqm/swrqm/sr/sw/srsec/swsec/savgrq-szavgqu-szawaitsvctm%utilsda058101846656441518256811131102dm-000183647764415181785470102%util的值可能因为四舍五入的错误超过100%。什么迹象意味着机器是I/O密集的呢?只要有足够的缓冲来服务写请求,即使机器正在做大量的写操作,也可能可以满足,但是却通常意味着硬盘可能会无法满足读请求。这听起来好象违反直觉,但是如果思考读和写的本质,就不会这么认为了:

想想这种方式:你可以发出一个写请求到缓冲区的某个地方,然后过一会完成。甚至可以每秒发出很多这样的请求。如果缓冲区正确工作,并且有足够的空间,每个请求都可以很快完成,并且实际上写到物理硬盘是被重新排序后更有效地批量操作的。然而,没有办法对读操作这么做一不管多小或多少的请求,都不可能让硬盘响应说“这是你的数据,我等一会读它”。这就是为什么读需要I/O等待是可以理解的原因。

一台正在发生内存交换的机器可能在swpd列有一个很高的值,也可能不高。但是可以看到si和so列有很髙的值,这是我们不希望看到的。下面是一台内存交换严重的机器的vmstat输出:

$vmstat5rbswpdfreebuffcachesisobiboincsussyidwa411379793621268270681451932415913308704051330924360071916113647procs-----------memory----------------swap---------io------system------cpu----01037942922443627076144127641985397815787498334084833961458220373847364207642711214547112171388152235839146241746406897

$vmstat5procs-----------memory-------------swap-------io------system-------cpu------rbswpdfreebuffcachesisobiboincsussyidwast00108492556676836009200345209265209710001084925566772360088000143571900100000010849255667763600840006355160010000

为MySQL选择和配置硬件,以及根据硬件配置MySQL,并不是什么神秘的艺术。通常,对于大部分目标需要的都是相同的技巧和知识。当然,也需要知道一些MySQL特有的特点。

我们通常建议大部分人在性能和成本之间找到一个好的平衡点。首先,出于多种原因,我们喜欢使用廉价服务器。举个例子,如果在使用服务器的过程中遇到了麻烦,并且在诊断时需要停止服务,或者希望只是简单地把出问题的服务器用另一台替换,如果使用的是一台$5000的廉价服务器,肯定比使用一台超过$50000或者更贵的服务器要简单得多。MySQL通常也更适应廉价服务器,不管是从软件自身而言还是从典型的工作负载而言。

MySQL需要的四种基本资源是:CPU、内存、硬盘以及网络资源。网络一般不会作为很严重的瓶颈出现,而CPU、内存和磁盘通常是主要的瓶颈所在。对MySQL而言,通常希望有很多快速CPU可以用,但如果必须在快和多之间做选择,则一般会选择更快而不是更多(其他条件相同的情况下)。

持久化存储的选择本质上归结为三个选项,以提高性能的次序排序:SAN、传统硬盘,以及固态存储设备。

固态存储设备可以很大地提升服务器整体性能。有时候一个不算昂贵的SSD,可以帮助解决经常在传统硬盘上遇到的特定工作负载的问题,如复制。如果真的需要很强的性能,应该使用PCIe设备。增加高速I/O设备会把服务器的性能瓶颈转移到CPU,有时也会转移到网络。

MySQL和InnoDB并不能完全发挥高端固态存储设备的性能,并且在某些场景下操作系统也不能发挥。但是提升依然很明显。PerconaServer对固态存储做了很多改进,并且很多改进在5.6发布时已经进入了MySQL主干代码。

THE END
1.回收来的旧家电都去哪儿了?听听原标题:回收来的旧家电都去哪儿了?记者探访废旧家电处理全流程 央广网北京12月1日消息 从2019年在某平台卖出第一件闲置物品开始,五年来,傅女士已卖出了近百件旧商品,包括蓝牙音箱等小家电。就在最近,她换了一种方式,趁着这波“以旧换新”热潮,为家里置换了冰箱、洗衣机等大家电,“通过参加‘以旧换新’活动https://www.workercn.cn/c/2024-12-02/8404899.shtml
2.央视曝光:旧家电进入废品回收站后去哪里了?无证回收网点随意处理废家电 在很多城市的住宅小区的门口,都可以看到骑着三轮车收废家电的商贩,老百姓把家中淘汰下来的废家电都卖给了这些小商贩,小商贩们又将收来的废家电转卖给了社区周边的回收网点。据了解,一部分废家电被这些回收网点直接拆解了,之后再卖铁,卖铝。 https://m.feipinzhan.com/news/show-7.html
3.丽水小家电库存回收丽水小家电库存交易平台中山市东凤镇德力冠电器,主营厨卫电器,家电库存,电器库存回收,电器库存,小家电库存,电器库存回收,库存家电,库存小家电,厨卫库存,厨卫电器库存等业务.凭借数十年的库存回收行业经验实现了与全国客商有业务往来,为客户提供整单,高品质,低价格的超值产品。http://www.deliguan.com/lishui.html
4.上海松下小家电回收,松下库存电器回收公司价格厂家小家电,电饭煲回收,电磁炉回收,电水壶风扇回收,上海宾馆设备回收 上海厨房用品回收,上海酒店设备回收 上海宾馆设备回收 上海厨房用品回收 经营范围; 制冷设备:向企事业单位公司求购各种品牌旧中央空调风冷,水冷机组,型号规格不限。 一匹至十匹(挂壁式、柜式、吸顶式)空调。冷冻设备、冷库、冰柜、制冰机、除湿机等大中https://www.china.cn/minidianfanbao/4249070954.html
5.“换”醒环保意识,家电回收服务进社区负责回收的工作人员耐心向居民介绍规则。7月25日,在朝阳区和平家园社区小公园,和平街街道办事处联合和平家园社区、和平家园北社区以及北京天一绿洲再生资源回收有限公司组织开展了一场“家电回收 以物换礼”小旧家电回收垃圾分类宣传活动。一上午时间,60余位居民把自家75件闲置小家电置换成了常用的生活用品,满载而归。https://news.sina.cn/2023-07-25/detail-imzcwxhq1125318.d.html
6.处理一批库存小家电,我是一般纳税人企业现已批低价处理库存商品该临沂家电城(八路西面和聚财路交汇),经营和回收大、小家电以及元器件。经营户很多。你都有什么品种,可以给你推荐。 丹东收垃圾的都代收家电。有一些家电,专门的电器维修店也收购。然后拆解后卖件。丹东收垃圾的人基本都是河南驻马店人,以驻马店市上蔡县的人为多。这个地方是中国著名的adis病之乡,知道什么是adis吧。http://www.jiebohui.com/znjd/jdwd/206988.html
7.爱裹旧衣回收有偿回收环保低碳小家电回收 1.我的衣服不足3KG怎么回收? 不满足3KG,运费成本很高暂不回收,还请您多积累一段时间再下单哦。旧衣服重量不足3KG时,平台不做返现,也不发放蚂蚁森林能量 2.回收完成后现金如何领取? 3.旧衣回收需要自己打包么? 4.回收需要客户支付运费吗? http://www.aiguo.tech/
8.京东小家电华北回收分拣中心正式成立或将促进产业绿色发展随着京东小家电回收生态链的逐步完善,将进一步促进小家电产品的流转和经济的发展,处理大量闲置物资,优化社会资源配置。同时,依托京东物流覆盖全国存储、运输、配送能力,保证更短的物流时间和足够大量的回收产品货源供给,提升回收效率降低回收成本,并将此回馈给用户,促进小家电再循环产业链的逐步完善,助力我国「双碳」目标https://www.iyiou.com/news/202405251067701
9.“以旧换新”的春风将至,家里的闲置家电有了好去处杭州新闻中心小家电流通快、大家电回收难 线下二手市场有晴有雨 除了线上,售卖二手家电,还有不少人热衷去线下店逛逛。 1月28日,在拱墅区锦鸿街,杭州首家闲鱼循环商店开启试营业。从开业第一天就爆单,到成为社交平台上的热门打卡点,小小的实体店吸引许多人慕名来到这里。 https://hznews.hangzhou.com.cn/jingji/content/2024-03/15/content_8701631_2.htm
10.这里有14个回收渠道分享!闲置换钱花,一年回血好几千潮流消费1.大家电回收涉及到拆机,相对来说比较麻烦 京东转转算是做的比较好的,可以不收费上门拆机~2.如果https://go.cqmmgo.com/forum-5-thread-78431649222771780-showthread-26561542-puid-26561542-1-1.html
11.关于大学生二手小家电市场的调查问卷亲爱的同学: 您好!我们是华南师范大学社区废旧小家电公益维修与回收项目小组,此次问卷是希望了解您对购买二手小家电的看法以及处理小家电的方式,进而研究本项目的存在意义。希望得到您的支持和配合,谢谢您!*1. 您是否有购买二手小家电的经历? 有 没有 *2. 根据您的了解,您身边的同学使用二手小家电的情况是? 非常https://www.wjx.cn/jq/4111453.aspx
12.湖南同力环保科技有限公司“四机一脑”改建及小家电拆解续建项目3 ()本项目在总图布置、设计上充分利用现有场地和现 有办公生活、交通、供电、供水等设施,不新占用土地。根 据生产规模,“四机一脑”改建部分利用现有生产线及生产设 备进行生产,小家电续建项目利用现有已建设闲置车间安装 设备及生产线进行生产,总体建设条件良好,无需新增土建 工程。 项目选址地区交通运输条件良好,https://max.book118.com/html/2023/0914/5020220104010330.shtm
13.二手家电市场闲置变现探秘今日二手家电市场的繁荣与挑战另一边,在北京朝阳区,有个名叫王女士,她是一位热衷于收集二手电子产品的小资本家。她常常会去各大街头巷尾寻找那些即将被拆迁户所遗弃或是废弃的小件设备,然后通过网上平台或者实体店销售。王女士表示:“现在很多人都知道回收利用比直接丢弃更环保,而且还能赚点钱,所以这些东西总是有人要。” https://www.3oh2lnsk.com/xiao-jia-dian/411732.html
14.家电回收的微博家电回收,微博钱包家电回收业务官方微博。家电回收的微博主页、个人资料、相册。新浪微博,随时随地分享身边的新鲜事儿。https://weibo.com/u/7646512025?is_all=1
15.(家电企业管理)家电以前家电行业大致分为白色家电、黑色家电、小家电、IT通讯产品等领 域。而今,这种单一的划分现在已很难框住很多企业,白电生产企业进入黑电 领域,黑电生产企业进入白电领域,大家电企业生产小家电,小家电企业生产 大家电,IT企业生产家电,家电企业生产手机,已经成为一种趋势。已很少有 企业固守某一个生产领域,而越来越多https://doc.mbalib.com/view/3a8477e975824270a70980c2cd464854.html