Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

> Not an NGINX problem either


There is a header that says that, but it actually was an NGINX problem.


Not 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.


The TCP layer is already perfectly capable of detecting if a connection has failed. NGINX wanted to do something extra, and did it incorrectly.


nginx 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.


> 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.


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.


> 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.


> 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.


The 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.


.. and the correct way to do this is SO_SNDTIMEO.


That'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.


This was a unix stack problem, but it could be fixed in nginx :)


NGINX 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.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: