HNNewShowAskJobs
Built with Tanstack Start
Serving a half billion requests per day with Rust and CGI(jacob.gold)
46 points by feep 2 days ago | 30 comments
  • neilv14 minutes ago

    One reason to use CGI is legacy systems. A large, complex, and important system that I inherited was still using CGI (and it worked, because a rare "10x genuinely more productive" developer built it). Many years later, to lower some of the peak resource usage, and speed up a few things, I made an almost drop-in replacement library, to permit it to also run with SCGI (and back out easily to CGI if there was a problem in production). https://docs.racket-lang.org/scgi/

    Another reason to use CGI is if you have a very small and simple system. Say, a Web UI on a small home router or appliance. You're not going to want the 200 NPM packages, transpilers and build tools and 'environment' managers, Linux containers, Kubernetes, and 4 different observability platforms. (Resume-driven-development aside.)

    A disheartening thing about most my recent Web full-stack project was that I'd put a lot of work into wrangling it the way Svelte and SvelteKit wanted, but not being happy with the complicated and surprisingly inefficient runtime execution, and realizing that I could've done it in a fraction of the time and complexity -- in any language with convenient HTML generation, a SQL DB library, an HTTP/CGI/SCGI-ish library, and a little client-side JS).

  • oxcabea minute ago

    It'd be interesting to compare the performance of the author's approach to an analogous design that changes CGI for WASI, and scripts/binaries to Wasm.

  • simonwan hour ago

    I really like the code that accompanies this as an example of how to build the same SQLite powered guestbook across Bash, Python, Perl, Rust, Go, JavaScript and C: https://github.com/Jacob2161/cgi-bin

    • Bluesteinan hour ago |parent

      This is a veritable Rosetta stone of a repo. Wow.-

  • jchwan hour ago

    Honestly, I'm just trying to understand why people want to return to CGI. It's cool that you can fork+exec 5000 times per second, but if you don't have to, isn't that significantly better? Plus, with FastCGI, it's trivial to have separate privileges for the application server and the webserver. The CGI model may still work fine, but it is an outdated execution model that we left behind for more than one reason, not just security or performance. I can absolutely see the appeal in a world where a lot of people are using cPanel shared hosting and stuff like that, but in the modern era when many are using unmanaged Linux VPSes you may as well just set up another service for your application server.

    Plus, honestly, even if you are relatively careful and configure everything perfectly correct, having the web server execute stuff in a specific folder inside the document root just seems like a recipe for problems.

    • 9rxa minute ago |parent

      I suppose because they can. While there were other good reasons leave CGI behind, performance was really the only reason it got left behind. Now that performance isn't the same concern it once was...

    • taeric41 minutes ago |parent

      I thought the general view was that leaving the CGI model was not necessarily better for most people? In particular, I know I was at a bigger company that tried and failed many times to replace essentially a CGI model with a JVM based solution. Most of the benefits that they were supposed to see from not having the outdated execution model, as you call it, typically turned into liabilities and actually kept them from hitting the performance they claimed they would get to.

      And, sadly, there is no getting around the "configure everything perfectly" problem. :(

    • 0x000xca0xfe17 minutes ago |parent

      I guess multiprocessing got a bad reputation because it used to be slow and simple so it got looked down upon as a primitive tool for less capable developers.

      But the world has changed. Modern systems are excellent for multiprocessing, CPUs are fast, cores are plentiful and memory bandwidth just continues getting better and better. Single thread performance has stalled.

      It really is time to reconsider the old mantras. Setting up highly complicated containerized environments to manage a fleet of anemic VMs because NodeJS' single threaded event loop chokes on real traffic is not the future.

      • jchw10 minutes ago |parent

        I feel it necessary to clarify that I am not suggesting we should use single-threaded servers. My go-to approach for one-offs is Go HTTP servers and reverse proxying. This will do quite well to utilize multiple CPU cores, although admittedly Go is still far from optimal.

        Still, even when people run single-thread event loop servers, you can run an instance per CPU core; I recall this being common for WSGI/Python.

      • ben-schaaf9 minutes ago |parent

        That really has nothing to do with the choice to use CGI. You can just as well use rust with Axum or Actix and get a fully threaded web server without having to fork for every request.

    • Nzen12 minutes ago |parent

      My personal interest in CGI stems from my website host offering it as a means of responding to requests [0] in addition to static assets.

      [0] https://www.nearlyfreespeech.net/help/faq#CGISupport

    • UK-Al0516 minutes ago |parent

      It's very unix. A single process executable to handle a request then shuts down.

    • zokier33 minutes ago |parent

      Having completely isolated ephemeral request handlers with no shared state and no persistent runtime makes very clean and nice programming model. It also makes deployments simple because there is no graceful shutdown or service management to worry about; in simplest case you can just drop in new executables and they will be automatically taken into use without any service interruption. Fundamentally CGI model allows leveraging lot of tools that Linux/UNIX has to offer.

    • p2detaran hour ago |parent

      For smaller things, and I mean single-script stuff, I pretty much always use php-fpm. It’s fast, it scales, it’s low effort to run on a VPS. Shipped a side-project with a couple of PHP scripts a couple of years ago. It works to this day.

      • jchw42 minutes ago |parent

        php-fpm does work surprisingly well. Though, on the other hand, traditional PHP using php-fpm kinda does follow the CGI model of executing stuff in the document root.

    • g-morkan hour ago |parent

      processless is the new serverless, it lets you fit infinite jobs in RAM thus enabling impressive economies of scale. only dinosaurs run their own processes

    • monkeyelite39 minutes ago |parent

      Think about all the problems associated with process life cycle - is a process stalled? How often should I restart a crashed process? Why is that process using so much memory? How should my process count change with demand? All of those go away when the lifecycle is tied to the request.

      It’s also more secure because each request is isolated at the process level. Long lived processes leak information to other requests.

      I would turn it around and say it’s the ideal model for many applications. The only concern is performance. So it makes sense that we revisit this question given that we make all kinds of other performance tradeoffs and have better hardware.

      Or you know not every site is about scaling requests. It’s another way you can simplify.

      > but it is an outdated execution model

      Not an argument.

      The opposite trend of ignoring OS level security and hoping your language lib does it right seems like the wrong direction.

      • jchw25 minutes ago |parent

        > Think about all the problems associated with process life cycle - is a process stalled? Should I restart it? Why is that process using so much memory? How should my process count change with demand? All of those go away when the lifecycle is tied to the request.

        So the upshot of writing CGI scripts is that you can... ship broken, buggy code that leaks memory to your webserver and have it work mostly alright. I mean look, everyone makes mistakes, but if you are routinely running into problems shipping basic FastCGI or HTTP servers in the modern era you really need to introspect what's going wrong. I am no stranger to writing one-off Go servers for things and this is not a serious concern.

        Plus, realistically, this only gives a little bit of insulation anyway. You can definitely still write CGI scripts that explode violently if you want to. The only way you can really prevent that is by having complete isolation between processes, which is not something you traditionally do with CGI.

        > It’s also more secure because each request is isolated at the process level. Long lived processes leak information to other requests.

        What information does this leak, and why should I be concerned?

        > Or you know not every site is about scaling requests. It’s another way you can simplify.

        > > but it is an outdated execution model

        > Not an argument.

        Correct. That's not the argument, it's the conclusion.

        For some reason you ignored the imperative parts,

        > It's cool that you can fork+exec 5000 times per second, but if you don't have to, isn't that significantly better?

        > Plus, with FastCGI, it's trivial to have separate privileges for the application server and the webserver.

        > [Having] the web server execute stuff in a specific folder inside the document root just seems like a recipe for problems.

        Those are the primary reasons why I believe the CGI model of execution is outdated.

        > The opposite trend of ignoring OS level security and hoping your language lib does it right seems like the wrong direction.

        CGI is in the opposite direction, though. With CGI, the default behavior is that your CGI process is going to run with similar privileges to the web server itself, under the same user. On a modern Linux server it's relatively easy to set up a separate user with more specifically-tuned privileges and with various isolation options and resource limits (e.g. cgroups.)

        • monkeyelite10 minutes ago |parent

          > So the upshot of writing CGI scripts is that you can... ship broken, buggy code that leaks memory to your webserver and have it work mostly alright

          Yes. The code is already shitty. That’s life. Let’s make the system more reliable and fault tolerant.

          This argument sounds a lot like “garbage collection is for bad programmers who can’t manage their memory”.

          But let me add another reason why it’s wrong with your own framing. In fire/forget programmers get used to crashing intentionally at the first sign of trouble. This makes it easy to detect failures and improve code. The incentive for long running processes is to avoid crashing, so programs get into bad states instead.

          > The only way you can really prevent that is by having complete isolation between processes

          Yes. That’s the idea. Web server forks, and execs. Separate memory spaces.

          > What information does this leak

          Anything that might be in a resource, or memory. Or even in the resource of a library you use.

          > and why should I be concerned

          Accessing leaked information form a prior run is a common attack.

          > but if you don't have to, isn't that significantly better?

          Long running processes are inherently more complex. The only benefit is performance.

          > H’the web server execute stuff in a specific folder inside the document root just seems like a recipe for problems.

          As opposed to? All processes have a working directory. What problems come from using the file system?

          > cgroups

          Yes it’s the same amount of effort to configure this.

  • an hour ago
    [deleted]
  • rokob33 minutes ago

    I’m interested why Rust and C have similarly bad tail latencies but Go doesn’t.

    • twh27013 minutes ago |parent

      OP posited SQLite database contention. I don't know enough about this space to agree or disagree. It would be interesting, and perhaps illuminating, to perform a similar experiment with Postgres.

    • bracketfocus12 minutes ago |parent

      The author guessed it was a result of database contention.

      I’d also be interested in getting a concrete reason though.

  • shrubble2 hours ago

    In a corporate environment, for internal use, I often see egregiously specced VMs or machines for sites that have very low requests per second. There's a commercial monitoring app that runs on K8s, 3 VMs of 128GB RAM each, to monitor 600 systems; using 500MB per system, basically, just to poll it each 5 minutes, do some pretty graphs, etc. Of course it has a complex app server integrated into the web server and so forth.

    • RedShift1an hour ago |parent

      Yep. ERP vendors are the worst offenders. Last deployment for 40-ish users "needed" an 22 CPU cores and 44 GB of RAM. After long back and forths I negotiated down to 8 CPU cores and 32 GB. Looking at the usage statistics, it's 10% MAX... And it's cloud infra so paying a lot for RAM and CPU sitting unused.

      • ted5376 minutes ago |parent

        Haha yes -- like what do you mean this CRUD app needs 20 GB of RAM and half an hour to startup?

  • andrewstuart2 hours ago

    How meaningful is “per day” as a performance metric?

    • diathan hour ago |parent

      Not at all, it may be a useful marketing metric, but not a performance one. The average load does not matter when your backend can't handle the peaks.

      • xnxan hour ago |parent

        True, though a lot higher spec'ed systems couldn't handle the minimum 5000 requests/second this implies.

  • 2 hours ago
    [deleted]