Live data from Hacker News

In defense of simple architectures

danluu.com

81–90 of 196 posts

Re: In defense of simple architectures

#81

How far can you get with a single Postgres instance on a single machine? I know things like cockroach and citus existence but generally Postgres isn’t sharded as far as I know.

You can scale up that one machine a lot. If you start with a normal sized machine you have a lot of overhead in increasing ram/cpu on that machine (eg you could start with say 16 cores and 100G ram or less and scale up to like 2TB ram and 64/128 cores). There’s also runway for scaling things by eg shooting down certain long-running queries that cause performance problems or setting up read replicas.

So even if you’re a bit worried about scaling it, you can at least feel the problems are far away enough that you shouldn’t care until later.

Re: In defense of simple architectures

#82

Earlier quoted context omitted.

_74_ services on a k8 stack for 3 pages and 100 active daily users????? This has to be a crime.

Ok I feel very validated now - I'm not used to microservices so didn't know what was typical. It felt crazy, so good to know based on this comment's responses that it is indeed crazy. For example, in order to sign up a user...the client hits the /signup endpoint, which first lands on the server-gateway service. Then that is passed along to an account-service which creates the user. Then the accounts-service hits a NA…

Even the most fanatical microservices proponent will tell you that's just bonkers.

At my very first programming job many years ago I was given a bunch of code written by a string of "previous guys" (mostly interns) over a period of 10 years or more and was told "good luck with it". I was the only developer, with no real technical oversight. It was my first "real" programming job, but I had been programming for many years already (mostly stuff for myself, open source stuff, etc, but never "real" production stuff).

In hindsight, I did some things that were clearly overcomplicated. I had plenty of time, could work on what I wanted, and it was fun to see if I could get the response speed of the webpage down from 100ms to 50ms, so I added a bunch of caching and such that really wasn't needed. Varnish had just been released and I was eager to try it, so I added that too. It was nowhere near the craziness you're describing though, and considering the state of the system when I took things over things were still massively improved, but I'd definitely do things different now because none of that was really needed.

Maybe if it had been today instead of 15 years ago I would have gone full microservice, too.

Re: In defense of simple architectures

#83
post #34

There are some web apps still in production that I wrote almost a decade ago in Node+Express in the simplest, dumbest style imaginable. The only dependencies are Express and some third-party API connectors. The database is an append-only file of JSON objects separated by newlines. When the app restarts, it reads the file and rebuilds its memory image. All data is in RAM. I figured these toys would be replaced pretty…

Built-in first-class concurrency (ala node, golang, rust, etc.) is a huge win for simple architectures, since it lets you avoid adding a background queue, or at least delay it for a very long time. I think people are also too quick to add secondary data stores and caches. If you can do everything with a transactional SQL database + app process memory instead, that is generally going to save you tons of trouble on ops…

> For example: instead of memcache/redis, set aside a ~100 MB of memory in your app process for an LRU cache. When an object is requested, hit the DB with an indexed query for just the 'updatedAt' timestamp (should be a sub-10ms query). If it hasn't been modified, return the cached object from memory, otherwise fetch the full object from the DB and update the local cache.

I've never built something with this type of mechanism for a DB query, but it's interesting. I don't think I've ever timed a query like this, but I feel like it's going to be an "it depends" situation based on what fields you're pulling back, if you're using a covering index, just how expensive the index seek operation is, and how frequently data changes. I've mainly always treated it as "avoid round trips to the database" -- zero queries is better than one, and one is better than five.

I also guess it depends on how frequently it's updated: if 100% of the time the timestamp is changed, you might as well just fetch (no caching). Based on all the other variables above, the inflection point where it makes sense to do this is going to change.

Interesting idea though, thanks.

> For bonus points, send an internal invalidation request to any other app instances you have running when an object gets updated. Now you have a fast, scalable, consistent, distributed cache with minimal ops complexity.

Now you have to track what other app servers exist, handle failures/timeouts/etc in the invalidation call, as well as have your app's logic able to work properly if this invalidation doesn't happen for any reason (classic cache invalidation problem). My inclination is at this point you're on the path of replicating a proper cache service anyways, and using Redis/Memcache/whatever would ultimately be simpler.

Re: In defense of simple architectures

#84
post #50
post #34

There are some web apps still in production that I wrote almost a decade ago in Node+Express in the simplest, dumbest style imaginable. The only dependencies are Express and some third-party API connectors. The database is an append-only file of JSON objects separated by newlines. When the app restarts, it reads the file and rebuilds its memory image. All data is in RAM. I figured these toys would be replaced pretty…

