PHP, Nginx, and Output Flushing

Alright, so one of the few hangups I’ve ran into with moving from Apache to Nginx was output buffering. Now, we have a few administrative tools we use to perform large operations on our library and data. These scripts can take normally 3-5 minutes to run, and they output their progress and what step they are on as they run. The way they do this is after ever step in PHP I issue the same two commands:

ob_flush(); // Flush anything that might be in the header output buffer
flush(); // Send contents so far to the browser

Well, with Nginx, it will wait for an entire response from the PHP-FPM instance before sending data to the browser. This is because traditionally the time to generate the response is less than the time to send the response to the browser, so Nginx will let the CGI instance finish as quick as possible to free it up for other requests. Well, even if I called ob_flush() and flush(), Nginx would wait for the entire response before sending it to the client’s browser. So, for our staff panel, I had to disable this buffering. It took a lot of scouring the web, but I finally figured it out:

Nginx Configuration

You need to set a few variables. I couldn’t actually figure out how to disable the buffer for Nginx, but I could set it very low on a per location configuration.

So I have the following location configurations:

    location ~ \.php$ {
        include /etc/nginx/fastcgi_params;
        fastcgi_index index.php;
        fastcgi_param  SCRIPT_FILENAME  /path/to/public_html/$fastcgi_script_name;
        fastcgi_read_timeout 600;
        fastcgi_buffer_size   1k;                              
        fastcgi_buffers       128 1k;  # up to 4k + 128 * 4k
        fastcgi_max_temp_file_size 0;
        gzip off;

The important configurations are:

fastcgi_buffer_size   1k;                              
fastcgi_buffers       128 1k;  # up to 1k + 128 * 1k
fastcgi_max_temp_file_size 0;
gzip off;

So I set the fastcgi_buffer_size and buffers to 1k. Then, you need to set the max temp file size to 0. Nginx by default will start to buffer on the disk. By setting it to 0 it will send it to the browser. The last piece of the puzzle I missed was turning gzip off, because it would try to buffer, even if it exceeded 1k, to compress the response.

Now, to get it to work, in my php script I echo out 1k worth of html commented out text to ensure everything else after it gets sent to the browser.

Now, I don’t recommend these settings for busy productions servers. However, only 3 people use this staff panel, so the performance differences are extremely low.

Justin is currently the Director of Development for the Deseret News. He is active in the Utah Open Source community. He is an advisory member of the Utah Open Source Foundation, and helps with the anual Utah Open Source Conference. He primarily focuses on PHP, MySQL, Redis, HTML, CSS, jQuery, and JavaScript. When he gets the time, he enjoys to play jazz piano. Read More

Tagged with: , , ,
Posted in Programming