-
-
Notifications
You must be signed in to change notification settings - Fork 2.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Please use TCP_NODELAY at least for websockets. #664
Comments
But, be careful. see tornadoweb/tornado@91fd578 |
As I see tornado toggles NODELAY at the end of every HTTP request handling. That may make sense in some situations but I'd like to have at least a flag for configuring behavior and benchmark showing the effort. For websockets there is a method for switching NODELAY on (disabled by default). It may be useful but user can do it right now by |
|
|
+1 to have this as an option. While in most situations it's better to set this flag on, this is not a general rule. However, having some API nicer than
won't hurt a lot. |
|
I don't want change aiohttp defaults without benchmarking. |
This problem is not reproduced in bulk data transfer, like file downloading/uploading or for large HTTP bodies. Problem appear when TCP is used for short message passing pattern (i.e. websockets or small http responses, long-polling), since kernel adds dealy before actual message send. |
I think TCP_NODELAY is reasonable default. We just just need api and I'd add TCP_CORK support as well |
Btw asyncio does not buffer writes, same for aiohttp, so even small responses generate multiple 'send' calls. It worse for chunked response, aiohttp sends delimiters as separate writes. |
Asyncio buffers writes only under io pressure |
OKAY. I will clear some points.
In that scheme, everything works perfectly. But for websockets, nodelay is set unconditionally (?). Also torando docs states that delay may be raised by kernel up to 500 ms (!).
|
I discovered effect of setting TCP_NODELAY. NGINX uses different approach than tornado. It has tcp_nodelay configuration parameter (on by default) which is applied only for keepalived connections. Also it has tcp_nopush param for forcing TCP_CORK only if sendfile is used. That maybe good for NGINX. Effort for pushing CORK before sending headers need additional investigation. I'm ok now for setting TCP_NODELAY on websocket negotiation. |
tcp_cork should configurable Sent from my iPhone
|
Okay, good news about websockets. It seems that 0ac669f sets TCP_NODELAY for any http response....does not it ? I think it should do so only for websockets and tornado approach for non-websockets |
It's not for any response but for keepalived connections only. |
what about chunked responses? |
Basically, any response that have notion of stream need tcp_nodelay |
Agree. But aiohttp has no knowledge is response is streamed or not. |
I'd make 'on' by default and off manual. But I am fine with your approach |
Well. @asvetlov : If nginx never send small portions of data, or resend all data it received in another socket, it is good to set nodelay unconditionally in order to, surprise, minimize delay, but also minimize packets per second. As @fafhrd91 said, aiohttp does send small pieces to kenrel in different send syscalls. So, to make tcp perform best, we should either turn nodelay unconditionally and optimize our code, or set and remove nodelay as tornado does. Seem this is clean to understand. If not - I will try to describe in more details. In current situation (where you enabled nodelay for all keepalive connections), performance will be slightly lower than before, since each delimiter of chunked response will be sent in separate tcp packet. It is not hard to check it, using tcpdump. Why not to use tornado approach ?! No one say why it is worse. |
Because I agree with @fafhrd91 -- nodelay should be on by default, both for websockets and stream responses. I feel this way is a bit better than tornado approach. Also asyncio has no such callback as tornado has. |
UPD. Thus TCP_CORK/TCP_PUSH optimization is not bad and make sense at least for file transferring but not extremely important. |
OK, what about this: https://github.com/KeepSafe/aiohttp/blob/master/aiohttp/protocol.py#L732 ? :) :) |
Good catch! |
But anyway, chunk header and chunk data will be written in separate syscalls, so tcp cork or temporatily switching nodelay off will improve performance. Same thing for other places like http headers and body. |
Actual behavior is a bit more complicated, see my message in #680 #680 (comment) |
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
Tornado use TCP_NODELAY at the end of every message. i.e. when tornado knows that this is last chunk written, it issue TCP_NODELAY setting to 1. After write buffer is flushed, it set TCP_NODELAY to 0.
This is helps alot. For example, see https://github.com/benjamin-hodgson/asynqp/pull/41/files and tornado sources against TCP_NODELAY
The text was updated successfully, but these errors were encountered: