2.2 IO配置
在借助各种成熟的存储技术的基础上,合理配置系统的IO分布及系统IO配置能大量减少系统在生产运行中出现IO性能及相关问题的几率。当然,这些配置是我们在布置数据库系统时初始建议,对于复杂的系统来说,很多配置(如一些存储相关的参数)是需要根据系统的运行状况进行调优的。
在数据库系统中,如果某个文件或者某块磁盘上存在远远高于其他文件或磁盘的大量IO访问,我们就称这个文件或磁盘为热点文件/磁盘。我们在做IO规划时的一个重要目标就是要消除系统中热点文件/磁盘的存在,使整个系统的IO负载相对平衡。
2.2.1 条带化的设置
由于现在的存储技术成熟、成本降低,大多数系统都采用条带化来实现系统的IO负载分担。如果操作系统有LVM(Logical Volume Manager逻辑卷管理器)软件或者硬件条带设备,我们就可以利用这些攻击来分布IO负载。当使用LVM或者硬件条带时,决定因素是条带深度(stripe depth)和条带宽度(stripe width):
- 条带深度指的是条带的大小,也叫条带单元;
- 条带宽度指的是条带深度的产量或者一个条带集中的驱动数;
需要根据系统的IO要求来合理的选择这些数据。对于Oracle数据库系统来数,比较合理的条带深度是从256K到1M。下面分析影响条带深度和条带宽度的影响因素。
2.2.1.1 条带深度
为了提高IO效率,我们要尽量使一次逻辑IO请求由一块磁盘的一次物理IO请求。因而影响条带的一个重要因素就是一次逻辑IO请求的大小。
此外,系统中IO的并发度不同我们对条带的配置要求也不同。例如,在高并发度且IO请求的大小都比较小的情况下,我们希望一块磁盘能同时响应多个IO操作;而在那些存在大IO请求的低并发度系统中,我们可能就需要多块磁盘同时响应一个IO请求。无论是一个磁盘还是多个磁盘响应IO请求,我们的一个原则是让一次逻辑IO能被一次处理完成。
下面先看下影响IO大小的操作系统和Oracle的相关参数:
- db_block_size:Oracle中的数据块大小,也决定了Oracle一次单个IO请求中的数据块的大小;
- db_file_multiblock_read_count:在多数据块读时,一次读取数据块的数量,它和参数db_block_size一起决定了一次多数据块读的大小,它们的乘积不能大于操作系统的最大IO大小;
- 操作系统的数据块大小:这个参数决定拉Redo Log和Archive Log操作时的数据块大小,对于大多数Unix系统来说,该值为512K;
- 最大操作系统IO大小:决定了一次单个的IO操作的IO大小的上限,对于大多数Unix系统来说,由参数max_io_size设置;
- sort_area_size:内存中sort area的大小,也决定了并发排序操作时的IO大小;
- hash_area_size:内存中hash area的大小,也决定了哈希操作的IO大小。
其中,前面两个是最关键的两个参数。
在OLTP系统中,会存在大量小的并发的IO请求。这时就需要考虑选择比较大的条带深度。使条带深度大于IO大小就称为粗粒度条带(Coarse Grain Striping)。在高并行度系统中,条带深度为(n * db_block_size),其中n为大于1的整数。
通过粗粒度条带能实现最大的IO吞吐量(一次物理IO可以同时响应多个并发的逻辑IO)。大的条带深度能够使像全表扫描那样的多数据块读操作由一个磁盘驱动来响应,并提高多数据块读操作的性能。
在低并发度的DSS系统中,由于IO请求比较序列化,为了避免出现热点磁盘,我们需要避免逻辑IO之由一块磁盘处理。这是,粗粒度条带就不适合了。我们选择小的条带深度,使一个逻辑IO分布到多个磁盘上,从而实现IO的负载均衡。这就叫细粒度条带。条带深度的大小为(n * db_block_size),其中n为小于多数据块读参数(db_file_multiblock_read_count)大小的整数。
另外,IO过程中,你无法保证Oracle数据块的边界能和条带单元的大小对齐。如果条带深度大小和Oracle数据块大小完全相同,而它们的边界没有对齐的话,那么就会存在大量一个单独的IO请求被两块磁盘来完成。
在OLTP系统中,为了避免一个逻辑IO请求被多个物理IO操作完成,条带宽度就需要设置为两倍或者两倍以上于Oracle数据块大小。例如,如果条带深度是IO大小的N倍,对于大量并发IO请求,我们可以保证最少有(N-1)/ N的请求是由一块磁盘来完成。
2.2.1.2 条带宽度
正如我们前面所述,无论是一个还是多个磁盘响应一个逻辑IO,我们都要求IO能被一次处理。因而在确定了条带深度的基础上,我们需要保证条带宽度 >= IO请求的大小 / 条带深度。
此外,考虑到以后系统容量的扩充,我们也需要规划好条带宽度。
如今大多数LVM都支持在线动态增加磁盘。也就是在磁盘容量不足时,我们可以随时将新磁盘加入到一个已经使用的逻辑卷中。这样的话,我们在设置逻辑卷时就可以简单地将所有磁盘都归入到一个卷中去。
但是,有些LVM可能还不支持动态增加磁盘。这时我们就需要考虑以后的容量扩充对IO均衡的影响了。因为你新增加的磁盘无法加入原有卷,而需要组成一个新的卷。但一般扩充的容量和原有容量比较相对比较小,如果原有卷的条带宽度比较大的话,新增加的卷的条带宽度无法达到其大小,这样就会使新、旧卷之间出现IO失衡。
例如,一个系统的初始配置是一个包含64块磁盘、每块磁盘大小为16G的单一逻辑卷。磁盘总的大小是1T。随着数据库的数据增长,需要增加80G的空间。我们把新增加的5个16G磁盘再组成一个逻辑卷。这样就会导致两个卷上的IO失衡。为了避免这种情况。我们可以将原有磁盘配置成每个条带宽度为8个磁盘的8个逻辑卷,这样在新增加磁盘时可以也增加为8个磁盘的新卷。但必须要保证8个磁盘的条带宽度能够支持系统的每秒IO吞吐量。
如果你的条带宽度设置得比较小,就需要估算出你的各个数据库文件的IO负载,并根据负载量不同将他们分别部署到不同卷上一分担IO负载。
2.2.2 人工条带
如果系统不支持LVM或者硬件条带,IO负载就必须由DBA根据数据库文件的IO负载不同手工将他们分散到各个磁盘上去以保证整个系统的IO负载均衡。
有许多DBA会将哪些使用频率非常高的表和它的索引分开存储。但实际上这种做法并不正确。在一个事务中,索引会先被读取到然后再读取表,它们的IO操作是有前后顺序的,因此索引和表存储在同一个磁盘上是没有冲突的。仅仅因为一个数据文件即包含了索引又包含了数据表而将它分割是不可取的。我们需要根据文件上的IO负载是否已经影响到了数据库的性能来决定是否将数据文件分割。
为了正确分布文件,我们首先必须先了解各个数据库文件的IO负载需求以及IO系统的处理能力。鉴定出每个文件的IO吞吐量。找出哪些文件的IO吞吐率最高而哪些IO量很少,将它们分散分布到所有磁盘上去以平衡IO吞吐率。
如果你不了解或者无法预计文件的IO负载,就只能先估计他们的IO负载来规划文件分布,在系统运行过程中再做调整。
2.2.3 文件分离
无论是采用操作系统条带化还是手工IO分布方式,如果IO系统或者IO规划布置无法满足IO吞吐率的要求,我们就需要考虑将高IO吞吐率的文件和其他文件分离。我们可以在存储规划阶段或者系统运行阶段找出那样的文件。
除了IO吞吐率,在决定是否分割文件时,我们还需要考虑可恢复性以及数据容量扩张问题。
但是在分割文件之前,一定要确认存在IO瓶颈,然后再根据产生IO瓶颈的数据定位到存在高IO吞吐率的文件(热点文件)。
2.2.3.1 表、索引和临时表空间
如果具有高IO吞吐率的数据文件属于包含表和索引的表空间,我们就需要找出这些文件的IO是否可以通过SQL语句调优或者优化应用程序来降低。
如果具有高IO吞吐率的数据文件属于临时表空间,那我们就需要检查是否可以通过避免或调优SQL语句的排序操作来降低IO。
经过应用调优后,如果IO分布仍然无法满足IO吞吐的要求,我们就需要考虑分离高IO吞吐率的数据文件了。
2.2.3.2 Redo Log文件
如果具有高IO吞吐率的文件是Redo Log文件,则需要考虑将Redo Log文件与其他文件分离,可以通过以下配置来实现:
- 将所有Redo Log文件放到没有任何其他文件的磁盘上去。考虑到可恢复性,需要将一个Redo Log组中的成员文件分别放到不同的物理磁盘上去;
- 将每个Redo Log组放到一个没有任何其他文件的单独磁盘上;
- 通过操作系统条带化工具,将Redo Log文件条带化分布到多个磁盘上去;
- 不要将Redo Log文件放到RAID 5上去
Redo Log文件是由LGWR进程序列化的写入的。如果在同一个磁盘上不存在并发的其他IO操作,写入效率就更高。我们需要确认已经没有其他优化调整空间再考虑分割Redo Log文件。如果系统支持AIO但还没有激活该特性,可以考虑激活AIO看是否能解决Redo Log的IO性能瓶颈。
2.2.3.3 归档Redo Log
如果归档变慢,我们也许可以通过使LGWR的写操作与Archive进程的读操作分离来避免LGWR进程鱼Archive进程直接的IO冲突。我们可以同交替成组存放Redo Log文件来实现。
例如,我们有四组Redo Log,每组包含两个Log文件:(A1,A2)、(B1,B2)、(C1,C2)、(D1,D2)。我们就可以以下面这种存放方式将它们分布存储到四个磁盘上去来实现磁盘分离访问:(A1,C1)、(A2、C2)、(B1,D1)、(B2,D2)。
当LGWR进程做日志切换时,如从A组切换到B组,LGWR开始向B组写Redo Log(第三、四块磁盘),而Archive进程则从B组读取数据(第一、二块磁盘)写入归档文件中去,他们分别访问的是不同磁盘,因而避免了IO冲突。
2.3 三种简单的配置方法
这里给出三种简单的操作系统IO配置的例子,包括如何简单地计算来决定磁盘的拓扑结构、条带深度等等。
2.3.1 将所有文件条带化到所有磁盘上去
IO配置最简单的方法就是建立一个大的逻辑卷,将所有磁盘都条带化到这个卷中去。考虑到可恢复性,这个卷需要被镜像(RAID 1)。每个磁盘的条带深度必须大于频繁执行的IO操作的最大IO大小。这种配置对大多数情况都能提供足够的性能支持。
2.3.2 将归档日志放到另外的磁盘上去
在归档模式下,如果归档文件也和其他文件放在同一个条带化的卷中,那么当归档进程对Redo Log进行归档时,会大大增加磁盘的IO负载。将归档日志转移到其他磁盘上有如下好处:
- 归档进程效率提高;
- 当归档时,其他进程受到归档进程的影响
归档日志的磁盘数由归档日志产生的频率以及归档存储容量决定。
2.3.3 将Redo Log文件放到另外的磁盘上去
在更新非常频繁的OLTP系统中,Redo Log的写操作非常频繁。将Redo Log文件转移到其他磁盘上可以有如下好处:
- 写Redo Log的读写效率最高,因而事务的执行也能获得非常好的性能;
- 写Redo Log操作不会影响任何其他IO操作
Redo Log的磁盘数量有Redo Log的大小决定。由于现在的磁盘容量都非常大,通常配置两个磁盘(如果做镜像则需要四块)就足够了。并且,根据我们前面的分析,将Redo Log文件交互的存放到两块磁盘上去能避免LGWR进程的写操作与ARCH进程的读操作之间的IO冲突。