【问题标题】:Detecting hanging processes in Perl/MySQL (FreeBSD)在 Perl/MySQL (FreeBSD) 中检测挂起的进程
【发布时间】:2012-09-04 22:43:39
【问题描述】:

我有一个在 FreeBSD/Apache 系统上运行的 Perl 脚本,它通过 DBI 对 MySQL 数据库进行一些简单的查询。服务器相当活跃(每天 15 万页),并且每隔一段时间(最多一分钟一次)就会导致进程挂起。我怀疑文件锁可能会阻止读取,或者可能是 SQL 调用,但我无法弄清楚如何获取有关挂起过程的信息。

Per Practical mod_perl 听起来像是识别让我头疼的操作的方法是系统跟踪、perl 跟踪或交互式调试器。我收集系统跟踪是 FreeBSD 上的 ktrace,但是当我附加到顶部的一个挂起进程时,进程被杀死后的唯一输出是:

50904 perl5.8.9 PSIG  SIGTERM SIG_DFL

这对我没有多大帮助。任何人都可以提出更有意义的方法吗?我在 Unix 管理员方面并不是很先进,所以如果我听起来很愚蠢,您的耐心将不胜感激.... :o)

【问题讨论】:

  • 我会尝试添加一些信号处理和日志记录以开始。如果可以的话,启用 mysql 日志记录肯定会有所帮助,以便查看在锁定时间戳之前/期间做了什么——这可能会提供一些进一步的见解。你碰巧在使用线程吗?您可以发布的任何日志信息都可能有助于任何潜在的 SO 用户也可以帮助您。对于信号处理,总是有 posix 模块 - perldoc.perl.org/POSIX.html#POSIX%3a%3aSigAction
  • 最好的情况是如果有人能识别出错误,否则你必须开始记录你的出路。我对日志进行了后处理,因此每个请求将它们提炼成一行,仅包含对主要状态更改的描述以及所需的开始和结束状态。然后,您应该能够找到没有所需结束状态的行,并使用最后记录的状态作为提示,您应该在哪个方向进行更多记录。

标签: mysql perl apache freebsd dbi


【解决方案1】:

如果我理解正确,您的 Perl 进程在查询 MySQL 时挂起,而 MySQL 本身仍然可以运行。 MySQL 服务器具有嵌入式故障排除功能,log_slow_queries 选项。将以下几行放入您的 my.cnf 即可实现这一技巧:

[mysqld]
log_slow_queries = /var/log/mysql/mysql-slow.log
long_query_time = 10

之后,重新启动或重新加载 MySQL 守护程序。让服务器运行一段时间以收集统计数据并分析发生了什么:

mysqldumpslow -s at /var/log/mysql/mysql-slow.log | less

在我的一台服务器上,最高记录(-s at 按平均查询时间排序,顺便说一句)是:

Count: 286  Time=101.26s (28960s)  Lock=14.74s (4214s)  Rows=0.0 (0), iwatcher[iwatcher]@localhost
  INSERT INTO `wp_posts` (`post_author`,`post_date`,`post_date_gmt`,`post_content`,`post_content_filtered`,`post_title`,`post_excerpt`,`post_status`,`post_type`,`comment_status`,`ping_status`,`post_password`,`post_name`,`to_ping`,`pinged`,`post_modified`,`post_modified_gmt`,`post_parent`,`menu_order`,`guid`) VALUES ('S','S','S','S','S','S','S','S','S','S','S','S','S','S','S','S','S','S','S','S')

FWIW,它是一个拥有超过 30K 帖子的 WordPress。

【讨论】:

  • 我不认为是 MySQL,因为没有脚本的那部分就发生了锁定。我最终将服务器移动到使用 fastcgi 的 Ubuntu/Nginx 机器上。我不得不对皮肤脚本进行一些重写,但罕见的锁定似乎仍然发生。我有一个 cron 脚本,它检查锁定的进程,然后重新启动 FCGI 包装器,这是一个非常糟糕的解决方案,但确实让盒子保持运行。99.99% 的时间。我尝试逐行浏览脚本,但没有跳出任何内容。我的同事建议我将整个事情转移到 PHP,这说起来容易做起来难。
  • 众所周知,FCGI 包装器很难调优;确实,我经历过许多突然的锁定。另一方面,Nginx 与 PSGI 配合得非常好。您可以尝试使用 PSGI 包装您的 CGI,例如使用 metacpan.org/module/CGI::Emulate::PSGI
  • 请注意,这样做可能有更好或更坏的方法;您甚至可以将旧的 cgi-bin 插回 Nginx:metacpan.org/module/Plack::App::CGIBin(可能会慢得要命,但无法占用足够的资源来挂起服务器)。
【解决方案2】:

Ktracing 只为您提供系统调用、信号 I/O 和名称处理。它会非常快速地生成大量数据。因此,找出问题点可能并不理想。

如果您可以看到脚本的标准输出,请在代码中围绕可疑的问题点放置一些策略性地放置打印语句。然后运行程序应该会显示您是否发生了挂起:

print "Before query X"
$dbh->do($statement)
print "After query X".

如果您看不到标准输出,请使用例如Sys::Syslog perl 模块,或调用 FreeBSD 的 logger(1) 程序将调试信息写入日志文件。将其封装到 debug() 函数中并使用它或打印语句可能是最简单的。

编辑:如果您不想在磁盘上进行大量日志记录,请将日志记录信息写入套接字(Sys::Syslog 支持 setlogsock()),然后编写另一个脚本到从该套接字读取并将调试文本转储到终端,并以接收数据的时间为前缀。一旦程序挂起,您就可以看到它在做什么。

【讨论】:

  • 很好的答案。问题是脚本在锁定一次之前运行了一百万次,所以这将是大量的数据记录,我想会给服务器带来一些负载。鉴于锁定极为罕见的限制,您如何建议我在没有过多服务器负载和大量误报的情况下跟踪锁定?
猜你喜欢
  • 1970-01-01
  • 2013-08-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-05
  • 2011-01-24
  • 2012-12-20
  • 1970-01-01
相关资源
最近更新 更多