This. Not that I'm all about janky, but my road is littered with stuff I didn't think would make it through summer, and everything I check is still ticking 5, 7, 10 years later. LONG ago I was amused by a Sun box in a closet that nobody knew anything about. I heard about the serial label printer that stopped working eight months ago, which was eight months after I shut off the Sun. I brought it back up again late one…

Ha, now you can use the label printer to label the machine!

Re: In defense of simple architectures

#85
post #74

Earlier quoted context omitted.

Pretty far!

How far was exactly? Like tps for reads and writes with what specs? I’ve been looking for real world performance.

That's complicated based on workload, etc. A single PG node will obviously never scale to Google or Facebook levels.

Attend a PG conference and you will run into plenty of people running PG with similar use cases(and maybe similar loads) to you.

I can say we run a few hundred concurrent users backed by PG on a small to medium sized VPS without issues. Our DB is in the 3 digit GB range on disk, but not yet TB range.

Re: In defense of simple architectures

#86
post #41

Earlier quoted context omitted.

> database is an append-only file of JSON objects separated by newlines. When the app restarts, it reads the file and rebuilds its memory image. All data is in RAM Apps like this tend to perform like an absolute whippet too (or if they dont, getting them to perform well is often a 5 line change). It's really freeing to be able to write scans and filters with simple loops that still return results faster than a networ…

Another issue with "just a JSON file" as a database is that you need to be a bit careful to avoid race conditions and the like, e.g. if two web pages try to write the same database at the same time. It's not an issue for all applications, and not that hard to get right, but does require some effort. This is a huge reason I prefer SQLite for simple file storage needs.

Doesn't the fact that its opened in append only mode (Linux) mitigate data races with regards to writes?

Re: In defense of simple architectures

#87
post #54
post #19

Earlier quoted context omitted.

Realistically almost every web app can start as a one-tier web app that uses SQLite as a data store and serves mostly HTML.

I have a dumb question ... In almost all performance areas -- gaming, PCs, autos, etc -- there are usually whole publications dedicated to performing benchmarks and publishing those results. Are there any publications or sites which implement a few basic applications against various new-this-season "full stacks" or whatnot, and document performance numbers and limit-thresholds on different hardware? Likewise, there m…

TechEmpower has benchmarks for different web stacks: https://www.techempower.com/benchmarks/

Re: In defense of simple architectures

#88
post #34

There are some web apps still in production that I wrote almost a decade ago in Node+Express in the simplest, dumbest style imaginable. The only dependencies are Express and some third-party API connectors. The database is an append-only file of JSON objects separated by newlines. When the app restarts, it reads the file and rebuilds its memory image. All data is in RAM. I figured these toys would be replaced pretty…

I would love to see more stuff like that.

An application I have written recently for personal use is a double entry accounting system after GNUcash hosed itself and gave me a headache. This is based on Go and SQLite. The entire thing is one file (go embed rocks) and serves a simple http interface with a few JS functions like it is 2002 again. The back end is a proper relational model that is stored in one .db file. It is fully transactional with integrity checks. To run it you just start program and open a browser. To backup you just copy the .db file. You can run reports straight out of SQLite in a terminal if you want.

This whole concept could scale to tens of users fine for LOB applications and consume little memory or resources.

Re: In defense of simple architectures

#89
post #9

I think the biggest problem for most developers is not understanding what one computer can actually do and how reliable they are in practice. Additionally, understanding of how tolerant 99% of businesses are to real-world problems that could hypothetically arise can help one not frustrate over insane edge case circumstances. I suspect a non-zero number of us have spent time thinking about how we could provide determi…

> I think the biggest problem for most developers is...

... reading blogs and such where some loud mouth is telling them about so called "best practices" and so they bring that back to work with them.

There are not enough loud mouths telling people to keep it simple (until you can't or know better).

Re: In defense of simple architectures

#90

Earlier quoted context omitted.

Another issue with "just a JSON file" as a database is that you need to be a bit careful to avoid race conditions and the like, e.g. if two web pages try to write the same database at the same time. It's not an issue for all applications, and not that hard to get right, but does require some effort. This is a huge reason I prefer SQLite for simple file storage needs.

Doesn't the fact that its opened in append only mode (Linux) mitigate data races with regards to writes?

Here is my list of numbers: 1,Here is my list of letters: a,b,2,3,d
Post reply on HN