5 ms·
> Not an NGINX problem either
by oarsinsync 11y ago
> Not an NGINX problem either
- Dylan16807 11y agoThere is a header that says that, but it actually was an NGINX problem.
- masklinn 11y agoNot really. nginx's implemented behaviour seems more or less what anyone writing socket code would do: write to buffer, then wait with timeout to write more, if timeout is hit consider the write failed. The problem here is that (TIL) on linux the "writable socket" state behaves completely differently than the "readable socket" one, and a socket can be effectively writeable even though poll(2) reports that it isn't.
- Dylan16807 11y agoThe TCP layer is already perfectly capable of detecting if a connection has failed. NGINX wanted to do something extra, and did it incorrectly.
- masklinn 11y ago> NGINX wanted to do something extra, and did it incorrectly. Having a timeout on a poll (or select) is not "something extra". it's something entirely normal and necessary for any non-trivial software, especially public-facing ones.
- Dylan16807 11y agoWhat? They wanted a timeout on how long it takes X bytes to send on an active TCP connection. That has nothing to do with poll/select timeouts.
- masklinn 11y ago> What? They wanted a timeout on how long it takes X bytes to send on an active TCP connection. That has nothing to do with poll/select timeouts. nginx called send(file), then polled the socket for write with the timeout, closing the connection if the timeout was hit. It has everything to do with poll/select timeouts, and especially with Linux letting poll hit timeouts when waiting on effectively writable sockets.
- Dylan16807 11y ago> writable sockets The goal of NGINX here is not to measure whether a socket can consume any data whatsoever. A connection that consumes 1 byte every 15 seconds is still considered stalled, and should be killed. Using the time between sendfile invocations is not the goal, it's a means toward implementing a minimum rate, and they implemented a minimum rate the wrong way. It's an X Y problem and that's not the kernel's fault.
- pjc50 11y ago.. and the correct way to do this is SO_SNDTIMEO.
- masklinn 11y agoThat's for blocking IO, it doesn't work on evented IO: > [SO_RCVTIMEO and SO_SNDTIMEO] only have effect for system calls that perform socket I/O (e.g., read(2), recvmsg(2), send(2), sendmsg(2)); timeouts have no effect for select(2), poll(2), epoll_wait(2), and so on. And from my understanding would have the same effect as a timeout on select/poll, so it's not the correct way to do anything.
- zzzcpan 11y agoThe problem is a fundamental one. Nginx, like many other event loop implementations of servers, presumes that kernel code behaves consistently, precisely and correctly, instead of treating it like a black box, that sometimes lies about things or behaves completely incorrectly, it's not the first time this happened. Any correct event loop implementation should take reported poll events under advisement only and try to schedule reads and writes independently from that.
- scurvy 11y agonginx is also resetting the connection instead of closing it. That's also a bug (separately). The use of a TCP reset here violates RFC and Postel's robustness maxim. Be liberal on what you accept and be conservative in what you send.
- NicoJuicy 11y agoThis was a unix stack problem, but it could be fixed in nginx :)
- Dylan16807 11y agoNGINX decided to have a maximum time between calls to sendfile, no matter whether the data is actually transferring or not. In configuring this setup, someone had a bad intuition about how often NGINX would end up calling sendfile. It is a problem entirely of NGINX's devising, not a unix stack problem.