Hacker News new | ask | show | jobs
by monus 476 days ago
> bringing HTTP/2 all the way to the Ruby app server is significantly complexifying your infrastructure for little benefit.

I think the author wrote it with encryption-is-a-must in the mind and after he corrected those parts, the article just ended up with these weird statements. What complexity is introduced apart from changing the serving library in your main file?

2 comments

In a language that uses forking to achieve parallelism, terminating multiple tasks at the same endpoint will cause those tasks to compete. For some workflows that may be a feature, but for most it is not.

So that's Python, Ruby, Node. Elixir won't care and C# and Java... well hopefully the HTTP/2 library takes care of the multiplexing of the replies, then you're good.

A good python web server should be single process with asyncio , or maybe have a few worker threads or processes. Definitely not fork for every request
Your response explains the other one, which I found just baffling.

I didn't say forking per request, good god. I meant running a process per core, or some ratio to the cores to achieve full server utilization. Limiting all of HTTP/2 requests per user to one core is unlikely to result in good feelings for anybody. If you let nginx fan them out to a couple cores it's going to work better.

These are not problems Java and C# have.

I don't think any serious implementation would do forking when using HTTP/2 or QUIC. Fork is a relic of the past.
You are correct about the first assumption, but even without encryption dealing with multiplexing significantly complexify things, so I still stand by that statement.

If you assume no multiplexing, you can write a much simpler server.

In reality you would build your application server on top of the HTTP/2 server, so you'd not have to deal with multiplexing, the server will hide that from you, so it's the same as an HTTP/1 server (ex: you pass some callback that gets called to handle the request). If you implement HTTP/2 from scratch, multiplexing is not even the most complex part... It's rather the sum of all parts: HPACK, flow-control, stream state, frames, settings, the large amount of validations, and so on.
This may be true with some stacks, but my answer has to be understood in the context of Ruby where the only real source of parallelism is `fork(2)`, hence the natural way to write server is an `accept` loop, which fits HTTP/1 very well, but not HTTP/2.
There is a gem that implements lightweight threads[0], and there is an HTTP/2 server that seems to abstract things out[1]. Your point probably still holds in the context of ruby + async + http/2; but then it's not http/2 fault, but rather ruby for not having a better concurrency story, like say golang.

[0]: https://github.com/socketry/async

[1]: https://github.com/socketry/falcon

The Ruby concurrency story is fine, the problem is parallelism. I have a whole list of posts about all that.

> it's not http/2 fault, but rather ruby

My post is to be read primarily in the context of Ruby, as the intro clearly explains it. I'm not the one who posted it here, it really isn't intended for the HN audience. I would never submit my posts here.

Many of my points are more general than just Ruby-centric, but yes, if your stack of choice have very good support for HTTP/2 I'm not saying not to use it in your DC.

My point is that as a Ruby user, there isn't much reason to lament over the lack of HTTP/2 support in Puma or some other servers.