优化服务器设置
InnoDB的IO配置
双写缓冲(Doublewrite Buffer)
InnoDB用双写缓冲来避免页没写完整所导致的数据损坏。当一个磁盘写操作不能完整地完成时,不完整的页写入就可能发生,16KB的页可能只有一部分被写到磁盘上。有多种多样的原因(崩溃、Bug,等等)可能导致页没有写完整。双写缓冲区在这种秦广发生时可以保证数据完整性。
双写缓冲是表空间的一个特殊保留区域,在一些连续的块中足够保存100个页。本质上是一个最近写回的页面的备份拷贝。当InnoDB从缓冲池刷新页面到磁盘时,首先把它们写(或者刷新)到双写缓冲,然后再把它们写道其所属的数据区域中。这可以保证每个页面的写入都是原子并且持久化的。
这意味着每个页都要写两遍?是的,但是因为InnoDB写页面到双写缓冲是顺序的,并且只调用一次fsync()刷新到磁盘,所以实际上对性能的冲击是比较小的)通常只有几个百分点,肯定没有一半那么多,尽管这个开销在SSD上更明显。更重要的是,这个策略允许日志文件更加高效。因为双写缓冲给了InnoDB一个非常牢固的保证,数据页不会损坏,InnoDB日志记录没必要包含整个页,它们更像是页面的二进制变化量。
如果有一个不完整的页写到了双写缓冲,原始的页依然会在磁盘上它的真实位置,当InnoDB恢复时,它将用原始页面替换掉双写缓冲中的损坏页面。然而,如果双写缓冲成功写入,但写到页的真实位置失败了,InnoDB在恢复时将使用双写缓冲中的拷贝来替换。InnoDb知道什么时候页面损坏了,因为每个页面在末尾都有校验值(Checksum)。校验值时最后写道页面的东西,所以如果页面的内容跟校验值不匹配,说明这个页面是损坏的。因此,在恢复的时候,InnoDB只需要读取双写缓冲中每个页面并且验证校验值,如果一个页面的校验值不对,就从它的原始位置读取这个页面。
有些场景下,双写缓冲确实没必要——例如,你也许想在备库上进制双写缓冲。此外一些文件系统(例如ZFS)做了同样的事,所以没必要再让InnoDB做一遍。可以通过innodb_doublewrite为0来关闭双写缓冲。在Percona Server中,可以配置双写缓冲到独立的文件中,所以可以把这部分工作压力分离出来放在单独的磁盘上。
其他的IO配置项
sync_binlog选项控制MySQL怎么刷新二进制日志到磁盘。默认值是0(更新版本中是1),意味着MySQL并不刷新,由操作系统自己决定什么时候刷新缓存到持久化设备。如果这个值比0大,它制定了两次刷新到磁盘的动作之间间隔多少次二进制日志写操作(如果autocommit被设置了,每个独立的语句都是一次血,否则就是一个事务一次写)。把它设置为0和1以外的值是很罕见的。
如果没有设置sync_binlog为1,那么崩溃以后可能导致二进制日志没有同步事务数据。这可以轻易地导致复制中断,并且使得及时恢复变得不可能。无论如何,可以把这个值设置为1来获得安全地保障。这样就会要求MySQL同步把二进制日志和事务日志两个文件刷新到两个不同地位置。这可能需要要磁盘寻道,相对来说是个很慢的操作。
像InnoDB日志文件一样,把二进制日志放到一个带有电池保护的写缓存的RAID卷,可以极大地提升性能。事实上,写和刷新二进制日志缓存其实比InnoDB事务日志要昂贵多了,因为不像InnoDB事务日志,每次写二进制日志都会增加它们的大小。这需要每次写入文件系统都更新元信息。所以,设置sync_binlog=1可能比innodb_flush_log_at_trx_commit=1对性能你的损害要大得多,尤其是网络文件系统,例如NFS.
一个跟性能无关的提示,关于二进制日志:如果希望使用expire_logs_days选项来自动清理旧的二进制日志,就不要用rm命令去删。服务器会感到困惑并且拒绝自动删除它们,并且PURGE MASTER LOGS也将停止工作。解决的办法是,如果发现了这种情况,就手动重新同步"主机名-bin.index"文件,可以用磁盘上现有日志文件的列表来更新。
把带有电池保护写缓存的高质量RAID控制器设置为使用写回(Writeback)策略,可以支持每秒数千的写入,并且依然会保证写到持久化存储。数据写到了带有电池的高速缓存,所以即使系统断电它也能存在。但电源恢复时,RAID控制器会在磁盘被设置可用前,把数据从缓存中写到磁盘。因此,一个带有电池保护写缓存的RAID控制器可以显著地提升性能,,这是非常值得的投资。当然,SSD存储是另一个选择。
MyISAM的IO配置
让我们从分析MyISAM怎么为索引操作IO开始。MyISAM通常每次操作之后就把索引变更刷新磁盘。如你打算在一张表上做很多修改,那么毫无疑问,批量操作会更快一些,一种办法是用LOCK TABLES延迟写入,知道解锁这些表。这是个提升性能的很有价值的技巧,因为它使得你精确控制哪些写被延迟,以及什么时候把它们刷到磁盘。可以精确延迟那些希望延迟的语句。
通过设置delay_key_write变量,也可以延迟索引的写入。如果这么做,修改的键缓冲块直到表被关闭才会刷新。(表可能因为多种原因被关闭。例如,服务器因为表缓存没有空间了就会关闭表,或者有人执行了FLUSH TABLES).可能的配置如下:
- 1.OFF
MyISAM每次写操作后刷新键缓冲(键缓存,Key Buffer)中的脏块到磁盘,除非表被LOCK TABLES锁定了 - 2.ON
打开延迟键写入,但是只对用DELAY_KEY_WRITE选项创建的表有效 - 3.ALL
所有的MyISAM表都会使用延迟键写入
延迟键写入在某些场景下可能很有帮助,但是通常不会带来很大的性能提升。但键缓冲的杜明中很好但谢明中不好时,数据又比较小,这可能很有用。当然也有一小部分缺点:
- 1.如果服务器缓存并且块没有被刷到磁盘,索引可能会损坏
- 2.如果很多写被延迟了,MySQL可能需要花费更长时间去关闭表,因为必须等待缓冲刷新到磁盘。在MySQL5.0这可能引起很长的表缓存锁
- 3.由于上面提到的原因,FLUSH TABLES可能需要很长时间。如果为了做逻辑卷(LVM)快照或者其他备份操作,而执行FLUSH TABLE WITH READ LOCK,那可能增加操作的时间
- 4.键缓冲中没有刷灰去的脏块可能占用空间,导致从磁盘上读取的新块没有空间存放,因此,查询语句可能需要等待MyISAM释放一些键缓存的空间。
另外,除了配置MyISAM的索引IO还可以配置MyISAM怎样尝试从损坏中恢复,myisam_recover选项控制MyISAM怎样寻找和修复错误。需要在配置文件或者命令中设置这个选项。可以通过下面的SQL语句查看选项的值,但是不能修改
mysql>SHOW VARIBLES LIKE 'myisam_recover_options';
打开这个选项通知MySQL在表打开时,检查是否损坏,并且在找到问题的时候进行修复。可以设置的值如下:
- 1.DEFAULT(或者不设置)
使MySQL尝试修复任何被标记为崩溃或者没有标记为完全关闭的表。默认值不要求在恢复时执行其他动作。跟大多数变量不同,这里DEFAULT值不是重置变量的值为编译值,它本质上意味着没有设置 - 2.BACKUP
让MySQL将数据文件的备份写到.BAK文件,以便随后进行检查 - 3.QUICK
除非又删除块,否则跳过恢复。块中有已经删除的行也依然会占用空间,但是可以被后面的INSERT语句宠用。这可能比较有用,因为MyISAM大表的恢复可能花费相当长的时间
可以使用多个设置,用逗号分割。例如"BACKUP,FORCE"会强制恢复并且创建备份。建议打开这个选项,尤其是只有一些小的MyISAM表时。服务器运行着一些损坏的MyISAM表是很危险的,因为它们有时可以导致更多数据损坏,甚至服务器崩溃。然而,如果有很大的表,原子恢复时不切实际的:它导致服务器打开所有的MyISAM表时都会检查和修复,这是低效的做法。在这段时间,MySQL会阻止连接做任何工作。如果有一大堆的MyISAM表,比较好的注意还是启动CHEKC TABLES和REPAIR TABLES命令来做,这样对服务器影响比较少。不管哪种方式,检查和修复表都是很中重要的。
打开数据文件的内存映射(MMAP)访问是另一个有用的MyISAM选项。内存映射使得MyISAM直接通过操作系统的页面缓存访问.MYD文件,避免系统调用的开销。在MySQL5.1和更新版本重,可以通过myisam_use_mmap选项打开内存映射。更老的版本的MySQL只能对压缩的MyISAM表使用内存映射