脑洞大开!使用Perf深入研究Oracle内部

这是我个人做的一次直播演讲。

一、Perf简介

Perf是用来进行软件性能分析的工具,使用Perf,可以帮我们解决一些性能问题。例如:程序运行很慢,占用CPU 100%,需要知道是程序的哪一个函数占用的CPU最高?可以以此来定位问题的根源。

运行环境:

这里介绍的Perf是运行在Oracle Linux Server Release 7.2上,内核版本4.1.12

Perf的版本:

Perf version 4.1.12-94.3.5.el6uek.x86_64

运行Perf list,可以看到现在Perf主要分为以下几类:

Hardware event,Software event,Hardware cache event,Raw hardware event descriptor,Hardware breakpoint,Tracepoint event等等。

Hardware event、Hardware cache event硬件这类的诊断依赖于PMU(performance monitoring unit),一般处理器厂商都会在硬件中加入了 PMU 单元, PMU可以让我们对某种硬件事件设置counter,一旦发生这种事件,处理器就会统计该事件发生的次数。一旦发生的次数超过设置的counter,便会产生中断,Software event是内核产生的事件,例如CPU时钟、上下文切换等。

Tracepoint event,是内核中静态tracepoint所触发的事件,只有2.6.3x以上的内核才可用。

二、Perf基本使用

介绍完基本概念,来看看Perf是怎么使用的。

1、Perf Top

Perf的top和linux的top工具类似,实时打印采样函数,默认的采样事件是循环的。这里Perf显示了大部分消耗cpu-time高的函数。

当然,如果想要继续分析下去,还可以按s,再输入函数名,如图所示,我输入了函数e1000_watchdog,显示下面具体的code地址及原子操作。这里的ja和mov都是汇编语言的一些操作,ja是判断两个无符号数之间的大小关系然后跳转,mov是数据传送指令。

2、Perf Record

Perf Record的作用是记录一段时间内系统或者进程的性能事件。这里用一个Oracle操作来做例子。首先打开2个session,会话1是登录到Oracle,查到它的spid:2794。

那我们就在session2这边监控2794这个进程。使用perf record –e cpu-clock –p 2794。

这里需要说明一下-e,这个就是我们前面介绍的事件,可以通过Perf list查看,这里我们选择了cpu-clock计数器。

这边监控打开之后,我们切换到session 1,随便执行一条SQL操作。

然后回到session 2,按ctrl + c终止监控。运行perf report,就能看到刚刚监控的结果了。如下所示:

这里显示刚刚整个SQL操作,最消耗CPU的是内核_raw_spin_unlock_irqrestore函数。

有了上述两个基本操作,可以帮助我们研究那些莫名其妙CPU过高的问题,分析出具体是哪个函数导致的,甚至这个函数的相关原子操作都可以能被我们看到。因为Oracle是不开源的,所以我们发现是那个函数异常了,就只能上Mos上搜索。

例如:刚刚看到的有一个叫kghalf的函数,我们上去搜索一番,你看在这个函数上面果然存在这一个bug,不过这里版本对不上。

是不是很强大?在我们没有头绪的时候,通过Perf top或者Perf record往往能帮我们找到一些线索。

三、结合Perf和Oracle进行深入研究

前面介绍的都是Perf的一些基本用法,后面我们来介绍一下它怎么和Oracle结合起来,做一些动态追踪技术。动态追踪技术主要使用的是探针,下面我们来介绍一个例子。

Perf和10046等待事件跟踪

这里首先要介绍一下Oracle内核的三个函数:kskthbwt、kskthewt、kews_update_wait_time。

这三个函数,分别是内核服务编译线程开始等待,内核服务编译线程结束等待,内核事件更新等待事件的等待时间。需要注意的是,这里涉及到汇编语言的原理知识,如段地址和寄存器,还有偏移量。如果大家需要深入研究,建议看一下计算机书籍编译原理和深入理解计算机系统。

X86-64架构下有16个64位的寄存器,其中%rdi、%rsi用作传递函数参数,分别对应第1个参数、第2个参数。图中RDI代表着等待时间(微秒),RDS代表的等待事件的number。

这里需要对这三个函数设置探针。

对上述三个函数设置完探针之后,我们运行perf probe –l就能看到我们设置的探针。你如果觉得设置有问题,可以运行perf probe –del进行删除。设置完成之后,我们就可以做10046追踪了。

运行完成出现下列结果:

上图我们能够看到探针做的一些事情。会话2794等待事件0x162,等待时间ox553df61f78f21,然后下一个等待事件0x93,等待时间0x553df61f7938d。这些数据不是很直观,我们需要对其格式化一下。等待事件的这些编号需要从视图v$event_name获取。

通过下列脚本格式化后,输出结果如下:

当然还有很多函数可以做探针来进行学习和研究,大家可以通过Github来获取各种函数的意义及参数。例如函数opiprs就是硬解析,而kksParseCursor则代表了软解析。如果你想知道Oracle数据库都有哪些函数,可以运行命令nm -D $ORACLE_HOME/bin/oracle,你可以看到10多万行的信息。绝大多数的函数都是非公开的,我们可以通过MOS获取到一些信息,然后还可以通过oradebug doc获取到一些信息?如果有精力,也可以使用gdb来慢慢调试。

https://github.com/LucaCanali/Linux_tracing_scripts/tree/master/Perf_probes

四、Perf和火焰图

火焰图可以一针见血地指出程序的性能瓶颈,指出问题之所在。而Oracle上我们能做的火焰图一般有下面几种。

1、基于执行计划的火焰图。

不仅仅有执行计划的信息,还有执行函数的信息,可以清楚帮助我们分析SQL语句的瓶颈。

2、基于逻辑I/O的火焰图

不仅仅有执行计划的信息,还有执行I/O函数的信息,清晰明了。

3、基于物理I/O的火焰图,同上。

4、基于系统负载的火焰图。

它可以帮助我们直观地查看到系统最耗费资源的地方,快速定位问题。

要生成这些图表,需要我们下载一些工具。

Flame Graphs  

https://github.com/brendangregg/FlameGraph.

到这里下载最新的版本example.zip

os_explain

http://blog.tanelpoder.com/files/scripts/tools/unix/os_explain

使用方法:

Session1:找出OSPID,并运行SQL语句,先让数据缓存到内存当中;

Session2:运行perf record 进行数据采集

perf record -a -g -F100000 -p pid

Session1:再次运行SQL语句

Session 2:按CTRL-C停止采集

Perf的数据有了,下面就是生成图了

当然,每一种图的执行方法不一样。详细可以参考:

http://externaltable.blogspot.com/2014/05/flame-graphs-for-oracle.html

 

分享到: 更多

Post a Comment

Your email is never published nor shared. Required fields are marked *