如何判断程序处于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的文章。

 

 

ldd3学习之十二(2):高级字符驱动程序操作--等待队列,阻塞I/O,休眠

在应用程序调用read,write时,若驱动程序无法立即满足要求,该如何响应?驱动程序应该(默认)阻塞该进程,将其置入休眠状态直到请求可继续。1.休眠进程被置为休眠,意味着它被标识为处于一个特殊的状态...

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

AIO 简介 Linux 异步 I/O 是 Linux 内核中提供的一个相当新的增强。它是 2.6 版本内核的一个标准特性,但是我们在 2.4 版本内核的补丁中也可以找到它。AIO 背后的基本思...
  • undoner
  • undoner
  • 2014年05月13日 21:33
  • 824

应用I/O口的相关程序

  • 2013年05月02日 21:46
  • 354KB
  • 下载

java实现简单聊天程序(集合,线程,I/O,网络编程)

这半个月的大作业,程序有一些不完善的地方有待提高,但是基本的聊天室功能已经完善 还没有接触javaFx所以用了swing做了简陋的界面 截图: 客户端: import java....
  • Wyx_wx
  • Wyx_wx
  • 2017年06月20日 22:35
  • 132

OpenCV之highgui 模块. 高层GUI和媒体I/O: 为程序界面添加滑动条 OpenCV的视频输入和相似度测量 用OpenCV创建视频

为程序界面添加滑动条 在以前的教程中 (例如 linear blending 和 brightness and contrast adjustments)你有可能注意到需要 input 一些...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:如何判断程序处于I/O等待
举报原因:
原因补充:

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