在 EC2 上运行大型 mod_perl 应用程序时,我们注意到实例的 CPU 使用率在重新启动或正常重启之间逐渐上升。
当前设置:CentOS 5.4、m2.4xlarge 实例、带有 mod_perl 的 apache 1.3。
我们第一次注意到这一点是在跟踪应用程序的 memcached 请求速度时。随着每个 apache 子进程的老化,对同一主机上运行的 memcached 实例进行读写所需的时间会更长。我们发现每小时执行一次 apachectl graceful 可以防止这种情况发生,但每次都会导致负载激增。
导致这种速度减慢的原因在我们的 ganglia 监控中也很明显。我们一直在运行一台服务器,没有每小时重启一次,尽管它处理请求的速度与其他服务器相同,但 CPU 使用率始终较高。“负载”数字大致相同,但系统 CPU 数字较高。
我正在绞尽脑汁想弄清楚这里发生了什么,因为每小时重新启动 apache 子进程意味着我们错过了进程内缓存的好处。
有人见过类似的事情吗?虽然我们在数据中心之一的真实硬件上运行时,这似乎不会影响我们的应用程序,尽管我们在那里使用 SUSE。
更新 1:感谢 voretaq7。我们选择了具有 68GB RAM 的 m2.4xlarge 实例类型。我们当前的 Apache 调优(始终运行 160 个子进程)只使用了大约一半,因此我们关闭了交换。没有任何等待 CPU 或被盗 CPU,因为实例大小意味着我们不与任何其他人共享底层主机。我们看到了用户和系统 CPU,系统 CPU 比我们每小时进行正常重启的机器上的 CPU 要多。
更新2:我目前正在对三台服务器进行另一项试验。一台每小时运行一次 apachectl 优雅重启,一台设置了 MaxRequestsPerChild = 512,第三台设置了 MaxRequestsPerChild = 64。这是为了尝试找出优雅重启是否以某种方式修复了父服务器,或者子服务器是否只是没有运行那么长时间。我将使用此设置运行 12 小时并比较统计数据。
更新 3:使用较小的 MaxRequestsPerChild 值运行子进程确实会略微改善情况。但是,执行正常重启的主机仍然表现更好。
更新 4:每个主机运行三个 apache 实例(总共 160 个子实例)和三个 memcached。由于只有一个 CPU 核心,我不知道上下文切换的成本是多少。我进行了一次试验,其中一个主机将所有 memcached 固定到 CPU0,将 apache 固定到 CPU1-7。这显著提高了性能。我仍然不知道究竟是什么原因导致 apache 重启之间 CPU 使用率下降,但看起来 CPU 亲和性、偶尔的平稳重启和更短的子生命周期的组合可以加快速度。
# Start the three memcacheds as follows
/bin/taskset --cpu-list 0 /usr/local/bin/memcached -d -p 12345
# Start apache as follows
/bin/taskset --cpu-list 1-7 apachectl start
任何应用于 apache 父进程的 CPU 亲和性都将应用于它衍生的所有子进程。
答案1
上下文切换似乎是 Apache 运行缓慢的主要原因。将 memcached 固定到一个 CPU,将 Apache 固定到所有其他 CPU,速度会大大加快。请参阅更新 4:问题中的详细信息。