Hacker News new | past | comments | ask | show | jobs | submit login
H2O – an optimized HTTP server and library implementation (github.com/kazuho)
102 points by dochtman on Sept 19, 2014 | hide | past | favorite | 40 comments

As the author of H2O, I would like to leave a comment here.

First of all, the development is still in early stages, please forgive me for the lack of documentation.

That said, below are some high-level design issues that are not addressed by the README.

- it is designed to be pluggable (though not as flexible as Apache), by providing virtual-host-based configuration of generators, output filters and loggers

  - lib/file.c and lib/chunked.c would be a good place to understand their interface if you are interested

  - I am (at the moment) not interested in providing support for input filters
- performance of HTTP parser is likely going to become importance since the ratio of small files being served is expected to increase in HTTP/2; H2O is designed with that in mind

Why is H2O faster than nginx? I've read the source of nginx and it does attempt to be very clean and tightly optimized, which makes me suspicious of H2O. Is there some big architectural advantage or is it less robust in some way?

Please read my other comment here https://news.ycombinator.com/item?id=8342684

I don't trust any benchmark using ab. Use Tsung or Siege.

That said, this library is very clean and easy to use. I just wish it had high-level functions to create sockets, but that's a minor detail.

Good job by Kazuho, as usual.

It uses libuv which you can use to create sockets. http://nikhilm.github.io/uvbook/networking.html#tcp

Looks impressive though benchmarking with "ab" should be taken with a grain of salt.

nginx does a lot of optimization at many level that ab can't figure out.

In short, it only profiles the speed of the HTTP parser and certainly not the network stack.

There are a lot of things that a HTTP server does in order to keep the connections stack "steady" : Disabling the Nagle algorithm at the right moment, gracefully handling failure, managing slow clients the right way, ...

FWIW, Tsung is an awesome benchmarking tool written in erlang : http://tsung.erlang-projects.org/

ab is also very slow, it can be the limiting factor in the benchmarking.

But the nginx http parser is one of the things that is fast, so a faster one is interesting.

I think having a library implementation is very useful as well.

ab has not been the bottleneck in the benchmarks since both servers were pinned to a single core. It is true that ab is too slow for benchmarking a HTTP server running on multiple CPU cores, but it is at least faster than a server only using one core.

Regarding the performance of the HTTP parser, I have heard that picohttpparser (the HTTP/1 parser used by H2O) is much faster than the HTTP parser used by nginx. https://github.com/kazuho/picohttpparser

If that is true, it is likely due to the difference between the approaches the parsers take. Unlike most parsers, picohttpparser does not have a callback-based API. Instead it uses a loop for parsing the HTTP request and header lines.

note: This comment might be biased since I am the author of H2O and picohttpparser.

I believe you when you say that picohttpparser is faster. But is it also correct and secure? Is it fully RFC7230 compliant? Are there no parsing bugs that would allow a security exploit?

It is hard to argue the secureness of a software, but I would say that if there are problems in the library it would be taken seriously.

picohttpparser is the core of HTTP::Parser::XS which is used by many HTTP application servers for Perl (see http://plackperl.org). There are many deployments using it.

Sure! And it supports HTTP/2.0 !

I think it's interesting that performance is mentioned as a primary feature of this. I haven't deployed a web service in nearly 15 years that had the HTTP server as the limiting factor for the performance of a website. Serving small files from RAM really fast just isn't that interesting. For this kind of workload Apache is fast enough for the vast majority of deployments (such a large majority that I've never worked on a deployment that it wasn't, and I've worked on some very large deployments), nginx is fast enough, and H2O is fast enough. Going from "fast enough" to "2x fast enough" isn't going to matter to end users who are waiting on other parts of the system.

The database is still gonna be a bottleneck. The application is still gonna be a bottleneck. The disks are still gonna be a bottleneck. The network is still gonna be a bottleneck (Apache can saturate a Gbit NIC, so can nginx, so can H2O).

I'm not saying this is useless. It looks like a cool project, built by someone really clever (unco is hilariously clever), with lots of good uses (an easily embedded HTTP server library is nothing to sneeze at). I'm saying I think it's weird and unfortunate that so many people focus on performance of the web server, as though it will make a difference for end users. In the vast majority of web server deployments any of the major web servers will do the job and will perform well enough to not be the bottleneck in the system.

Really depends on the scale you're at, but sometimes a couple CPU percent can equal saving a bunch of servers. Obviously the rest of the stack (application, db) has to also be fined tuned or else it's just pre-optimization.

