Handling Growth with Postgres
instagram-engineering.tumblr.com
instagram-engineering.tumblr.com
>Over the last two and a half years, we’ve picked up a few tips and tools about scaling Postgres that we wanted to share—things we wish we knew when we first launched Instagram.
A common failure mode for myself and, I suspect, others, is thinking that we have to know every single thing before we start. Good old geek perfectionism of wanting an ideal, elegant setup. A sort of Platonic Ideal, if you will.
These guys went on to build one of the hottest web properties on earth, and they didn't get it all right up front.
If you're postponing something because you think you need to master all the intricacies of EC2, Postgres, Rails or $Technology_Name, pay close attention to this example. While they were launching growing, and being acquired for a cool billion, were you agonizing over the perfect hba.conf?
More a note to myself than anything else :)
A shame, really: The very thing that drives us to be the best ends up holding us back.
They were seasoned enough to choose Python and Postgres, two technologies that are both relatively easy to start with and to scale later.
And, oddly enough, those two technologies are on the "do things right" side, and do not (usually) sacrifice their correctness to some convenience or fashion.
So, sure, one cannot expect to know every corner of the techno one chooses, but still choosing carefully the best options and shielding oneself against current hotness is still not a waste of time or energy.
So the lesson is not just be good at what you do, but be willing to listen to other people who knows better than you do.
I think django was a good choice; I just don't think you can draw those conclusions from it.
Go Bears. That's awesome. And we should all take a hint...
Every notable PostgreSQL deployment has had to 'roll their own'.
http://www.postgresql.org/docs/9.2/static/warm-standby.html#...
Not really suitable for the common scalability issues startups deal with today. Like working in multiple Amazon regions or supporting difference sets of servers.
If you are wanting master-master, look into http://postgres-xc.sourceforge.net.
It was included in the Postgres source code repository. I always considered that to be a pretty official solution.
Wrong. September of 2010: http://www.postgresql.org/about/news/1235/
Instagram seems to agree.
You don't need to worry about solving for scalability until you actually have scaling problems, which most startups will never face. Yet, weirdly, I've seen many companies sink massive amounts of time and money into solving future scaling issues that never materialize.
Solve the demand problem first, and use that to pay to fix the supply problem.
Especially, when you get Facebook-big, you hit a new wall of scaling challenges, and this wall will be very specific to your company. Solving those challenges is tough and expensive, which is just fine, because Instagram-level growth brings with it the money to pay for solving those problems.
And some of us run startups that have to deal with large volumes of data from day one. So this idea of "wait until you're big" is simply bad advice.
The vast majority of companies won't need to face scaling or big data issues, they're too busy going after that next sale to keep their heads above water. There are, however, some problems that require lots of data very early on so in these situations it's appropriate to look for solutions like MongoDB, CouchDB, Riak et al. What ends up happening all too often is someone hears about MongoDB being the best new cool thing and decides to implement their company CRUD + sales platform on top of it.
The question you have to ask yourself is why isn't Postgres suitable for you. That might be huge amounts of data and heavy reads and rapidly changing schemas that make MongoDB a better choice.
In any case this post was great because it shows that Postgres can scale if you're willing to put some money, thought and effort into it. I doubt many people here have Instagram's data size or scaling issues.
I want my app to work in multiple Amazon EC2 regions.
The Silicon Valley Tech Bubble is not where the bulk of data usage happens.
The big one is that it's on a per-cluster (ie., database instance) level. It's not possible to have different databases with different replication settings: You have to replicate everything or nothing.
Another gripe is that it's awkward to set up the first time; you have to do a base backup, rsync over, etc. It would have been great if you could just start a slave and tell it to stream the entire master database over. Possibly something that gets easier in 9.3.
Another gripe, as a developer, is that read-only queries can fail. You will eventually get a nice "ERROR: Canceling statement due to conflict with recovery"; and you will simply need to retry the query at that point. (We actually switch back to the master and retry.) We use long timeouts for the pertinent settings (see http://www.postgresql.org/docs/9.2/static/hot-standby.html), but we still get these.
Some MySQL fans would probably say that Postgres replication being single-master/multiple-slave is a problem, but I don't mind myself.
http://wiki.postgresql.org/wiki/Slow_Query_Questions
Query analysis tool http://explain.depesz.com
The mailing list http://www.postgresql.org/list/pgsql-performance/
Greg Smith's book http://www.amazon.com/PostgreSQL-High-Performance-Gregory-Sm...
#postgresql on freenode.net
Don't forget to mention PgAdmin III has a built-in graphical explain analyze, which is absolutely amazing yet rarely talked about.
http://www.postgresonline.com/journal/archives/27-Reading-Pg...
But you're right, a ton of great stuff has been added in 8.4+.
Glad I did though.
Which coincidentally followed the (probably much-needed) performance improvements which started landing heavily in the 8.x series.
Personally I caught on once I saw the feature list of 9.0. And 9.1... then 9.2... they just keep adding cool stuff that's made well. It becomes difficult to ignore.
Write throughput has been improved as well.
Check out Josh Berkus's (one of 7 core team members of the Postgres dev team) presentation on what's new in Postgres 9.2:
http://developer.postgresql.org/~josh/releases/9.2/92_grand_...
How do you deploy database updates? With Rails-style migrations?
One thing that bugs me about migrations is that if you use functions or views, the function/view definition has to be copied to a new file. It makes it difficult to see what's been changed. I'm looking forward to http://sqitch.org/ for this reason. (slides: http://www.slideshare.net/justatheory/sqitch-pgconsimple-sql...)
http://instagram-engineering.tumblr.com/post/10853187575/sha...
I worked with the Flickr-style ticket DB id setup at Etsy, and while it was lovely once it was all set up, it's way more complicated (requiring two dedicated servers and a lot of software and operations stuff.) The solution outlined by instagram of just having a clever schema layout and stored procedure that safely allocates IDs locally on each logical shard is elegant and I'm having a hard time blowing holes in it.
These kinds of stats always sound so impressive, but let's imagine:
- 8 byte timestamp
- 8 byte user ID
- 8 byte post ID
- 128 bytes DBMS overhead
- 128 bytes for user->like index
- 128 bytes for post->like index
= 3.96MiB/second, or ~1015 IOPs/second, or 342GB per day absolute worst case. A single economy machine with an even remotely decent SSD could handle a full day's data at these rates.1) Code that depends on autocommit is hard to unit test, since you have to mock out whatever internal method autocommit calls
2) Code that depends on autocommit is hard to reason about, since you don't have a consistent view of your data, especially in multi-step update methods.
3) Because of 2, your updates will (not "may", "will definitely") be corrupted at some point, leaving broken bad data in the database. Comprehensive constraints help, but if you're relying on autocommit chances are you're not using constraints very well either.
2. autocommit is explicitly mentioned in terms of single select reads. Besides - if you use transactions in your update, it doesn't affect anything - postgres will do the right thing. Similarly, postgres will wrap single statement updates in transactions for you. Using it in multi-step procedures is a no-no - fortunately autocommit is per-connection, so if you are being careful about what connection you use, you can have both.
3. Another strawman - using autocommit for single selects doesn't preclude not using it for places where data integrity is a concern.
The cost of a short-lived read transaction is incredibly low, especially with Postgres. All the data for the last so many transactions will be in the database anyway until a vacuum happens. There's no CPU cost to read transactions that I'm aware of.
Explicit transaction blocks for single-statement reads are pointless. Extra packets for the transaction demarcation even more so.
The performance savings comes from the roundtrip latency of the BEGIN TRANSACTION / COMMIT packets.
"Wouldn't a good programming practice, be to ensure that everything that is supposed to be atomic, occur in a single, possibly large, SQL statement anyways?"
The simplistic answer to that question is a resounding yes.http://www.craigkerstiens.com/ http://www.quora.com/Peter-van-Hardenberg
pg_reorg can re-organize tables without any locks, and can be a better
alternative of CLUSTER and VACUUM FULL. This project is not active now,
and fork project "pg_repack" takes over its role. See
https://github.com/reorg/pg_repack for details.