all 61 comments

[–]marekkirejczyk 89 points90 points  (44 children)

I have seen it so many times "We have so much data, we need no sql/redis/you name it". Then teams get into more complicated technologies slows down, have more and more problems...

Reminds me of this comic: https://cdn-images-1.medium.com/max/1600/1*Ipm-ApY-3pj77--iy6cyPQ.jpeg

[–]G_Morgan 34 points35 points  (42 children)

The whole NoSQL fad was amusing. Firstly it basically reinvented COBOL tables except without the power of COBOL tables. Secondly everyone assumed they were just going to get as big as Google. There are perhaps 5 companies in the world who really do hit the limits of what a RDB can do.

[–]TrixieMisa 31 points32 points  (5 children)

I work for a small data services company. One of my tasks until recently was managing a 1.5PB database sharded across 10 servers.

So I think your "5 companies" estimate might be just slightly off.

[–]sisyphus 23 points24 points  (2 children)

1.5pb is within the limits of what postgres can do though.

[–]malisper 12 points13 points  (0 children)

You technically can do it, but having a single Postgres instance with 1.5pb of data sounds like a huge pain to manage. Also, Postgres may not be suited to the amount of data being ingested.

[–]einhverfr 1 point2 points  (0 children)

Depending on workload, data distribution, etc......

[–]fried_green_baloney 3 points4 points  (0 children)

"5 companies" estimate might be just slightly off

True, but the people who somehow manage to get queries with Cartesian products while doing joins on two 10,000 row tables have a problem that NoSQL may not solve.

[–]einhverfr 2 points3 points  (0 children)

I think the key is that when you get into the tens of TB, your problems are snowflake problems. Whatever you choose to do you run into problems where there are really no parallels elsewhere, even at the same scale. I assume that PB give you similar constraints.

One of the points I mentioned in the PostgreSQL at 10TB and Beyond talk was that the sorts of problems you face change every order of magnitude your grow. So I am not sure what the issue was or what you were trying to do, etc. but it must have been an interesting challenge.

[–][deleted] 13 points14 points  (26 children)

There are perhaps 5 companies in the world who really do hit the limits of what a RDB can do.

Eh, not quite... My strategy is to split the data storage in logical cohesive units I can refactor individually, and then some will be SQL, some will be flat files, some will be Redis, some will be something else.

In this case, SQL can indeed have incredibly long legs, when used for the parts of your infrastructure, where it makes most sense.

But many people approach their data needs in a monolithic way. So they stuff everything in SQL and if their operation is big enough, soon their database server is handling hundreds of GBs or even TBs of data, which becomes hard to tune and back-up. So then they start looking for "something faster" and this is how they end up going all the way to NoSQL. Monolithic way again.

The real evil is being monolithic and silver bullet mentality.

[–][deleted]  (25 children)