Yes, if you have 50 web servers, saving a couple of CPU % can save a server. That said, I've never worked on a deployment that had 50 web servers, even though I've worked on a couple of major large city newspaper sites, a support site for the #2 or #3 most popular personal computer manufacturer (I don't remember what their rank was at the time), a free hosting provider that had ~12 million websites, and a handful of other interestingly large sites.

Given that a single web server (Apache or otherwise) can serve millions of pages per hour, it's pretty rarefied air to be talking about 50 or 100 or more web servers. There just aren't a lot of people working on sites with that kind of traffic.

I'm really not saying better performing, more efficient, web servers aren't a good thing. It's great that web servers (including Apache) continue to get faster and more efficient. I just don't think it should be the primary thing we're talking about when comparing new servers to tested and proven existing web servers. There are so many other factors, and performance doesn't matter at all if the web server doesn't do what you need it to do, or is insecure, or is unreliable.

Apache was always a badly designed HTTP server. Forking processes for every request was a stupid idea for any public web server (see also: CGI). It's the only reason web servers got Slashdotted back then and why they rarely do now. Forking processes is incredibly expensive compared to an event loop. Event-based HTTP servers inevitably won, it just took a while. Using select() wasn't ideal but then epoll() made things optimal.

The idea that Apache was ever good enough was wrong then and is wrong now. We always needed a more efficient design.

I'm sure someone could write an even more somewhat more efficient version of nginx but I'm not sure they could do it with as many features as nginx has. Which means you probably would just end up switching to nginx at some point. I think Cloudflare uses nginx. They probably could save on machines if they used a more minimal server.

So, you don't know enough to know that Apache is not tied to any particular concurrency model, nor has it used the concurrency implementation you've described (process-per-connection) in decades, yet you feel you know enough to make recommendations for web servers? Even if using Apache in the now quite old prefork MPM, it is a process pool, rather than a process-per-connection that you've described, and is not subject to the performance problems you're alleging (memory usage can be high when using that MPM for high concurrency workloads, but its performance in most deployments is not all that bad).

Further, "forking processes" is actually not incredibly expensive on Linux, and in fact, pthreads on Linux are implemented by the same code (clone() with varying levels of sharing). Forked applications on Linux are pretty much just as fast as threaded applications. It is a myth based on extremely outdated knowledge (fork on Solaris, for instance, and some other UNIX variants, had a history of being slow; but, Linux has always had a very fast fork).

