Ubuntu 的 PHP 会话垃圾收集 cron 作业需要 25 分钟才能运行,为什么?

Ubuntu 的 PHP 会话垃圾收集 cron 作业需要 25 分钟才能运行,为什么?

Ubuntu 设立了一个 cron 作业,用于查找并删除旧的 PHP 会话:

# Look for and purge old sessions every 30 minutes
09,39 *     * * *     root   [ -x /usr/lib/php5/maxlifetime ] \
   && [ -d /var/lib/php5 ] && find /var/lib/php5/ -depth -mindepth 1 \
   -maxdepth 1 -type f -cmin +$(/usr/lib/php5/maxlifetime) ! -execdir \
   fuser -s {} 2> /dev/null \; -delete

我的问题是,这个过程需要很长时间才能运行,并且需要大量的磁盘 IO。这是我的 CPU 使用率图表:

CPU 使用率图表

清理运行由蓝绿色峰值表示。在这段时间的开始,PHP 的清理作业被安排在默认的 09 和 39 分钟时间。在 15:00,我从 cron 中删除了 39 分钟的时间,因此两倍大小的清理作业运行频率减半(您可以看到峰值宽度增加一倍,频率减少一半)。

以下是 IO 时间的相应图表:

输入输出时间

以及磁盘操作:

磁盘操作

在高峰期,大约有 14,000 个会话处于活动状态,可以看到清理过程运行了整整 25 分钟,显然占用了 CPU 的一个核心的 100%,并且整个期间似乎占用了 100% 的磁盘 IO。为什么它会如此耗费资源?ls清理会话目录/var/lib/php5只需要几分之一秒。那么为什么清理旧会话需要整整 25 分钟呢?我可以做些什么来加快速度吗?

该设备的文件系统当前为 ext4,在 64 位 Ubuntu Precise 12.04 上运行。

编辑:我怀疑负载是由于不寻常的进程“fuser”造成的(因为我预计简单的进程rm会比我看到的性能快得多)。我将删除 fuser 的使用,看看会发生什么。

答案1

移除fuser应该有帮助。此作业fuser对找到的每个会话文件运行一个命令(检查文件是否当前已打开),在具有 14k 个会话的繁忙系统中,这很容易花费几分钟。这是一个 Debian 错误(Ubuntu 基于 Debian)。

除了 memcached,您还可以尝试使用 tmpfs(内存中的文件系统)来存储会话文件。与 memcached 一样,这会在重启时使会话无效(可以通过在关机脚本中的某个位置备份此目录并在启动脚本中恢复来解决),但设置起来会容易得多。但这对解决fuser问题没有帮助。

答案2

恭喜您拥有一个受欢迎的网站,并设法让它一直在虚拟机上运行。

fuser如果您每天确实要吸引 200 万次页面浏览量,那么您将在文件系统中堆积大量 PHP 会话,并且无论您使用还是rm吸尘器,都需要很长时间才能删除它们。

此时我建议您研究其他方法来存储您的会话:

  • 一个选择是将会话存储在memcached。速度极快,但如果服务器崩溃或重新启动,所有会话都将丢失,并且每个人都会被注销。
  • 您还可以将会话存储在数据库中。这会比 memcached 慢一点,但数据库是持久的,您可以使用简单的 SQL 查询清除旧会话。不过,要实现这一点,您必须编写自定义会话处理程序

答案3

因此,这里用户建议的 Memcached 和数据库会话存储选项都是提高性能的好选择,各有优缺点。

但通过性能测试,我发现此会话维护的巨大性能成本几乎完全归因于fusercron 作业中的调用。这是恢复到 Natty / Oneiric cron 作业后的性能图表,该作业使用rm而不是fuser来修剪旧会话,切换发生在 2:30。

CPU使用率

已用 IO 时间

磁盘操作

您可以看到,Ubuntu 的 PHP 会话清理导致的周期性性能下降几乎完全消除了。磁盘操作图中显示的峰值现在幅度小了很多,并且与该图所能测量的一样小,显示了一个短暂的小中断,而之前的服务器性能在 25 分钟内显著下降。额外的 CPU 使用率已完全消除,这现在是一项 IO 密集型工作。

(一个不相关的 IO 作业在 05:00 运行,CPU 作业在 7:40 运行,这两个作业都导致这些图表上出现各自的峰值)

我现在运行的修改后的 cron 作业是:

09 *     * * *     root   [ -x /usr/lib/php5/maxlifetime ] && \
   [ -d /var/lib/php5 ] && find /var/lib/php5/ -depth -mindepth 1 \
   -maxdepth 1 -type f -cmin +$(/usr/lib/php5/maxlifetime) -print0 \
   | xargs -n 200 -r -0 rm

答案4

对于这种流量,您不应该将会话放在磁盘上。您应该使用类似 memcache 的东西。您所要做的就是设置 php,不需要更改代码。例如

http://www.dotdeb.org/2008/08/25/storing-your-php-sessions-using-memcached/

之所以花费这么长时间,是因为它需要对大量文件进行排序,以确定哪些文件可以删除。Memcache 可以根据您在代码中设置的会话长度自动使这些文件过期。

相关内容