在部署了ORACLE数据库的服务器上,我们大家或多或少的遇到过下列情况:
1. 业务系统运行缓慢,作为系统管理员需要检查包括IO在内的系统资源,这时系统管理员、存储管理员可能得到DBA(数据库管理员)的反馈说,IO的响应时间很慢,达到了30毫秒以上,要求解决。但存储管理员检查又不存在热点盘的情况,系统的IO量就是很大,除了使用更多的RAID组来重新分布数据、更换为更高端的存储外,似乎没有太好的办法;
2. 我们可能通过iostat和sar -d命令观察到磁盘的busy很高、每秒的IOPS很高、每秒的IO读写量很大、HBA卡的流量很高等危险的现象;
3. IO响应时间长,到底是导致业务慢的原因还是结果?
4. IOPS很高、IO读写量很大,到底是原因还是结果?
5. 除了硬件的扩容或升级,难道没有别的解决方法么?
6. 如何识别ORACLE服务器上的IO来源,如何判断这些IO是否是有效IO,怎么消除无效IO?
7. 作为系统管理员和存储管理员需要掌握哪些数据库简单技能才不会在出现IO问题时处于被动的局面?
8. ORACLE DBA评判IO是否有性能问题的标准是什么?
9. ORACLE数据库的IO有什么特点?哪些IO是比较关键,是必须保障性能的?
我们将通过理论和实际案例穿插介绍的方式为大家进行讲解和分享,希望对大家有所启发。
本文是系列的第一篇。需要说明的是,由于篇幅有限,会暂时省略掉部分在过程中实际发生但与本主题不是那么密切的内容,如UNDO、checkpoint等内容。
同时考虑到AIX专家俱乐部可能更多的是系统/存储管理员,因此会有部分科普的内容,水平较好的ORACLE DBA可以自行跳到案例探讨环节。对于没有真正做过DBA的同学来说,ORACLE可能稍微有点难,但只要静下心来花点时间去主动了解了,那就不难了。
出一个问题时段的AWR报告,将awr报告对应的html文件下载到PC终端
用IE等浏览器打开,查找”SQL ordered by Reads”部分,如下图所示
可以看到:
1) 排名第一的SQL语句,占了整个数据库服务器IO的99.79%
2) 一共执行了8次,每次执行发生的IO是2,129,053个BLOCK,一个BLOCK是8K,即每次执行该SQL,将发生2,129,053*8K=16.24G
知识点:
BLOCK是ORACLE数据文件的最小分配单元,类似LV的PP,数据就存储在BLOCK中,一个BLOCK可以存储几十到几百条不等的用户表的数据
是不是很简单?
当然,大家也可以用操作系统的命令也可以看到进程级的IO分布情况。
例如Linux环境下通过pidstat -d 可以监控哪个进程IO消耗较高。
当然,采用操作系统方式查看进程级别的IO分布的方式的缺点是很显然的,更可怕的是,这表明你依然在把数据库当黑盒子来看待,进程具体在做什么?为什么IO那么高?
我们需要继续往前一步。
知识点:
一般来说,如果单个IO的响应时间在20毫秒以内,是可以接受的,较好的性能应该在10个毫秒以下,越低越好。超过20毫秒的单个IO响应时间,则可认为性能不佳,需要做调优。需要说明的是,对于IO次数只有个位数的文件,IO超过20毫秒,也是可以接受的,因为在存储层面不容易被cache。
通过OS和数据库AWR报告两个方式均可以判断IO是否有问题,建议以OS方式为准。
操作系统方式
sar –d 2 10的输出中,avwait和avserv两列之和即为IO的响应时间(AIX环境),单位为毫秒。LINUX环境下有区别,IO的响应时间为AVWAIT列。
可以看到:
hdisk4上单个IO的响应时间达到4000多毫秒和2000多毫秒,远远大于20毫秒,IO性能到了无法忍受的地步,需要尽快分析是否存储存储cache被关闭,硬盘是否出现故障、链路是否出现问题等情况。
数据库AWR报告方式
下图的Av Rd(MS)表示单次读的毫秒数,即为单个IO的响应时间。可以看到,在0.01毫秒,远远低于20毫秒,IO性能非常的好!(能达到整个性能,往往是在文件系统缓存中被缓存了)
下图的Av Rd(MS)表示单次IO读的毫秒数,即为单个IO的响应时间。可以看到,大部分数据文件的IO响应时间超过40毫秒,远远大于20毫秒,IO性能不理想,在对存储进行扩容或者升级前,应该先好好分析IO是否是无效IO,是否可以消除无效IO!通过SQL优化消除无效IO,可以有效保护存储等硬件的投资,满足未来多年的业务发展,而不是盲目扩容。
上述的AWR报告是怎么获得的呢?什么是AWR报告呢?容许我啰嗦一下
很多同学可能听过AWR报告,收集AWR报告的步骤是固定的,很简单,步骤如下:
#su – oracle
$sqlplus “/ as sysdba”
SQL>exec dbms_workload_repository.create_snapshot();
SQL>@?/rdbms/admin/awrrpt.sql
依次输入
1) Html
2) 回车
3) 输入想要抓取的时间范围所对应的开始snap_id
4) 输入想要抓取的时间范围所对应的结束snap_id
5) 输入想要保存为报告的名称(自己选个名字即可)
6) 刷屏出报告中……
通过AWR报告这个数据库内置的工具,可以清楚的了解到某个时段,数据库中到底执行了哪些SQL,产生了多少IO,消耗了多少CPU。
也许有人会说,AWR报告我已经会出了,但看懂AWR报告才是关键。
是的,你需要更深入地了解一些数据库知识,不妨耐心往下看。
ORACLE数据库,简单来说,主要就是对外提供数据存储服务,同时可以通过内置的丰富的SQL/PLSQL接口,对外提供数据检索、比对、关联等计算服务。
具体一点来说,ORACLE数据库通过服务器上的一组进程(后台进程与前台进程)和内存结构,对存储上的数据进行读写和计算。
知识点
ORACLE实例和ORACLE数据库的区别是什么?
做SA的很多同学一直不太清楚什么是ORACLE实例,其实很简单:
进程和内存结构加起来就称之为ORACLE实例即instance。
因为进程和内存是随着数据库/OS重启而消失的,因此oracle实例中不恒久的存储数据
我们的用户数据,最终是存放在磁盘中的,具体来说,是存在在磁盘中的数据文件中。
数据文件、控制文件、在线日志文件,这些物理上存在的文件组成了我们传统所说的ORACLE数据库。
知识点
ORACLE是一种典型的C/S架构么?
答:是的。
我们知道,客户端或者应用程序是通过SQL语句和数据库交互的。
当客户端或应用程序想连接到数据库执行SQL语句来完成查询和增删改数据时,ORACLE服务器上默认地,将为每一个客户端对应地创建一个专有的服务进程(在操作系统上将看到LOCAL=NO的进程)来单独的为这个客户端服务,这个专有的服务进程帮助这个客户端执行相关SQL,当执行完SQL时,这个进程也不能做别的,就只能等着客户端发起的下一条SQL。这就好比,我们去一个高级的餐厅,有一个专属的服务员为我们服务。
我们接下来用一幅图来总结上述的内容,即ORACLE的简单架构
可以看到:
每个客户端要执行SQL,只需要通过网络将SQL传到对应的服务进程,由服务进程帮忙执行即可。多个客户端则对应多个服务进程(见上图中的LOCAL=NO专属前台进程),这些服务进程我们也称之为前台进程。
ORACLE包含内存结构和后台进程
SGA共享内存,又可细分为
1) Buffer cache,用来缓存最近访问的数据,避免出现IO。Buffer cache中的数据可能比磁盘中的数据要新,例如读进内存后再修改为新的数据。我们称只要的数据为脏数据,脏块。
2) Log buffer,用一组记录来表示对数据库的修改过程,我们称之为改变向量。
3) 其他如shared pool/large pool/java pool/stream pool等,不在此介绍
ORACLE后台进程,又可细分为
1) DBWR进程,由于ORACLE定期会像word那样暂存一下最近所做的修改(我们称之为检查点checkpoint触发DBWR写脏数据),就是将buffer cache中的脏数据写回磁盘中的数据文件。这个IO属于随机写。
2) LGWR进程,在提交commit命令发出时,将log buffer中的修改记录以同步IO的形式写到磁盘中的在线日志文件后返回,commit才能完成,此时虽然buffer cache内存中的数据比磁盘中的数据文件中的数据要新,但是因为已经确保有一份修改过程写到了磁盘的在线日志文件,这个时候即使数据库掉电,也可以通过重新执行在线日志文件的修改记录,来保证数据不出现丢失。这在任何关系型数据库中常见的“日志先行”策略。由于lgwr进程采用追加写的方式把改变向量写到在线日志文件后面,因此LGWR的IO属于连续写。
3) 其他以ora_开头的oracle后台进程,如pmon/smon/ckpt,不在此介绍
知识点:
LGWR进程的IO是否支持写到文件系统缓存就返回?
不支持,LGWR进程的IO是透写的。如果只写到文件系统缓存(如果数据文件存放在文件系统缓存)就返回,则一旦系统crash,文件系统缓存来不及刷到磁盘,则会出现用户commit后已经提示修改成功,但由于log buffer/buffer cache中的改变最终没有落盘而出现数据丢失的情况。
LGWR进程的IO是异步IO么?
不是,因为要确保数据不丢失,lgwr必须等IO返回才会接着处理下一个IO写请求。
ORACLE架构中最大的瓶颈在哪里?
在ORACLE 12C之前,Lgw后台进程只有1个,由于所有进程在commit前都需要通知lgwr进程帮忙把之前在log buffer中生成的修改过程记录(改变向量)写到磁盘中。当大量进程要同时请lgwr进程帮忙写时,就出现排队的情况。在高并发的联机交易OLTP系统中,单进程的lgwr进程有可能成为一个大瓶颈,特别是在无法保证在线日志IO写性能的情况下,很容易出现排队等lgwr进程的情况。这其实也是很容易引发问题的一个点,是ORACLE一个相对脆弱的地方。
知识点:
为什么ORACLE那么吃内存?服务器一半左右的内存都被ORACLE吃掉了…
因为IO相比内存要慢非常多,因此很多关系型数据库为了更好的性能,大量采用内存换IO的策略,ORACLE也不例外,具体来说,ORACLE利用SGA中的buffer cache来缓存最近访问的数据,从而避免再次访问时需要发生IO。Buffer cache通常会占到SGA大小的80%,即buffer cache占到服务器内存的50%*0.8=40%左右。