29. MySQL磁盘 IO 问题
前面提到的 SQL 优化、数据库对象优化、数据库参数优化,以及应用程序优化等, 大部分都是想通过减少或延缓磁盘读写来减轻磁盘 I/O 的压力及其对性能的影响。
1. 使用磁盘阵列⚓
RAID(Redundant Array of Inexpensive Disks):廉价磁盘冗余阵列,通常就叫做磁盘阵列。
RAID 级别 | 特性 | 优点 | 缺点 |
---|---|---|---|
RAID 0 | 也叫条带化(Stripe),按一定 的条带大小(Chunk Size)将数 据依次分布到各个磁盘,没有 数据冗余 | 数据并发读写速度快,无额 外磁盘空间开销,投资省 | 数据无冗余保护,可靠性 差 |
RAID 1 | 也叫磁盘镜像(Mirror),两个 磁盘一组,所有数据都同时写 入两个磁盘,但读时从任一磁 盘读都可以 | 数据有完全冗余保护,只要 不出现两块镜像磁盘同时损 坏,不会影响使用;可以提 高并发读性能 | 容量一定的话,需要 2 陪 的磁盘,投资比较大 |
RAID 10 | 是 RAID 1 和 RAID 0 的结合,也 叫 RAID 1+0。先对磁盘做镜像, 再条带话,使其兼具 RAID 1 的可靠性和RAID 0的优良并发读写性能 | 可靠性高,并发读写性能优 良 | 容量一定的话,需要 2 陪 的磁盘,投资比较大 |
RAID 4 | 象 RAID 0 一样对磁盘组条带 化,不同的是:需要额外增加 一个磁盘,用来写各 Stripe 的 校验纠错数据 | RAID 中的一个磁盘损坏,其 数据可以通过校验纠错数据 计算出来,具有一定容错保 护能力;读数据速度快 | 每个 Stripe 上数据的修改 都要写校验纠错块,写性 能受影响;所有纠错数据 都在同一磁盘上,风险大, 也会形成一个性能瓶颈; 在出现坏盘时,读性能会下降 |
RAID 5 | 是对 RAID 4 的改进:将每一个 条带(Stripe)的校验纠错数据 块也分布写到各个磁盘,而不 是写到一个特定的磁盘 | 基本同 RAID 4,只是其写性 能和数据保护能力要更强一 点 | 写性能不及 RAID 0、RAID 1 和 RAID 10,容错能力也不 及 RAID 1;在出现坏盘时, 读性能会下降 |
根据数据读写的特点、可靠性要求,以及投资预算等来选择合适的 RAID 级别,比如:
- 数据读写都很频繁,可靠性要求也很高,最好选择 RAID 10;
- 数据读很频繁,写相对较少,对可靠性有一定要求,可以选择 RAID 5;
- 数据读写都很频繁,但可靠性要求不高,可以选择 RAID 0。
1.1 虚拟文件卷或软 RAID⚓
一些操作系统中提供的软件包,也模拟实现了一些 RAID 的特性,但性能上不如硬 RAID 。
比如,Linux 下的逻辑卷(Logical Volume)系统 lvm2,支持条带化(Stripe);Linux 下的 MD(Multiple Device)驱动,支持 RAID 0、RAID 1、RAID 4、RAID 5、RAID 6 等。
2. 使用 Symbolic Links 分布 I/O⚓
默认情况下,创建的数据库和表都存放在参数 datadir定义的目录下。在这种情况下,我们就可以利用操作系统的符号连接(Symbolic Links)将不同的数据库或表、索引指向不同的物理磁盘,从而达到分布磁盘 I/O 的目的。
- 将一个数据库指向其他物理磁盘。
其方法是先在目标磁盘上创建目录,然后再创建从 MySQL 数据目录到目标目录的符号连接:
shell> mkdir /otherdisk/databases/test
shell> ln -s /otherdisk/databases/test /path/to/datadir
2. 将MyISAM(其他存储引擎的表不支持)表的数据文件或索引文件指向其他物理磁盘。
1. 对于新建的表,可以通过在CREATE TABLE语句中增加`DATA DIRECTORY`和`INDEX DIRECTORY`选项来完成(对于分区表无效),例如:
Create table test(id int primary key,
Name varchar(20))
Type = myisam
DATA DIRECTORY = '/disk2/data'
INDEX DIRECTORY = '/disk3/index'
2. 对于已有的表,可以先将其数据文件(.MYD)或索引文件(.MYI)转移到目标磁盘,然后再建立符号连接即可。需要说明的是表定义文件(.frm)必须位于MySQL数据文件目录下,不能用符号连接。
注意:使用Symbolic Links存在一定的安全风险,如果不使用Symbolic Links,应通过启动参数skip-symbolic-links禁用这一功能。
3. 禁止操作系统更新文件的 atime 属性⚓
atime
是 Linux/UNIX 系统下的一个文件属性,每当读取文件时,操作系统都会将读操作发生的时间回写到磁盘上。可以通过设置文件系统的 mount 属性,阻止操作系统写 atime 信息,以减轻磁盘 I/O 的负担。在 Linux 下的具体做法是:
-
修改文件系统配置文件
/etc/fstab
,指定 noatime 选项:LABEL=/home /home ext3 noatime 1 2
-
然后重新 mount 文件系统:
mount -oremount /home
完成上述操作,以后读 /home 下文件就不会再写磁盘了 。
4. 用裸设备(Raw Device)存放 InnoDB 的共享表空间⚓
MyISAM 存储引擎有自己的索引缓存机制,但数据文件的读写完全依赖于操作系统,操作系统磁盘 I/O 缓存对 MyISAM 表的存取很重要。
但 InnoDB 存储引擎与 MyISAM 不同它采用类似 Oracle 的数据缓存机制来 Cache 索引和数据,操作系统的磁盘 I/O 缓存对其性能不仅没有帮助,甚至还有反作用。
因此,在 InnoDB 缓存充足的情况下,可以考虑使用 Raw device 来存放 InnoDB 共享表空间:
- 修改MySQL配置文件,在innodb_data_file_path参数中增加裸设备文件名并指定newraw属性:
[mysqld]
innodb_data_home_dir=
innodb_data_file_path=/dev/hdd1:3Gnewraw;/dev/hdd2:2Gnewraw
- 启动MySQL,使其完成分区初始化工作,然后关闭MySQL。此时还不能创建或修改InnoDB表。
- 将innodb_data_file_path中的newraw改成raw :
......
class=programlisting[mysqld]
innodb_data_home_dir=
innodb_data_file_path=/dev/hdd1:3Graw;/dev/hdd2:2Graw
......
- 重新启动即可开始使用。