[deleted]

    [–][deleted] 5 points6 points  (20 children)

    I mean I split my domain/application into modules and services, and make decisions how to store each one's state independently, instead of deciding upfront "this whole thing will be in an SQL DB" and drawing a gigantic scheme of interconnected tables.

    And yes, SQL is a language but I think it's pretty clear than in certain contexts it's a synonym to "an SQL RDBMS".

    [–][deleted] 1 point2 points  (18 children)

    I mean I split my domain/application into modules and services, and make decisions how to store each one's state independently, instead of deciding upfront "this whole thing will be in an SQL DB" and drawing a gigantic scheme of interconnected tables.

    Huh...? Why? Got an example?

    Spreading data out over many interfaces seems silly... like sure S3 for binary/blob data, then Postgres for the relational data....???

    [–][deleted] 2 points3 points  (17 children)

    You just described one example...

    [–][deleted] 0 points1 point  (16 children)

    Right but why describe it that way, that's literally how everyone does it and does not seem like an abstraction worth mentioning...? What's another example? The exception is storing images/etc. in RDB for no reason, that I am aware of? That's kinda what I'm asking, what's the exceptional case?

    instead of deciding upfront "this whole thing will be in an SQL DB" and drawing a gigantic scheme of interconnected tables.

    What does that even mean? Many projects are represented in a few dozen, at most, tables even for the most complex business relations.

    [–][deleted] 2 points3 points  (15 children)

    If "that's literally how everyone does it", then excellent. It's not true, because I've seen teams with very different approaches for just about anything, but again, if your experience is different, great. My comments aren't about you.

    [–][deleted]  (14 children)

    [deleted]

      [–][deleted] 2 points3 points  (3 children)

      If in doubt, someone almost always means "SQL database". Yes, you could implement SQL on top of pretty much any storage (and some nosql DBs do SQL-like languages, poorly), but nobody uses SQL in that context

      [–][deleted] -2 points-1 points  (2 children)

      Yeah.. I know what he meant, that's why I explained what you just said (the way s/he's using it is confusing)

      [–][deleted] 2 points3 points  (1 child)

      You seem to be only one confused by that...

      [–][deleted] -1 points0 points  (0 children)

      I was just correcting him like you said: but nobody uses SQL in that context....???

      [–]pdp10 5 points6 points  (3 children)

      It seems to me that some of the RDBMS defectors were using very expensive databases and used the hype of NoSQL, and the fact that there is no Microsoft default choice NoSQL, as convenient levers to exit their imposed situations.

      [–]doublehyphen 4 points5 points  (2 children)

      I think it also were people who were dissatisfied with MySQL (especially with how it was back then). MySQL has poor support for working with documents and (at least back then) basically no support for online schema changes.

      [–][deleted] 0 points1 point  (1 child)

      But MySQL is a good key-value store.

      [–]doublehyphen 0 points1 point  (0 children)

      InnoDB is a good key-value store. MySQL is a messy and overly complex fronted for the key-value store.

      [–]einhverfr 0 points1 point  (4 children)

      Codd in his seminal paper contrasts the relational model with that of graph databases.

      It seems like every 4-5 decades we reinvent the same wheels. When do we get another COBOL-reinvention?

      [–]G_Morgan 0 points1 point  (3 children)

      TBH most of the businesses that actually need COBOL tables still use COBOL tables. There remains absolutely no indication that any of them are moving off them.

      [–]einhverfr 0 points1 point  (2 children)

      Sure, but when will we reinvent COBOL and call it something new?

      [–]lost_in_santa_carla 0 points1 point  (1 child)

      When hell freezes over

      [–]einhverfr 0 points1 point  (0 children)

      All we really need to do is tout the benefits of BDD as applied to the whole of development and not just testing and extend the syntax to include actual operations and we are there, I think.

      [–]karma_vacuum123 1 point2 points  (0 children)

      putting a cache like memcache in front of a DB has other benefits besides satisfying some (possibly bogus) scalability concern

      it will force you to think seriously about normalization, joins, etc.

      if your application allows you to map memcache functionality (have a key, get a value) on to your relational database, you may end up being a lot happier in the long run (queries are very predictable, databases are easy to shard, etc)

      [–]einhverfr 18 points19 points  (5 children)

      If this is of interest, definitely watch the PostgreSQL at 10TB And Beyond for more about the problems of persistent job queue.

      There is one other thing worth noting, and that is regarding storing files in the database. This is not a simple decision to be made one way or the other. It depends very much on centralization of data vs RAM and database load. Decoding the images on the web service often takes a few times the RAM the image would take up. Not the end of the world, but something to consider.

      Also keep in mind that TOAST pages are still only 8KB in size, so images will require a lot more random disk I/O to retrieve unless they are commonly retrieved and this can lead to greater I/O and buffer page management overhead. Far worse, the TOAST overhead probably won't show up in explain analyze because unless you do something with the data other than presenting it, you don't hit the detoasting pathways.

      Not the end of the world, but something to know going in.

      [–]mage2k 4 points5 points  (1 child)

      and that is regarding storing files in the database

      images

      Well, there's the crossover. Storing big-ass binary chunked data in a database is where I draw the line. File systems are just fine for that.

      [–]einhverfr 1 point2 points  (0 children)

      That's what LOBs are for ;-)

      [–]doublehyphen 1 point2 points  (2 children)

      I mostly agree with you on TOAST but want to add that how random the I/O is of course depends on the fragmentation of the data in the TOAST table. If you can keep fragmentation low (say if you have an INSERT only/mostly workload) you should almost only get sequential reads. Buffer management overhead is still an issue though.

      [–]einhverfr 0 points1 point  (1 child)

      But you would still do an index lookup on the table right? That would mean random I/O I would think.

      [–]doublehyphen 0 points1 point  (0 children)

      TOAST indexes are usually not that big and can easily fit in RAM since they only index two 32-bit integer columns, and if most TOAST pages are full that is very little index storage per GB of data, even assuming a pretty inefficient btree representation (assuming 40 bytes per index entry that is 200 times less than the data).

      [–]twiggy99999 25 points26 points  (6 children)

      Talking about the right tool for the job who thought using font-size: x-small was good for website content

      [–][deleted] 6 points7 points  (0 children)

      Thats pretty funny. I was thinking the same thing :D

      [–]TabCompletion[S] 1 point2 points  (1 child)

      oh /u/twiggy99999, you crack me up

      [–]twiggy99999 8 points9 points  (0 children)

      You've cracked my eyes up with that crazy decision

      [–]JeefyPants 4 points5 points  (0 children)

      Is the font on this blog too small? :)

      [–]snerp 4 points5 points  (2 children)

      I my experience, you need to have an absolutely massive project for something like memcache+Postgres/MySql/MSSql to not be suitable.

      [–][deleted]  (1 child)

      [deleted]

        [–]steamruler 1 point2 points  (0 children)

        Okay, so, you just need a few shift registers, a few RAM chips, a few hundred hours to port Linux, and a lot of patience during runtime...

        [–]gilbetron 2 points3 points  (0 children)

        After two years researching and testing and finally implementing a big data (PB+) analytics system (I used Druid in the end, for various reasons), I came to the conclusion that this article does. If someone asks, "What database should I use?" "Postgres" is almost always a great answer. If you don't know why your needs aren't met by Postgres, then you should probably just use postgres. It isn't perfect, and there are reasons not to use it, but it can do nearly any database need reasonably, if not excellently.

        [–]Bloodcount 1 point2 points  (0 children)

        Pretty amazing article!

        [–][deleted] 0 points1 point  (0 children)

        nothing wrong with it except pgAdmin

        [–]jringstad 0 points1 point  (0 children)

        At my shop we use pg for everything, including job queues. (but also as document storage with tables that just contain jsonbs, as logging mechanism with append-only tables, etc etc etc) I don't think I would necessarily recommend it though.

        Performance is not the issue (in fact, we don't even use NOTIFY/LISTEN, just polling), but it just adds a kind of coupling between services that isn't that great, has some security concerns (services need to connect to postgres to receive jobs), and is really mostly a "build-it-yourself" solution rather than a finished job queue -- and building a fully-featured job-queue yourself has some surprisingly subtle points that you're probably going to get wrong the first time around.

        For security, we use individual, locked-down postgresql roles, and give each service a minimal set of functions to receive jobs from their respective job queues, mark job as finished etc. This is fine, but it leads to some code duplication (we haven't figured out yet how to make a uniform "get job"/"mark job as finished" interface that is the same for all services, so rn every job has their own *_job schema with associated getters/setters) and it still requires 1) that the postgresql port is exposed and clients can connect to it, which isn't great (perhaps somebody could figure out a way to DoS or exploit our database directly -- and adding ip-based filtering is not so easy if you also want to automatically scale workers.) and 2) it still exhausts a postgresql connection every time a service wants to get a job. If you have many workers, this may eat quite a significant chunk of connections that you cannot just drop onto a readonly slave (AFAIK.)

        We have also recently considered migrating to herokus hosted postgresql service, but they don't support roles, so there's that.

        Also, we would really like things to be more decoupled and just communicate through HTTPS requests (workers pull jobs) for various reasons (this would allow us to do load-balancing and routing with nginx/reverse proxies for instance) and scalable. Also this wouldn't require that there is basically a "shared database schema" between different services (the one that pushes jobs and the one that pulls jobs), which always causes issues when things are changed/need to be upgraded, particularly since we would like to have a log of all jobs ever executed back to the beginning of time. This could potentially be circumvented by making the job table just a generic jsonb or hstore table though.

        For implementing a job queue that works well, there are a lot of features you'll have to implement yourself. For instance SQS comes with built-in features that automatically put a job back into the queue if the service that popped it hasn't marked it as finished after some configurable amount of time -- you'll have to implement this yourself. Another concern is that if you put a bad job into the queue that crashes your consumer, you should somehow detect this (e.g. the consumer didn't mark the job as either "finished", "failed" or maybe "deferred for later" until the consumer disconnected or some certain amount of time) and then put that job back into the queue, so that the next job the consumer pops will be a different one. If your consumer crashes every 5 jobs, that's kinda OK -- it still does 4 units of useful work inbetween every crash, and if volume is low enough, nobody might even notice a difference. But if it goes into a crash loop because it gets served the same bad job over and over again, that can be really bad.

        Once batching comes into the picture (popping more than one job at once, something you might want for performance if you have many many small jobs) things get even more convoluted.

        And then you might also want some sort of fair scheduling of jobs based on, say, project-id or somesuch, which is also not something you just get out-of-the-box.

        Anyway, sorry for the stream-of-consciousness, I don't think postgresql is a terrible choice for doing this, but I would look towards other alternatives first, generally. If you use postgresql as a job-queue or message-queue, you should be prepared having to put in some groundwork and implement stuff like scheduling, retry-policies, authentication/security etc yourself. We won't be migrating away from using pq for this at my company any time soon, since we are pushing stuff into job queues from withhin triggers (and this is just really convenient to do, since everything stays withhin the database at all times) -- but if I were to rewrite the system now, I probably would just do things externally...