往期分享
RDS MySQL
RDS PostgreSQL
概述
实例的磁盘IO负载是RDS SQL Server用户日常应重点关注的监控项之一,如果磁盘IO压力过大,很容易导致数据库性能问题。根据实例计算规格的不同及其使用的磁盘的类型和容量大小不同,实例的磁盘IO处理能力上限也不同,主要体现在IOPS的限制和IO吞吐量的限制两个方面。由于SQL Server中的IO访问块的大小总体来说是比较大的(大部分都在8KB以上),因此在RDS中,IOPS达到实例上限并成为主要的磁盘性能瓶颈的情况相对比较少,而IO吞吐达到上限的情况相对出现的就比较多一些。
磁盘IO吞吐限制
对于本地盘版的RDS SQL Server 2008 R2实例来说,是采用的同一物理主机上多个实例共享几块本地SSD盘的架构。虽然有对每个实例可以使用的最大磁盘IOPS做限制,但并未在单个实例的磁盘IO吞吐量方面做严格限制,因此实际上单个实例可以使用的最大磁盘IO吞吐量往往可以达到1GB/sec以上,但相应的也就存在着同一主机上多个实例之间竞争磁盘IO资源并相互影响性能的可能性。因此对于需要独享磁盘IO资源的RDS SQL Server 2008 R2用户来说,应选择独占物理机的规格。
对于云盘版的RDS SQL Server实例来说,是采用的每个实例独立的挂载单块SSD或ESSD云盘的架构,因此在磁盘IO资源方面是完全隔离和独享的。相应的单个RDS实例的磁盘IO吞吐能力上限,就取决于实例的计算规格及使用的SSD或ESSD云盘的规格和容量大小。
- 目前云盘版的RDS SQL Server实例使用的计算节点主要是ECS 6代规格的实例,包括g6、c6和r6这几个规格族,因此单个RDS实例可以提供的最大IO吞吐量首先会受到对应的ECS规格的单实例最大IO吞吐量限制,具体可参考如下链接:https://help.aliyun.com/document_detail/25378.html#g6
相应的,常见的几种CPU核数的RDS SQL Server实例在ECS计算节点层面的IO吞吐量上限如下:
CPU核数 | IO吞吐量上限(MB/sec) |
2 | 125 |
4 | 187.5 |
8 | 250 |
16 | 375 |
24 | 500 |
32 | 625 |
- 目前云盘版的RDS SQL Server实例使用的云盘有SSD和ESSD两类,其中ESSD云盘又支持PL1、PL2和PL3三个性能等级,因此单个RDS实例可以提供的最大IO吞吐量还受到其使用的云盘的类型和容量大小的限制,具体可参考如下链接:https://help.aliyun.com/document_detail/25382.html
其中,对于最常见的ESSD PL1云盘来说,其IO吞吐量上限的计算公式为:min{120+0.5*容量, 350}
举例来说,若一个云盘版RDS SQL Server实例的CPU核数为8,使用的云盘存储类型为ESSD PL1(默认类型),存储空间大小为200GB。根据以上规则,实例在ECS层面的IO吞吐量上限为250MB/sec,在云盘层面的IO吞吐量上限为220MB/sec,则实例最终的IO吞吐量上限为220MB/sec。
如果实例的CPU核数不变,而存储空间扩容到500GB,则云盘层面的IO吞吐量上限将增加到350MB/sec,但是受实例的计算规格限制,其IO吞吐量上限仍只能达到250MB/sec。
如果进一步升级实例的CPU核数到16,则ECS层面的IO吞吐量上限将增加到375MB/sec,这时受云盘规格的限制,其IO吞吐量上限就是350MB/sec了。
查看磁盘IO吞吐使用情况
RDS控制台CloudDBA
目前RDS SQL Server控制台的监控与报警部分还没有提供关于实例的磁盘IO吞吐使用量的监控数据,需要在CloudDBA中查看磁盘IO吞吐量的数据。
在RDS控制台的“CloudDBA”->“性能优化”页中的“性能洞察”部分,可以添加查看实例的磁盘IO吞吐量相关的性能指标:
其中IO_Throughput_Read_Kb和IO_Throughput_Write_Kb分别对应实例的每秒磁盘读IO吞吐量和每秒磁盘写IO吞吐量,IO_Throughput_Total_Kb则为二者之和,即每秒磁盘读写IO吞吐总量。示例如下:
从上图中可以看到,这个实例的IO吞吐中读IO占了大部分,写IO的比例要小的多。其中8-22点这段时间是IO负载相对比较平稳的时段,另外1-3点和22-0点各有一个明显的IO吞吐高峰。
如果实例的磁盘IO吞吐负载经常持续达到磁盘IO吞吐上限的70-80%以上,就说明实例在磁盘IO吞吐方面有比较明显的性能瓶颈,并应进行相应的原因分析和优化。对于不同类型的数据库IO操作造成的实例磁盘IO吞吐高问题,其原理和优化途径也各自不同。
磁盘IO吞吐负载分析与优化
SQL Server中的磁盘IO负载由数据文件的读、写及事务日志文件的读、写几类请求组成,其中数据文件的读IO负载主要有查询请求产生的数据页读取和数据库备份操作产生的数据页读取两类,而日志文件除了在做备份时会有较多的读IO负载,其他情况下基本主要都是写IO负载。因此,当发现实例的磁盘IO吞吐使用量较高时,我们可以进一步通过以下性能指标分析是哪一类负载导致了较高的IO吞吐:
性能指标 |
IO类型 |
含义 |
Page_Reads |
读 |
每秒由于未命中缓存从数据文件中读取的数据页的个数 |
Page_Write |
写 |
每秒向数据文件中写入的数据页的个数 |
Log_Bytes_Flushed/sec |
写 |
每秒向日志文件中写入的字节数 |
Backup_Restore_Throughput/sec |
读 |
每秒由备份或还原操作产生的数据和日志文件读写的字节数 |
其中每个数据页的大小为8KB。
延续前面的示例,在同样的连续24小时时段内,可以获得以上性能指标的监控数据如下:
从图1中可以看到,1点左右的IO吞吐量突增主要是数据页的读取造成的,其峰值达到了50000页左右,即400MB/sec。
从图1、2、3中可以看到,2-3点左右的IO吞吐高峰由数据页读取(峰值约40MB/sec)、数据页写入(峰值也为接近40MB/sec)、日志文件写入(峰值约30MB/sec)和日志备份(峰值约50MB/sec)几类负载共同组成,累积的IO吞吐峰值约达到150MB/sec。
从图1、2中可以看到,8-22点期间的IO吞吐中大部分是数据页的读取,平均值大约在80-100MB/sec;其次是数据页的写入,平均值大约在30MB/sec;再次是日志文件的写入,平均值不到5MB/sec。
从图3中可以看到,22-0点的IO吞吐高峰完全是由备份造成的,持续达到了220MB/sec以上。
数据页读取IO吞吐高
数据页读取(Page Reads)IO吞吐高是导致RDS SQL Server实例磁盘IO吞吐高的原因中最常见的一类,其主要原因通常为实例的缓存相对不足,从而导致查询请求在执行过程中经常由于数据缓存无法命中(cache miss)而需要从磁盘中读取大量的数据页。
与缓存瓶颈诊断相关的另外一个常用的性能计数器指标是Page Life Expentancy(页生命周期),它的含义是平均每个缓存的数据页可以在内存中驻留的时间(秒),这个值越小就意味着实例的缓存压力越大(已缓存的数据页在较短的时间内就要被清除掉以容纳新读取的数据页)。
一般来说Page Life Expentancy建议的阈值应至少不低于300,而实例的内存规格越高的话,这个阈值也应越大,具体可参考如下链接中推荐的阈值参考公式:
https://www.sqlshack.com/page-life-expectancy-ple-in-sql-server/
PLE (Page Life Expectancy) threshold = ((Buffer Memory Allocation (GB)) / 4 ) * 300
例如对一个16GB内存规格的RDS SQL Server实例来说,通常buffer memory实际可以使用的内存不超过12GB,按照以上公式,则Page Life Expentancy的值建议应不低于900,否则就说明实例的缓存压力较大。
对于数据页读取高导致的磁盘IO吞吐负载过高的情况,首先应考虑的优化措施是升级实例的内存规格,而不是提升实例的磁盘性能等级。磁盘性能等级的提升虽然可以缓解IO吞吐使用率过高导致的磁盘页读取性能瓶颈的问题,但相比内存页的读写,磁盘页读写的平均相应时间和CPU资源开销都是更高的,因此升级内存通常是解决此类性能问题的最佳选择。
另外在数据库层面也有很多可以通过减少数据页总量来降低缓存压力和磁盘数据页读取负载的手段,例如历史数据的归档/清理、在表上启用数据压缩、去除表上的低价值索引、索引碎片整理等,这些就需要结合具体的表和索引结构来进行深入分析和优化了。
数据页写入/日志文件写入IO吞吐高
对于数据页写入或日志文件写入导致IO吞吐高的情况,首先可利用CloudDBA中的性能洞察功能检查一下,写IO吞吐高期间是否有频繁的DML类的写入操作(INSERT/DELETE/UPDATE/MERGE等),或是主要为DDL类的写入操作(CREATE INDEX/ALTER INDEX等)。
如果主要的写负载为DML操作,可首先评估一下是否为常规的业务行为。如果不是的话(例如为临时性的数据处理或归档操作),那么尽量将此类操作错开到非业务高峰期执行通常即可。如果是的话,那意味着业务负载本身确实需要产生大量的数据/日志写入,这时如果磁盘IO吞吐达到瓶颈的话,就应考虑升级实例的磁盘性能等级了,例如从ESSD PL1到PL2。另外对表上的索引结构进行优化,尤其是去除一些不必要的非聚集索引,往往也是降低表上的数据写入操作过程中产生的数据和日志写入IO量的有效手段。
如果主要的写负载为DDL操作,那么通常都是数据维护类或临时性的行为,一般也是尽量避免在业务高峰期执行即可。另外对于索引创建/重建等操作,还可以通过在SQL语句中使用MAXDOP提示来限制任务执行的并行度,从而降低其执行过程中的磁盘IO吞吐峰值,但这也意味着DDL操作执行的时间会更长。
备份IO吞吐高
目前RDS SQL Server仅支持在主实例上进行数据库备份,而不支持在从实例上做备份。数据库备份操作导致主实例的磁盘IO吞吐高也是一种较常见的情况,其中主要是数据备份(尤其是全量备份)操作的影响,而日志备份的影响通常较小。
由于备份操作是保障RDS数据安全和可靠性所必不可少的,因此对于备份产生的磁盘IO性能影响,主要还是通过优化备份时间的设置来进行规避。
用户可在RDS控制台的数据备份历史记录中查看到近期一次全量备份执行的耗时,然后结合实例的整体负载变化情况,选择合适的备份时间窗口。
例如一次全量备份大约需要6小时,每天9点至21点是数据库常规业务负载较高的时段,22点至1点间有后台数据处理任务执行的话,那么就可以把备份(开始)时间设为01:00-02:00,这样基本上8点之前全量备份就可以完成了。而备份周期可以保持默认的每天备份的设置,这样当需要通过备份进行数据还原时,还原操作执行的效率也是相对较高的。
而如果一次全量备份大约需要15小时,每周一至周五9点至21点是数据库常规业务负载较高的时段的话,那么在周一至周五期间任何时间开始执行全量备份都可能和常规业务负载高峰时段发生冲突。在这种情况下,可以考虑将备份周期设为仅周六和周日,备份时间设为01:00-02:00。由于RDS SQL Server每3天才会做一次全量备份,其他日期是做差异备份,这样设置的结果就是每周六1点至2点间会开始执行一次全量备份、每周日1点至2点间会开始执行一次差异备份,也就是可以避免全量备份操作在业务高峰期被执行。但以上设置带来的一个影响,就是将来如果要通过备份进行指定时间点的数据还原时,还原操作执行的耗时有可能会相对较长。
而如果通过备份时间的调整无法避免全量备份操作和数据库常规业务负载高峰期的冲突的话,那么就要考虑升级实例的磁盘性能等级了。或是考虑对实例上的数据进行拆分,通过减少单个实例上的数据量大小来缩短全量备份操作所需的时间。