3 ms·
I'm skeptical of the performance numbers. First, like others here I don't believe nginx's performance will be a bottleneck for HTTP/2. Beyond that, I suspect th
by scottlamb 12y ago
I'm skeptical of the performance numbers. First, like others here I don't believe nginx's performance will be a bottleneck for HTTP/2. Beyond that, I suspect there are cases in which this code is much worse than nginx.
Here's one. Look at the example request loop on <https://github.com/h2o/picohttpparser/> https://github.com/h2o/picohttpparser/>. It reads from a socket, appending to an initially-empty buffer. Then it tries to parse the buffer contents as an HTTP request. If the request is incomplete, the loop repeats. (h2o's lib/http1.c:handle_incoming_request appears to do the same thing.)
In particular, phr_parse_request doesn't retain any state between attempts. Each time, it goes through the whole buffer. In the degenerate case in which a client sends a large (n-byte) request one byte at a byte, it uses O(n^2) CPU for parsing. That extreme should be rare when clients are not malicious, but the benchmark is probably testing the other extreme where all requests are in a single read. Typical conditions are probably somewhere between.
- zzzcpan 12y agoYou are incorrect, modern clients are fast and requests typically reside in buffers by the time event driven webservers decide to read them. Nginx had parsing with state retention because of the simple idea to handle large amounts of slow clients, which was a problem back when nginx was born. As it turned out later it didn't help with malicious clients at all, because costs to retain clients' connections and get and process each new portion of data were still very high. Instead, accept filters were used and to this day are advised in such situations by nginx people.
- scottlamb 12y ago> You are incorrect, modern clients are fast and requests typically reside in buffers by the time event driven webservers decide to read them. Hmm. Not sure if that's universally true. I've heard that in some cases HTTP requests can be quite large due to having several cookies, long strings of Accept: garbage, etc. My impression was that this could make them not only exceed the MSS (thus be in multiple packets) but also the congestion window (thus be in multiple round trips). It doesn't matter then how fast the client code is. On looking a little now, my information may be old. Apparently Linux increased the default initial congestion window back in 2011: https://www.igvita.com/2011/10/20/faster-web-vs-tcp-slow-start/ https://www.igvita.com/2011/10/20/faster-web-vs-tcp-slow-sta... . Is the same true for all the widely-deployed versions of iOS, Windows, and OS X? > Instead, accept filters were used and to this day are advised in such situations by nginx people. Hadn't seen that before: http://www.freebsd.org/cgi/man.cgi?query=accf_http&sektion=9&apropos=0&manpath=FreeBSD+10.1-RELEASE http://www.freebsd.org/cgi/man.cgi?query=accf_http&sektion=9... Interesting feature, and certainly would the initial congestion window problem, but there doesn't seem to be an equivalent on Linux.
- zzzcpan 12y ago> in some cases HTTP requests can be quite large Sure. I might have slightly overgeneralized some things to illustrate the point. > equivalent on Linux TCP_DEFER_ACCEPT is something similar on Linux
- scottlamb 12y ago> TCP_DEFER_ACCEPT is something similar on Linux Not similar enough. In the case I was describing, there are some bytes to read but not a full HTTP request. TCP_DEFER_ACCEPT prevents accept() from returning until there are some bytes to read. That doesn't help.