硬盘对数据库性能的影响
传统机械硬盘
当前大多数数据库使用的都是传统的机械硬盘。机械硬盘的技术目前已非常成熟,在服务器领域一般使用SAS或SATA接口的硬盘。服务器机械硬盘开始向小型化转型,目前已经有大量2.5寸的SAS机械硬盘。
机械硬盘有两个重要的指标:一个是寻道时间,另一个是转速。当前服务器机械硬盘的寻道时间已经能够达到3ms,转速为15 000rpm。传统机械硬盘最大的问题在于读写磁头,读写磁头的设计使得硬盘可以不再像磁带一样,只能进行顺序访问,而是可以随机访问。但是,硬盘的访问需要耗费长时间的磁头旋转和定位来查找,因此顺序访问的速度远远高于随机访问。数据库的很多设计也都是在尽量充分地利用顺序访问的特性。
可以将多块硬盘组成RAID来提高数据库的性能,也可以将数据文件分布在不同硬盘上来达到访问负载的均衡。
固态硬盘
固态硬盘,更准确地说是基于闪存的固态硬盘,是近几年出现的一种新的存储设备,其内部由闪存(Flash Memory)组成。因为闪存的低延迟性、低功耗以及防震性,所以闪存设备已在移动设备上得到了广泛的应用。企业级应用一般使用固态硬盘,通过并联多块闪存来进一步提高数据传输的吞吐量。传统的存储服务提供商EMC公司已经开始提供基于闪存的固态硬盘的TB级别存储解决方案。数据库厂商Oracle公司最近也开始提供绑定固态硬盘的Exadata服务器。
不同于传统的机械硬盘,闪存是一个完全的电子设备,没有传统机械硬盘的读写磁头。因此,固态硬盘不需要像传统机械硬盘一样,需要耗费大量时间的磁头旋转和定位来查找数据,所以固态硬盘可以提供一致的随机访问时间。固态硬盘这种对数据的快速读写和定位特性是值得研究的。
另一方面,闪存中的数据是不可以更新的,只能通过扇区(sector)的覆盖重写,而在覆盖重写之前,需要执行非常耗时的擦除(erase)操作。擦除操作不能在所含数据的扇区上完成,而是需要擦除整个被称为擦除块的基础上,这个擦除块的尺寸大于扇区的大小,通常为128KB。此外,每个擦除块有擦写次数的限制。已经有一些算法来解决这个问题。但是对于数据库应用,需要认真考虑固态硬盘在写入方面存在的问题。
因为存在上述写入方面的问题,闪存提供的读写速度是非对称的。读取速度要远快于写入的速度,因此对于固态硬盘在数据库中的应用,应该好好利用其读取的性能,避免过多的写入操作。
下图显示了一个双通道的固态硬盘架构,通过支持4路的闪存交叉存储来降低固态硬盘的访问延时,同时增大并发的读写操作。通过进一步增加通道的数量,固态硬盘的性能可以线性地提高,如我们常见的Intel X-25M固态硬盘就是10通道的固态硬盘。
因为闪存是一个完全的电子设备,没有读写磁头等移动部件,因此固态硬盘有着较低的访问延时。当主机发布一个读写请求时,固态硬盘的控制器会把I/O命令从逻辑地址映射成实际的物理地址,写操作还需要修改相应的映射表信息。算上这些额外的开销,固态硬盘的访问延时一般小于0.1ms左右。
下图显示了传统机械硬盘、内存、固态硬盘的随机访问延时之间的比较:
对于固态硬盘在InnoDB存储引擎中的优化,可以增加innodb_io_capacity变量的值,以达到充分利用固态硬盘带来的高IOPS的特性。同时也可以通过修改源代码来禁用InnoDB存储引擎的预读、邻接页的写入特性。
合理地设置RAID
RAID类型
RAID(Redundant Array of Independent Disks,独立磁盘冗余数组)的基本思想,就是把多个相对便宜的硬盘组合起来,成为一个磁盘数组,使性能达到甚至超过一个价格昂贵、容量巨大的硬盘。由于将多个硬盘组合成为一个逻辑扇区,RAID看起来就像一个单独的硬盘或逻辑存储单元,因此操作系统只会把它当作一个硬盘。
RAID的作用是:
- 增强数据集成度
- 增强容错功能
- 增加处理量或容量
根据不同磁盘的组合方式,常见的RAID组合方式可分为RAID 0、RAID 1、RAID 5、RAID 10和RAID 50等。
(1)RAID 0:将多个磁盘合并成一个大的磁盘,不会有冗余,并行I/O,速度最快。RAID 0亦称为带区集,它是将多个磁盘并列起来,使之成为一个大磁盘。在存放数据时,其将数据按磁盘的个数来进行分段,然后同时将这些数据写进这些盘中。所以,在所有的级别中,RAID 0的速度是最快的。但是RAID 0没有冗余功能,如果一个磁盘(物理)损坏,则所有的数据都会丢失。理论上,多磁盘的效能就等于[单一磁盘效能]x[磁盘数],但实际上受限于总线I/O瓶颈及其他因素的影响,所以RAID效能会随边际递减。也就是说,假设一个磁盘的效能是50MB/秒,两个磁盘的RAID 0效能约96MB/秒,三个磁盘的RAID 0也许是130MB/秒,而不是150MB/秒。
(2)RAID 1:两组以上的N个磁盘相互作为镜像,在一些多线程操作系统中能有很好的读取速度,但写入速度略有降低。除非拥有相同数据的主磁盘与镜像同时损坏,否则只要一个磁盘正常,即可维持运作,因此可靠性最高。RAID 1就是镜像,其原理为,在主硬盘上存放数据的同时也在镜像硬盘上写一样的数据。当主硬盘(物理)损坏时,镜像硬盘则代替主硬盘的工作。因为有镜像硬盘做数据备份,所以RAID 1的数据安全性在所有的RAID级别中是最好的。但是,无论用多少磁盘,作为RAID 1,仅算一个磁盘的容量,所以RAID1是所有RAID中磁盘利用率最低的一个级别。
(3)RAID 5:是一种存储性能、数据安全和存储成本兼顾的存储解决方案。它使用的是Disk Striping(硬盘分区)技术。RAID 5至少需要三个硬盘,RAID 5不对存储的数据进行备份,而是把数据和相对应的奇偶校验信息存储到组成RAID 5的各个磁盘上,并且奇偶校验信息和相对应的数据分别存储于不同的磁盘上。当RAID 5的一个磁盘数据发生损坏后,利用剩下的数据和相应的奇偶校验信息去恢复被损坏的数据。RAID 5可以理解为是RAID 0和RAID 1的折中方案。RAID 5可以为系统提供数据安全保障,但保障程度要比镜像低,而磁盘空间利用率要比镜像高。RAID 5具有和RAID 0相近似的数据读取速度,只是多了一个奇偶校验信息,所以写入数据的速度相当慢,若使用Write Back可以让性能改善不少。同时,由于多个数据对应一个奇偶校验信息,因此RAID 5的磁盘空间利用率要比RAID 1高,存储成本相对较低。
(4)RAID 10和RAID 01:RAID 10是先镜射,再分区数据。它将所有硬盘分为两组,视为RAID 0的最低组合,然后将这两组各自视为RAID 1运作。RAID 10有着不错的读取速度,而且拥有比RAID 0更高的数据保护性。RAID 01则与RAID 10的程序相反,是先分区,再将数据镜射到两组硬盘。它将所有的硬盘分为两组,变成RAID 1的最低组合,而将两组硬盘各自视为RAID 0运作。RAID 01比起RAID 10有着更快的读写速度,不过也多了一些会让整个硬盘组停止运转的概率:因为只要同一组的硬盘全部损毁,RAID 01就会停止运作,而RAID 10则可以在牺牲RAID 0的优势下正常运作。RAID 10巧妙地利用了RAID 0的速度以及RAID 1的安全(保护)两种特性,它的缺点是需要较多的硬盘,因为至少必须拥有4个以上的偶数硬盘才能使用。
(5)RAID 50:RAID 50也被称为镜像阵列条带,由至少6块硬盘组成,像RAID 0一样,数据被分区成条带,在同一时间内向多块磁盘写入;像RAID 5一样,RAID 50也是以数据的校验位来保证数据的安全,且校验条带均匀分布在各个磁盘上,其目的在于提高RAID 5的读写性能。
对于数据库应用来说,RAID 10是最好的选择,它同时兼顾了RAID 1和RAID 0的特性。但是,当一个磁盘失效时,性能可能会受到很大的影响,因为条带(strip)会成为瓶颈,譬如:2台负载基本相同的数据库,一台正常的服务器磁盘IO负载为20%左右,而另一台服务器IO负载却高达90%。
RAID Write Back功能
RAID Write Back功能是指RAID控制器能够将写入的数据放入自身的缓存中,并把它们安排到后面再执行。这样做的好处是,不用等待物理磁盘实际写入的完成,因此写入变得更快了。对于数据库来说,这显得十分重要。例如,对重做日志的写入、在将sync_binlog设为1的情况下二进制日志的写入、脏页的刷新等,这些都可以使性能明显的提升。
但是,如果系统发生意外,Write Back功能可能会破坏数据库的数据,因为缓存可能还在RAID卡中,这样磁盘并没有写入时故障就发生了。对此,大部分的硬件RAID卡都提供了电池备份单元(BBU,Battery Backup Unit),因此可以放心地开启Write Back的功能。每台服务器的出厂设置都是不同的,应该将你的RAID设置要求告知服务器提供商,开启一些你认为需要的参数。
如果没有启用Write Back功能,那么在RAID卡设置中显示的就是Write Through。Write Through没有缓冲写入,因此写入性能可能不是很好,但它的确是最安全的写入。
即使开启了Write Back功能,RAID卡也可能只是启用了Write Through,之前提到过,安全使用Write Back的前提是RAID卡有电池备份单元。为了确保电池的有效性,RAID卡会定期检查电池状态,并在电池电量不足时对其充电,在充电的这段时间内,会将Write Back功能切换为最为安全的Write Through。
你可以在没有电池备份单元的情况下强制启用Write Back功能,也可以在电池充电时强制使用Write Back功能。只是写入是不安全的,你应该非常确信这点,否则不应该在没有电池备份单元的情况下启用Write Back。
可以通过插入20W的记录来比较Write Back和Write Through的性能差异:
create table t(a char(2)) engine=innodb;
delimiter //
create procedure p()
begin
declare v int;
set v=0;
while v<200000 do
insert into t values('aa');
set v=v+1;
end while;
end
//
delimiter;
我们创建了一个往t表插入20万条记录的存储过程,并在Write Back和Write Through的设置下分别进行测试,测试结果如表9-1所示:
我们的测试不是在一个事务中,而是直接用命令CALL P来运行的,因此数据库实际执行了20万次的事务。很明显可以看到,在Write Back模式下执行时间只需要43秒,而在Write Through模式下执行时间需要31分钟,大约是40多倍的差距。
当然,在Write Through模式下,通过将参数innodb_flush_log_at_trx_commit设置为0也可以提高执行存储过程P的性能,这时只需要68秒了。因为在此设置下,重做日志的写入不是发生在每次事务提交时,而是发生在后台master线程每秒钟自动刷新的时候,因此减少了物理磁盘的写入请求,所以执行速度也有明显的提高。
RAID配置工具
RAID卡的配置可以在服务器启动时进入一个类似于BIOS的配置界面,然后再对其进行各种设置。此外,很多厂商都开发了各种操作系统下的软件来进行RAID卡的配置,如果你使用的是LSI公司生产提供的RAID卡,则可以使用MegaCLI工具进行配置。
MegaCLI为多个操作系统提供了支持,在Windows下还提供了GUI界面的配置,相对来说比较简单。主要介绍命令行下MegaCLI的使用,Windows下可以使用MegaCLI.exe程序。
使用MegaCLI查看RAID卡的信息:
/opt/MegaRAID/MegaCli/MegaCli64 -AdpAllInfo -a0
用过上述命令,可以看到RAID卡的一些硬件设置,如这块RAID卡的型号是MegaRAID SAS 8708ELP,缓存大小是256MB,一些默认的配置,如默认启用的Write Policy为WB(Write Back)等。
MegaCLI还可以用来查看当前物理磁盘的信息:
/opt/MegaRAID/MegaCli/MegaCli64 -PDList -aALL
可以看到当前使用的磁盘型号是SEAGATE ST3300655SS。
你可以从这个型号继续找到这个硬盘的具体信息,如在希捷官网http://discountechnology.com/Seagate-ST3300655SS-SAS-Hard-Drive上可以知道,这块硬盘大小是3.5寸的,转速为15 000,硬盘的Cache为16MB,随机读取的寻道时间是3.5毫秒,随机写入的寻道时间是4.0毫秒等。
通过下面的命令来查看是否开启了Write Back功能:
/opt/MegaRAID/MegaCli/MegaCli64 -LDGetProp -Cache -LALL -aALL
Adapter 0-VD 0(target id:0):Cache Policy:WriteBack,ReadAheadNone,Direct,No Write Cache if bad BBU
Adapter 0-VD 1(target id:1):Cache Policy:WriteBack,ReadAheadNone,Direct,No Write Cache if bad BBU
Exit Code:0x00
可以看到当前开启了Write Back功能,并且当BBU有问题时或者在充电时禁用Write Back功能。这里还显示了不需要启用RAID卡的预读功能,写入为直接写入方式。
通过下面的命令可以对当前的写入策略进行调整:
/opt/MegaRAID/MegaCli/MegaCli64-LDSetProp WB -LALL -aALL
/opt/MegaRAID/MegaCli/MegaCli64-LDSetProp WT -LALL -aALL
注意:当写入策略从Write Back切换为Write Through时,该更改立即生效,但是从Write Through切换为Write Back时,必须重启服务器才能使其生效。
操作系统的选择也很重要
Linux是MySQL数据库服务器中最常见的操作系统。与其他操作系统不同的是,Linux有着众多的发行版本,可能每个人的偏好都不相同。但是,在将Linux操作系统作为数据库服务器时,需要考虑更多的是操作系统的稳定性,而不是新特性。
除了Linux操作系统外,FreeBSD也是另一个常见的操作系统。之前版本的FreeBSD对MySQL数据库支持得不是很好,需要选择单独的线程库进行手动编译,但是新版本的FreeBSD对MySQL数据库的支持已经好了很多,直接下载二进制安装包即可。
Solaris之前是基于SPARC硬件的操作系统,现在已经移植到了X86平台上。Solaris是高性能、高可靠性的操作系统,同时其提供的ZFS文件系统非常适合MySQL的数据库应用。如果需要,你可以尝试它的开源版本Open Solaris。
Windows在MySQL的数据库应用中也非常常见。也有的公司喜欢在开发环境下使用Windows版本的MySQL,到正式生产环境下使用Linux。这本身没有什么问题,但问题通常发生于大小写敏感方面。Windows下表名不区分大小写,而Linux操作系统却是大小写敏感的,这点在开发阶段需要特别注意。
4GB内存在当前已经非常普遍了,即使是桌面用户也开始使用8GB的内存。为了可以更好地使用大于4GB的内存容量,必须使用64位的操作系统,上述介绍的这些操作系统都提供了64位的版本。此外,使用64位的操作系统还必须使用64位的软件。这听上去是句废话,但是我多次看到32位的MySQL数据库安装在64位的系统上,而这样会导致不能充分发挥64位操作系统的寻址能力。
不同的文件系统对数据库性能的影响
每个操作系统都默认支持一种文件系统并推荐用户使用,如Windows默认支持NTFS,Solaris默认支持ZFS。而对于Linux这样的操作系统,不同发行版本默认支持的文件系统又各不相同,有的默认支持EXT3,有的是ReiserFS,有的是EXT4,有的是XFS。
虽然有着很多不同特性的文件系统,但是我在实际使用过程中从未感觉到文件系统的性能差异有多大。DBA应该把更多的注意力放到数据库上面,而不是纠结于文件系统。文件系统可提供的功能也许是DBA需要关注的,例如ZFS文件系统本身就可以支持快照,因此就不需要LVM这样的逻辑卷管理工具。此外,可能还需要知道mount的参数,这些参数在每个文件系统中又可能有所不同。