It is true that event-based thread (or process) pool concurrency implementations can provide superior performance to thread- or process-per-connection implementations, for a variety of reasons, but Apache has that covered. I'm gonna guess you've never even used or seen an Apache installation that forked a process for every request (because it's been so long since that was a thing Apache did), so I'm not sure how you could believe it works that way.

Where did you get all of these assertions from? Are there sites out there propagating these crazy claims about Apache? And, if so, why? What does one gain by trash-talking a project that was instrumental in helping build the open web and still powers more websites than any other web server in the world? And, does it well, I might add. There are some good reasons a reasonable admin might choose nginx over Apache. But, they aren't because Apache is a terrible piece of software written by incompetent people.

In short, your comment has negative value, by providing misleading and outright incorrect information.

Edit: And, this is why I hate it when performance is the measuring stick people use to discuss web servers. It begins to seem like it is a useful metric for comparing web servers, when it really is not for 99% (or more) of deployments. Apache is fast enough. nginx is fast enough. Pick your web server based on other characteristics, because otherwise you're almost certainly making decisions based on the wrong things.

> Further, "forking processes" is actually not incredibly expensive on Linux, and in fact, pthreads on Linux are implemented by the same code (clone() with varying levels of sharing). Forked applications on Linux are pretty much just as fast as threaded applications. It is a myth based on extremely outdated knowledge (fork on Solaris, for instance, and some other UNIX variants, had a history of being slow; but, Linux has always had a very fast fork).

I think you are referring to vfork vs. fork. While not terribly expensive, forking certainly is more expensive than the alternatives. (There is a reason why none of the Apache MPM's do that unless you give them a very messed up config.)

However, you are right that the real issue isn't the cost of the fork (which, duh, if it were Apache would totally have you covered!!). It's more about the address space used up by each process/thread. That becomes a limiting factor for high levels of concurrency, though below levels where it may be a limiting factor the model tends to execute very efficiently (arguably more efficiently).

Apache's "event" MPM isn't really quite the same as engines light nginx & lighttpd... it works quite well, but it even describes itself as a "hybrid multi-process/mutli-threaded server".

As for sites "propagating" this information, there is certainly the ol' traditional: http://www.kegel.com/c10k.html

You can also fight some pretty well established companies in the web hosting business that really ought to know of what they speak, like say DreamHost: http://wiki.dreamhost.com/Web_Server_Performance_Comparison

You're arguing against several strawmen of your own invention. Preforking is still forking, for one. Under heavy load you're forking to keep up with new connections while existing processes are tied up very slowly serving responses to bandwidth constrained clients. Also, I never claimed forking is expensive. I said it's expensive compared to an event loop. Correcting things I didn't say might feel good but you're just lying to yourself. Regurgitating what you've read about how Linux processes and clone() works is stereotypical sysadmin bloviating.

Several other things you say are equally wrong. Claiming that Apache has been away from a process model for decades is dishonest. It's not even decades old and the Apache project itself contradicts you.

Preforking is still recommended for "sites requiring stability" and is in (most?) common usage http://httpd.apache.org/docs/current/mpm.html

> The server can be better customized for the needs of the particular site. For example, sites that need a great deal of scalability can choose to use a threaded MPM like worker or event, while sites requiring stability or compatibility with older software can use a prefork.

Your religious devotion to Apache and claim that "Apache is fast enough" ignores the reality of what nginx can do with so much less CPU and memory. It's not a technical argument but a religious one. Nginx is good enough. Apache is not. It never was, people have lived with it for too long because people like yourself buried their heads in the sand. You're still doing it.

> Preforking is still forking, for one. Under heavy load you're forking to keep up with new connections while existing processes are tied up very slowly serving responses to bandwidth constrained clients.

No, that's not strictly true. If you have min & max servers fixed at the same value and the max requests per child set absurdly high, you won't fork much if at all under heavy load. Pre-forking can result in a lot of forking and requests being blocked while you fork if a) you have a surge in traffic and b) your min servers isn't set high enough to cover the surge or alternatively c) your max requests per child is low enough that you are constantly having processes exit.

> I never claimed forking is expensive. I said it's expensive compared to an event loop.

Agreed, although that's kind of a meaningless statement (an event loop is something you go through on a per-request basis), and misses the real problem with the multi-process model: virtual address space for each process.

> It's not a technical argument but a religious one. Nginx is good enough. Apache is not.

Umm... that sounds like a religious argument in its own right. Apache is certainly good enough for plenty of people, and more importantly with all the dynamic content on sites, the web server tends to be a pretty unimportant factor in the performance of many sites. Apache brings other things to the table which are often valued for projects, and there is no reason that needs to be considered a "religious" decision.

> I never claimed forking is expensive. I said it's expensive ... yeah, no that seems to be exactly what you are saying. just nitpickinkg.

The performance is not the only problem, the config files are just terrible compare to Nginx.

That's a valid consideration. If the Apache configuration file is difficult, then choosing something else might make sense. I'm not saying everyone should use Apache. I'm saying that almost no one should be using performance as the metric by which they judge web servers.

Though, while we're on the subject, it's a little too easy to configure nginx in insecure ways, and several configuration examples on the web exhibit pretty bad practices. But, on the whole, I agree that nginx is pretty easy to setup and maintain, and it is a great piece of software.

It's interesting that folks have interpreted my comments to mean people shouldn't use nginx and should always use Apache. I've never suggested that (and, I find it funny, because I was the biggest proponent of adding nginx support to the control panel software I work on). All I've said is that I recommend people not choose their webserver based on performance, because they're all (Apache and nginx in particular, and the one OP posted about) fast enough for the vast majority of websites and environments.

It's a good thing we have http://httpd.apache.org/docs/current/mod/event.html then.

I've spent a decent amount of time trying to make evented Apache work. It's never been worth it when a better choice that just does it is right there for the taking.

(And god help you if you try to do it with Passenger.)

Is there a latency angle to webserver performance that /is/ valid? I have heard anecdotal information that single-thread performance does affect webserver response latency and I can see how an optimized server could make a difference there.

Request latency is certainly a factor, especially with more requests happening per page, and more demanding desktop-experience applications on the web. But, none of the servers I mentioned are a significant contributor to latency when configured appropriately for the workload. Apache has competent concurrency options on modern systems (including libevent), as does nginx.

