Recently I write a django service to produce very large data in response, about 10GB data per request or even larger sometimes.
When I use python manage.py runserver
to test service, there is no problem. But when use nginx + uwsgi to support service, I can't get the complete response at the client side. At the same time, there is an error log in uwsgi.log and a regular log notice that uswgi has finished request processing:1
2
3Fri Feb 88 88:88:88 2088 - uwsgi_response_write_body_do() TIMEOUT !!!
OSError: write error
GET REQUEST-URL => generated 8888888888 bytes in 8888 msecs (HTTP/1.1 200) 8 headers in 888 bytes
When uwsgi outputs these logs, the client still receives response data until the size of received equal to the generated size output in server log. And the generated size is smaller than the full size of response. So I think there is a large buffer in Nginx. Uwsgi writes response to Nginx actively and the speed is very fast because they are in same machine. But Nginx writes response to client is slow. If Nginx stores response data in buffer, uwsgi's write request will block when buffer is full. If buffer size is very large, uwsgi will wait a long time before Nginx clears its buffer and write request timeout.
Only in this way the Nginx can still write data to client when uwsgi finishs processing and close response stream.
According to ngx_http_uwsgi_module's document:
When buffering is enabled, nginx receives a response from the uwsgi server as soon as possible, saving it into the buffers set by the uwsgi_buffer_size and uwsgi_buffers directives. If the whole response does not fit into memory, a part of it can be saved to a temporary file on the disk. Writing to temporary files is controlled by the uwsgi_max_temp_file_size and uwsgi_temp_file_write_size directives.
There are memory buffers and temporary file buffers. The default size of memory buffers is only a few kilobytes. But the default max size of temporary file buffers is 1024MB, which is approximately equal to the generated size in uwsgi log.
In order to solve this problem, we can just disable temporary file buffers, use the directive uwsgi_max_temp_file_size 0;
.
A memory buffer of a few kilobytes is ok because it will not block uwsgi' write request much time.
But as the previous analysis, if the transmission speed between Nginx and client side is far slower to the speed between Nginx and uswgi, the problem will come up no matter how smaller the buffer is.
As the implementation of Django and uwsgi, uwsgi read a block of data and write to response stream, if the block size is large enough and the transmission speed to the client side is slow enough, the problem will come up even all buffers in Nginx disabled. Because the block can be considered as a different form of buffer.
So slower transmission speed to client side means the smaller size of buffer we can use.
And we don't know user's network conditions, what we can do is only disable buffers.