Nginx和php-fpm:无法摆脱502和504错误

时间:2012-07-19 10:58:47

标签: linux performance nginx php

我有一个ubuntu服务器和一个相当高的网站。服务器是:

  • 致力于nginx,使用php-fpm(没有apache),mysql位于不同的机器上
  • 拥有8 GB的RAM
  • 每秒获取大约2000个请求。

根据top命令,每个php-fpm进程占用大约65MB的RAM:

top command

免费记忆:

admin@myserver:~$ free -m
             total       used       free     shared    buffers     cached
Mem:          7910       7156        753          0        284       2502
-/+ buffers/cache:       4369       3540
Swap:         8099          0       8099

问题

最近,我遇到了很大的性能问题。非常大的响应时间,非常多Gateway Timeouts,在晚上,当负载变高时,90%的用户只看到“找不到服务器”而不是网站(我似乎无法重现这一点)


日志

我的Nginx错误日志中充满了以下消息:

2012/07/18 20:36:48 [error] 3451#0: *241904 upstream prematurely closed connection while reading response header from upstream, client: 178.49.30.245, server: example.net, request: request: "GET /readarticle/121430 HTTP/1.1", upstream: "fastcgi://127.0.0.1:9001", host: "example.net", referrer: "http://example.net/articles"

我尝试过切换到unix socket,但仍然会遇到这些错误:

2012/07/18 19:27:30 [crit] 2275#0: *12334 connect() to unix:/tmp/fastcgi.sock failed (2: No such file or directory) while connecting to upstream, client: 84.
237.189.45, server: example.net, request: "GET /readarticle/121430 HTTP/1.1", upstream: "fastcgi://unix:/tmp/fastcgi.sock:", host: "example.net", referrer: "http
://example.net/articles"

php-fpm日志充满了这些:

[18-Jul-2012 19:23:34] WARNING: [pool www] seems busy (you may need to increase pm.start_servers, or pm.min/max_spare_servers), spawning 32 children, there  are 0 idle, and 75 total children

我尝试将给定参数增加到100,但似乎还不够。


CONFIGS

这是我目前的配置

PHP-FPM

listen = 127.0.0.1:9001
listen.backlog = 4096
pm = dynamic
pm.max_children = 130
pm.start_servers = 40
pm.min_spare_servers = 10
pm.max_spare_servers = 40
pm.max_requests = 100

nginx的

worker_processes  4;
worker_rlimit_nofile 8192;
worker_priority 0;
worker_cpu_affinity 0001 0010 0100 1000;

error_log  /var/log/nginx_errors.log;

events {
    multi_accept off;
    worker_connections  4096;
}


http {
    include       mime.types;
    default_type  application/octet-stream;

    access_log off;
    sendfile        on;
    keepalive_timeout  65;
    gzip  on;

    # fastcgi parameters
    fastcgi_connect_timeout 120;
    fastcgi_send_timeout 180;
    fastcgi_read_timeout 1000;
    fastcgi_buffer_size 128k;
    fastcgi_buffers 4 256k;
    fastcgi_busy_buffers_size 256k;
    fastcgi_temp_file_write_size 256k;
    fastcgi_intercept_errors on;

    client_max_body_size 128M;

    server {
        server_name example.net;
        root /var/www/example/httpdocs;
        index index.php;
        charset utf-8;
        error_log /var/www/example/nginx_error.log;

        error_page 502 504 = /gateway_timeout.html;

        # rewrite rule
        location / {
            if (!-e $request_filename) {
                rewrite ^(.*)$ /index.php?path=$1 last;
            }
        }
        location ~* \.php {
            fastcgi_pass 127.0.0.1:9001;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
            fastcgi_param PATH_INFO $fastcgi_script_name;
            include fastcgi_params;
        }
    }
}

对于如何识别问题以及我可以调整哪些参数来解决这个问题,我将非常感激。或者8GB的内存对于这种负载来说还不够?

5 个答案:

答案 0 :(得分:1)

一些问题。仍然值得用这么繁忙的网站修复它们。 MySQL可能是现在的根本原因。但从长远来看,你需要做更多的工作。

<强>缓存

我看到你的一个错误消息显示对php上游的get请求。对于如此高流量的站点(如你所提到的2000 r / s),这看起来不太好。这个页面(/ readarticle / 121430)似乎是一个完全可缓存的页面。首先,您可以使用nginx缓存此类页面。查看fastcgi cache

GET /readarticle/121430

<强> PHP-FPM

pm.max_requests = 100

该值表示在提供100个请求后,php-fpm master将终止进程。 php-fpm使用该值来对抗第三方内存泄漏。您的网站非常繁忙,速度为2000r / s。您的最大子进程为130,每个进程最多只能提供100个请求。这意味着在13000/2000 = 6.5秒后,所有这些都将被回收。这太过分了(每秒有20个进程被杀死)。只要您没有看到内存泄漏,您至少应该以1000的值开头并增加该数字。有人在生产中使用10,000。

<强> nginx.conf

  • 问题1:

        if (!-e $request_filename) {
            rewrite ^(.*)$ /index.php?path=$1 last;
        }
    
    应该用更高效的try_files替换

        try_files $uri /index.php?path=$uri;
    

您可以保存额外的 if 位置块和正则表达式重写规则匹配。

  • 问题2:使用unix socket会比使用ip节省更多时间(根据我的经验,大约10-20%)。这就是php-fpm默认使用它的原因。

  • 问题3:您可能有兴趣在nginx和php-fpm之间建立keepalive连接。在nginx官方网站上给出了一个例子here

答案 1 :(得分:1)

我需要看看你的php.ini设置,我不认为这与MySQL有关,因为你看到它的套接字错误。此外,这是在一段时间后开始发生的事情,还是在服务器重新启动时立即发生的事情?

尝试重新启动php5-fpm守护程序,看看在查找错误日志时会发生什么。

检查您的php.ini文件以及通常位于/ etc / nginx / fastcgi_params中的所有fastcgi_params。你要做的事情有很多例子。

此外,您是否启用了apc php缓存扩展?

如果您在灯堆上,它将在您的php.ini文件中看起来像这样:

延长= apc.so
....
apc.enabled = 0

从命令行执行一些mysql连接负载测试也可能没什么坏处,看看结果是什么。

答案 2 :(得分:1)

设置nginx微型也会有所帮助。 这将在几秒钟内提供相同的响应。

http://seravo.fi/2013/optimizing-web-server-performance-with-nginx-and-php 有一些关于nginx性能的好信息。 亲自跟着那个,我很开心。

答案 3 :(得分:0)

为了回答这个问题:

You should check your MySQL server. Probably it's overloaded or it limits count of parallel MySQL connections. You should find the bottleneck. And according to your top screenshot it doesn't look like either RAM or CPU, then it's most likely I/O. - @VBrat

您未来可能想要做的事情:

1-增加RAM大小。

2-使用缓存。请参阅this article了解缓存如何加快您的网站速度

3-减少执行的查询数量。

答案 4 :(得分:0)

  • 设置PHP的APC扩展(检查/配置)
  • MySQL - 检查配置,索引,慢查询
  • 安装并配置Varnish。这可以缓存页面请求,并且在减少需要进行的php请求和mysql查询的数量方面非常有用。使用cookies / ssl可能会很棘手,但在其他方面并不太困难且非常值得运行