如何判断程序处于I/O等待

原创 2011年01月07日 16:57:00

 

现象:
程序启动后正常运行,使用prstat -p <PID>看到内存在逐步增加。使用tail -f <logfile>看到不停的有log输出。突然在log打印一条SQL被送往DB Server以后,程序似乎停下来了。没有报错,没有core dump。

 

 

诊断:
程序PID=6208。要求MIT做pfile,pstack,pflags。XuXu帮助我将现场保存到/var/tmp下

 

-rw-r–r–   1 root     other       1788 Jul 18 02:31 /var/tmp/pfiles.6208
-rw-r–r–   1 root     other        668 Jul 18 02:31 /var/tmp/pflags.6208
-rw-r–r–   1 root     other        759 Jul 18 02:31 /var/tmp/prstat.6208
-rw-r–r–   1 root     other       4222 Jul 18 02:30 /var/tmp/pstack.6208

 

PD虽然没有root权限,但是prstat -p还是可以用的

 

bash-2.03$ cat prstat.6208
  PID USERNAME  SIZE   RSS STATE  PRI NICE  TIME    CPU  PROCESS/LWPID
  6208 user        633M  614M sleep   59  -20   0:00.00 0.0% scrubber/5
  6208 user        633M  614M sleep   59  -20   0:00.00 0.0% scrubber/10
  ……(此处我省略了…)

可以发现:

  1. 内存Size和驻留内存RSS稳定在一个固定的值上面,没有变化–>程序没有在进行内存分配和释放
  2. 程序状态一直处于Sleep,CPU=0.0%,程序似乎什么事都不在干
  3. 程序并没有退出,没有类似SEG FAULT– Exit之类的信息显示–>程序正在正常运行。

 

bash-2.03$ cat pflags.6208
6208:   …(此处省略)
  /1:   flags = PR_PCINVAL|PR_ASLEEP [ accept(0x5,0xfd109a28,0xfd109a20,0x1) ]
  /2:   flags = PR_PCINVAL|PR_ASLWP|PR_ASLEEP [ signotifywait() ]
  /3:   flags = PR_PCINVAL|PR_ASLEEP [ read(0xd,0x22738716,0x2010) ]
  /5:   flags = PR_PCINVAL|PR_ASLEEP [ lwp_sema_wait(0xfd20be60) ]
  /8:   flags = PR_PCINVAL|PR_ASLEEP [ lwp_cond_wait(0xfe1d34f0,0xfe1d3500,0xfe1ccd88) ]
  /9:   flags = PR_PCINVAL|PR_ASLEEP [ lwp_cond_wait(0xfe1ccd30,0xfe1ccd18,0x0) ]
  sigmask = 0xffbffeff,0x00001fff
  /10:  flags = PR_PCINVAL|PR_ASLEEP [ door(0x0,0x0,0x0,0x0,0xfc60bd38,0x4) ]

 

所有线程处于Sleep状态,注意到read操作正在I/O等待。LWP号码是3,于是查看pstack找出对应的thread call stack:

 

—————–  lwp# 3 / thread# 1  ——————–
fe29ecc0 read     (d, 22738716, 2010)

 

(具体的调用栈我就不在这里贴出来了,但是这里的call stack已经能够帮助PD方便的定位程序源代码了,可以用gc++filt进行unmangle便于阅读), 于是基本肯定是在DB Read的时候发生I/O等待。这一点也和我们从log中看到的信息符合。XuXu接着帮我确认了这一点。

 

在进行Oracle DB链接的时候,应用程序需要知道链接信息,其中包括Oracle DB的VIP Name和Port。于是我们查看pfiles. 假设端口号是2000。数据库服务器的名字是arrowpigDB.vip.com

 

bash-2.03$ cat pfiles.6208 | grep 2000

        peername: AF_INET 11.11.11.11  port: 2000  (此处的IP和端口是我杜撰的,但是不影响理解)
        peername: AF_INET 11.12.12.12  port: 2000

 

bash-2.03$ /usr/sbin/nslookup 11.12.12.12
Server:    –>此处显示dns服务器的名字
Address:  –>此处显示dns服务器的IP

Name:     arrowpigDB.vip.com  –>说明应用程序到DB的链接已经正确建立,I/O等待发生在DB Server一侧。由此可确定是SQL执行速度太慢。


Address:  11.12.12.12

 

 

解决:
该程序确实使用了一条新的SQL,虽然我觉得SQL的改动很小,只是改动了where:原来的where是:

last_modified between :start_time and :end_time order by last_modified

现在改为:

last_modified=:start_time and item_id>:last_id order by item_id

 

Oracle可以方便的找到应用程序发往DB的SQL. 然后查看执行计划:

 

SQL> explain plan for
select ……. <此处我省略具体的SQL>

Explained.
SQL> @?/rdbms/admin/utlxpls
PLAN_TABLE_OUTPUT
… <此处我省略具体的执行计划>

初步结果是在做DB Join的时候,有一张130GB的表,原来的访问是使用Table Range Scan,而新的SQL却使用Table Access Full。于是我发了一个DB Review Ticket让DBA帮我看怎么解决,是不是需要添加Hint,是不是需要代码改动。等这个Ticket resolve以后,我争取能够理解DBA的Tuning技术,然后补一下关于这个SQL Tuning的文章。

 

 

版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

使用异步 I/O 大大提高应用程序的性能

一直对阻塞、非阻塞、同步和异步概念模糊,在IBM的网站上发现了这篇好文,概念和实践俱佳的一篇文章,实践主要是针对异步非阻塞IO,转载到csdn上跟大家分享。 原文地址:https://www.ibm...

应用I/O口的相关程序

  • 2013-05-02 21:46
  • 354KB
  • 下载

【Linux 驱动】第六章 高级字符驱动程序操作 ----阻塞型I/O

序言:试想如果在驱动方法中的read/write中,当数据不可用时,用户可能调用read,当输出缓冲区满时,设备并未准备好接受数据,这种情况下驱动程序可以阻塞该进程,并且置入休眠状态直到满足条件。 ...

使用异步 I/O 大大提高应用程序的性能

转载:http://www.ibm.com/developerworks/cn/linux/l-async/ AIO 简介   Linux 异步 I/O 是 Linux 内核中提供的一个相当新的...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)