Certainly performance is nice. I'm not saying it isn't. But, the webserver is going to spend most of its time waiting on your application and your database. I'd like to see folks more focused on standards-compliant behavior, secure behavior, etc. That's not as easy as slapping up an ab benchmark, but it's more useful in helping me decide if a new server is appropriate for my needs, and it's helpful in moving the state of the art forward on fronts that are far more important than squeezing another bajillion requests out of hardware that can already serve a bajillion requests.

Another interesting angle is memory usage. Apache does require more memory than nginx or, presumably, H2O. It's not a huge difference, if Apache is configured as minimally as nginx is, by default, but it's notable on a very high concurrency system. In the "Internet of things", small embeddable web servers will be important. If H2O uses less memory than nginx, that'd be interesting (I think more interesting than performance). But, memory usage isn't really mentioned anywhere that I see...if a memory graph were beside the ab benchmarks, I probably wouldn't have even complained about the benchmarks being so prominent. It would have added a useful and maybe even predictive piece of data to the page.

Looks like it doesn't support IPv6.

src/main.c: conf->fd = socket(AF_INET, SOCK_STREAM, 0)

Although that is the example server, maybe the library does?

As happy as I am so see open source libraries that can support SPDY/HTTP2, these "2x faster than nginx" stats are a joke. This dubious claim is based on how fast H20 and nginx can serve a 6 byte, and a 4KB response

I hope to see it in TechEmpowers benchmarks: http://www.techempower.com/benchmarks/

Does this server/library allow the same kind of hooks and configuration that a traditional web server allows?

Or is that the point? If you don't need all the configuration and features of an off-the-shelf web server, you can more easily custom-build an H20 HTTP server for your specific needs that is blazing fast?

Very nice, I've often wondered at the lack of embeddable http servers in the c/c++ world. Are there any other libraries that do the same thing? What is the status of this project? Is it being used in production anywhere?

I wrote one: https://github.com/tom-seddon/yhs (README includes a bunch of links to others at the bottom)

I wrote it for an iOS game, the idea being that configuration of the game would be done in real time by connecting to your iThing via a web browser and tweaking it using a bunch of HTML widgets or whatever. But its intended users ended up preferring to do their tweaking using some on-screen Cocoa Touch stuff that I'd also put in, so the HTML idea never ended up being taken further.

My library has a few good points, I think: no dependencies, no threading, easy integration, simple API, builds as C89/C99/C++, doesn't hate Windows. (I've often wished other libraries did all of those.) But I don't currently have any plans to work on it further, and you can probably find other options that have been more thoroughly battle-tested, were more carefully planned, and are actively maintained.

(These days I'm more comfortable with Javascript, and I've come to the conclusion that a better approach would be to implement a bare bones WebSocket server that does little more than let the iWhatever send data to the browser and vice versa. No need for the iDevice to serve any HTML or cooked data or anything like that; just send raw data and interpret it in your JS code, which of course would be stored locally on your PC, along with associated HTML/CSS/etc. Quicker turnaround during development, and easier to push updates to its users, who would probably just need to get latest and hit refresh in the browser as they'd be running it straight from their working copy.)

Another example is Mongoose. It's small, easy to config and embeddable(I've used Mongoose on android with NDK with no problem). Unlike H2O, Mongoose is using an old school one-thread-per-request approach, so I would expect the throughput won't be as high as H2O, which seems to be using an event based approach similar to ngnix. Be aware of the license of Mongoose though, it used to be MIT (or apapche?), but now it's GPLv2.

There is kore. See https://kore.io and https://github.com/jorisvink/kore

Has quite alot of neat features for C web development imho, then again I wrote it so of course I like it.

cpp-netlib provides an embeddable HTTP server based on boost::asio, which adopts a proactor pattern. As with all things boost, it is well made and elegant, and takes a bit getting used to.

The Poco Net libraries include a more traditional thread-per-request server which is very easy to use, with a clean OO approach.

I think ACE includes an HTTP server as well, but I have no experience with it.

For C, libmicrohttpd


Big list of alternative libraries at the bottom also.

There is also libonion (https://github.com/davidmoreno/onion), another high performance HTTP library.

It also has C and C++ support, with very clean API, django-like templates, initial Python and PHP bindings, Websocket, Webdav, has several threading modes (poll, pool, one thread...) And many other goodies.

Disclaimer: Im the author.

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