Stripe – Outage postmortem
support.stripe.com
support.stripe.com
We have a library that allows us to describe expected schemas and expected indexes in application code. When application developers add or remove expected indexes in application code, an automated task turns these into alerts to database operators to run pre-defined tools that handle index operations.
In this situation, an application developer didn't add a new index description or remove an index description, but rather modified an existing index description. Our automated tooling erroneously handled this particular change and interpreted it not as a single intention but instead encoded it as two separate operations (an addition and a removal).
Developers describe indices directly in the relevant application/model code to ensure we always have the right indices available -- and in part to help avoid situations like this. In addition, the tooling for adding and removing indexes in production is restricted to a smaller set of people, both for security and to provide an additional layer of review (also to help prevent situations like this). Unfortunately, because of the bug above, the intent was not accurately communicated. The operator saw two operations, not obviously linked to each other, among several other alerts, and, well, the result followed.
There are some pretty obvious areas for tooling and process improvements here. We've been investigating them over the last few days. For non-urgent remediations, we have a custom of waiting at least a week after an incident before conducting a full postmortem and determining remediations. This gives us time to cool down after an incident and think clearly about our remediations for the long-term. We'll be having these in-depth discussions, and making decisions about the future of our tooling and processes, over the next week.
I'd actually applied to work at stripe about two years ago, you guys turned me down ;)
I was responsible for ops at a billion-device-scale mobile analytics company for about 1.5 years. Your tooling is far superior to anything we produced. I like the idea of a single source of truth describing the data model (code, tables, query patterns, etc.) a lot, and doubly-so that it's revision-controlled and available right alongside the code.
I think it's far from decided though, how much to involve human operators in processes like this. Judging from this answer, you seem to be on the extreme end of "automate everything". How then, I'm curious, do you train/communicate to developers what can be done safely vs. something that would cause i/o bottlenecks, slowdown, or other potentially production-impacting effects? Can you even predict these things accurately in advance? (Some of our worst outages were caused by emergent phenomena that only manifested at production scale, such as hitting packet throughput and network bandwidth limits on memcached -- totally unforseeable in a code-only test environment).
It sounds like you let developers request changes (a la "The Phoenix Project") but ops is responsible for final approval of the change? That actually sounds like a great system. Would love some elaboration on this.
In any case, great writeup and from one guy who's been there when the pager goes off to another, sounds like the recovery went pretty smoothly.
We're always learning and improving. In order to scale, we'll need better ways to manage complexity and isolate failure. Our tools, patterns, and processes have changed quite a bit over the last few years, and they will continue to change. Ultimately, we want every Stripe employee to have the right information evident to them when they make decisions. This will be challenging, especially as we grow, but I'm excited to take on that challenge.
If you're still interested in working at Stripe, I'd encourage you to reapply! Our needs have changed quite a bit since you applied, and we're willing to reconsider candidates after a year has passed. Feel free to shoot me a resume: jorge@stripe.com
It would be interesting to build a RDBMS that enforced that subset by simply not allowing those features to be used/abused with support for many of the modern features (JSONB etc) but that is way beyond my area of expertise.
As a simple example, to make an atomic change to a write-only table, you could create a copy of the table, alter the copy as necessary, then in a single rename operation, rename the live table to '_old' and the '_new' table to live. You most likely would not want to add two additional table schema and all of those steps to your development database operations.
It's entirely possible that they could capture what is done in production as migrations, and test them first, but it would still likely be separate from what the application developers are working with.
The problem with MongoDB is that teams think they can get away by just setting it and forgetting it. Real companies have DBAs that monitor it and understand it and make a living through it. They're just trying to automate it using fancy ui's. That's what you get for trying to automate your DBAs.
I'm an SRE at Google, where postmortems are habitual. The thing that jumped out at me here is that a production change was instantaneously pushed globally, instead of being canaried on a fraction of the serving capacity so that problems could be detected. That seems like your big problem here.
(Of course, without knowing how your data storage works, it's difficult to tell how hard it is to fix that.)
This is one of our few remaining unsharded databases (legacy problems...), so we can't easily canary a fraction of serving capacity. However, one clear remediation we can implement easily is to have our tooling change a replica first, failover to it as primary, and, if problems are detected, quickly fail back to the healthy former primary.
Lesson learned. We'll be doing a review of all of our database tooling to make sure changes are always canaried or easily reversible.
There's a trend towards "hosted POS", where point of sale systems have to talk to the "cloud" to do anything, even handle cash. Until recently, most POS systems were running off a server in the manager's office, which communicated to servers and credit card systems elsewhere. A network outage didn't affect cash transactions. Often, the systems could even process a credit card transaction without external help, giving up real-time validation but still logging the transaction for later processing.
There's a single point of failure being designed into retail here.
[1] http://www.usatoday.com/story/tech/2015/04/24/starbucks-poin...
There are expensive retail consultants who clean up stores and improve sales by doing this.
Gap gets this right. Gap stores have big, clear counters, so you can bring up lots of merchandise and have a place to put it. This increases sales per customer. Gap is amazingly successful despite a rather blah product line.
Retailers no longer have the power to make customers wait. Consumers have too many other buying options.
Also, box office revenue hasn't collapsed or anything, so I'm not sure what you mean with your example. In fact, come to think of it, I see people lining up for things multiple times every year at the theaters I frequent.
And yet Apple had a line 12+ hours before opening to release their 9th generation iPhone -- despite also taking orders online.
Hopdoddy in Austin has a line out the door for lunch and dinner; they even have a person dedicated to managing it, along with waitstaff to take drink orders
I think the line is alive and well in America for certain establishments.
Japanese convenience stores also get this right most of the time. There is almost never a line up at the cash register. As soon as one begins to form, the employees will drop whatever they are doing and open up a new register. At some places, the register can actually handle more than one customer at a time, so if you have someone fumbling for change, they can start tallying up goods for the next person in line.
Possibly I'm not typical, but I often spend a lot of time browsing in stores. As soon as I have decided that I'm done, though, I get very irritated at anything that slows me down. I had never really put my finger on it until reading the OP's post.
Ironically, I think "open" stores (like an Apple store) exhibit the same behavior. Even though there's technically no labyrinth to navigate through, good luck finding an efficient way to purchase a product, especially if it's just a small one. You first signal an Apple checkout fairy to grace you with her checkout wand, so that someone else can find you and swipe your card. If your purchase is small, they hardly even give you time of day. So stupid.
And the analogy can be extended to online stores too. Any store with a "just add this too" in the checkout experience invokes the same negative reaction. Though I am a heavy Amazon customer, their checkout process is just barely tolerable in this way. And think about GoDaddy and how miserably awful their checkout experience has been (and continues to be) throughout the years.
But for every person like you, there are about 50 others who do browse through all the stuff and perhaps add more to their shopping. Not everyone is in a hurry and capitalizing on small additions and combo deals and sales signups can be great business for the retailer.
I did consulting for them and they hired aforementioned retail consultants for this job. I will admit I initially thought it was stupid, having been a wise retail manager at the age of 17 at one point in my life (and did a lot of level-1 tracking of sales and A/B testing, even back then!). But when these retail consultants showed me their data and how it was formatted... it was unbelievable. Most of what I experienced in retail were these nebulous and stupid ideas that were conjured from the ether from my direct managers and general managers and the like. While I'm sure not all the information I saw trickled down to employees, it was truly enlightening and gave me zero room to argue particulars with how they were studying and implementing retail flow, checkout, and return procedures.
The "2.0 generation" (or was that 5 years ago?) is forgoing a lot of redundancy and safeguards that existed in the previous systems
When did we assume a fast data link (and all the infrastructure behind it) would be available 24/7?
At least do cash transactions and note them in a notebook
I'm reminded of something I read in a book a while back about aviation disasters "It's not the first problem that kills you, it's the second".
In this post the described system for change management is at least as good as any I've seen in production and yet a series of small problems got out of hand quickly.
The issue IMO is splitting an otherwise atomic procedure (creation/drop of index) into two change tickets. I'd be interested to know how the DDL was communicated to ops that led to its getting split.
EDIT: Someone, somewhere is going to have a bad day because they didn't know what you did. This is why sharing knowledge is so important. That's part of what HN exists for! Share what you know! Help improve open source tools! Help your fellow IT professional get a good night's sleep.
In that case I don't need to basically congratulate Stripe on messing up and then posting PR piece on how they messed up, especially when it's such a trivial mistake (by that I mean it's not anything technically interesting for what went wrong). I guess I'll concede that what is technically interesting is not objective - many things I consider complicated other would consider basic, so I don't really have the right to serve as the arbiter of what is technically interesting.
What happened? We dropped an index. Why? Bad tooling. Fix? Patch code, add index. Future fix? Vague goals to stop this from happening.
Though I might be taking it too far, I don't see why I need to give props to someone for doing messing up something relatively basic and then fixing it - don't people complain enough about kids getting participation trophies?
Anyway, don't mean to call out any specific Stripe engineer, it's failed process at multiple levels (guy who drops index has no visibility into DB?).
Why? How does the honesty (in this case openness really) change the quality?
Genuine question: Would you rather have an org that's always reliable but private in their tech or one that has issues but open about them?
Plenty of companies also communicate the status and that something is happening but don't fully expound on all the internal details. Not sure why it's such a big difference if they did. It feels like fake PR trust to me.
You are, of course, entitled to your opinion. I don't think its going to hurt their business at all.
For their customers.
> In that case I don't need to basically congratulate Stripe on messing up and then posting PR piece on how they messed up, especially when it's such a trivial mistake (by that I mean it's not anything technically interesting for what went wrong).
Few screw-ups are ever that technically interesting. The point of a postmortem isn't to be interesting, it's to explain what went wrong, why, and what you are doing to prevent it from happening again in the future.
If nothing else, I don't understand the role of "database operator" if they'll just blindly delete a critical index without thinking about it. Shouldn't that person have known better than anybody how critical the index was?
One is to keep it running, monitor disc space, response times etc. but otherwise leave the schema to the developers.
Or you can own the schema, discuss all the changes and migrations with the developers etc.
If it was the first kind of DB operation (which wouldn't surprise me, because that's what our $work has as well), it's not surprising that they trust the developers to provide sane DDL patches.
TBH, it seems odd to call the first one a "database operator" instead of an IT admin.
To me it seemed that it was a bug in the tooling that split the index change into two separate change requests. I'm sure a change request supports more than one piece of DDL, and it must have worked in the normal case, otherwise they would have run into this problem much earlier. So it was likely some weird corner case.
Now that I think about it, this could happen to us as well. We have peer review for each database change, but only at the source level (so, definition of the schema); the actual commands for schema changes are usually generated automatically. If some bug in that step existed that was only triggered in weird corner cases, we'd be screwed.
A backup of our main database takes about 7 hours to restore, and then we'd have to reply the binlogs from the time of the last snapshot up to the failed schema changes, so I guess we'd lose about a solid work day if things went down south. Yikes.
If you're using any of the DBIx::Class deployment tools they should be perfectly happy writing the DDL to disk and then running it from there, specifically to make it possible to audit the DDL as part of the commit that changed the result classes.
Generated != unauditable, especially when the tools are trying their best to co-operate :D
This incident report reminded me of the 'Game Day Exercise' post from 2014:
https://stripe.com/blog/game-day-exercises-at-stripe
in which one robustness check that should be a continuous-integration kind of test, or at least a daily test of a normally working system, is such a big deal to them that they make a big 'Game Day' about it, and serious problems result from this one simple test.
After they have lots of paying customers, of course.
I know we are supposed to be positive and supportive on HN but this was a red flag that the entire department has no idea what an actual robust system looks like and were so far away from that, after having built a substantial amount of software, that expecting them to ever get there may be wishful thinking.
So I am completely unsurprised that they are having this kind of problem. The post-mortem reveals problems that could only occur in systems designed by people who do not think carefully about robustness ... which is consistent with the 2014 post. It kind of shocks me that anyone lets Stripe have anything to do with money.
(For those wondering why this is important, Sidney Dekker's "Field Guide to Understanding Human Error" is a mindblowing book.)
Especially after a dramatic event, those are very easy reactions to have, and they can sound very sensible.
Devops is like 80% dependency management. It's painful initially but you have to crack down on manual changes to production - all production changes should be defined in code, committed to git, tested, and flow through non-prod environments first. (just had an outage yesterday that was essentially because I failed to do this)
Although in this case the test for this change may just EXPLAIN a known query and ensure the output matches what is expected.
Appreciate the disclosure. Stripe engineers have been so helpful to me and my business. Keep up the good work.
If you have a human there to perform tasks, then it would seem natural to allow them "human advantages" such as the ability to communicate with the person who created the request, or the ability to have some of their own checks and balances before performing the index deletion (ex. let's take a look and see if this seems safe based on the current schema and codebase).
I am also surprised how easy it was for a single dev to make a request that subsequently results in the modification of a production database.
I'm sure stripe has very good metrics of all their systems, nonetheless that's some rockstar level debugging skills.
"Hey {on-call-engineer}, we're seeing a huge slowdown all of the sudden."
"Was there any change in the last few minutes?"
"We just deleted a database index."
"Yup, that'll do it. Gotta restore it."
I mean, you only get these scars from actually working with your DB and hopefully in development / capacity planning stages, so maybe that makes you a rockstar. Not to take anything away from the Stripe engineer(s).
Shouldn't the app developers be in charge of deploying their code and making sure its working? It seems odd that they pass off a migration like this to a DBA to then go deploy randomly, or that they weren't around when it was happening to monitor it.
Also, it seems like there should have been a script that can be run that encapsulates the required dependencies, namely, don't drop an index before building the new one maybe? This should at least minimize the amount of context needed in a ticket.
Relying on fully correct context in tickets seems like it could be super error prone.
And then it needs to rebuild an index on top of the already above-average load.
While splitting these two changes may be silly in the case of a simple index change, I think that it's a good general policy to only deploy the minimal set of changes to a production database at once. On the production system I manage (admittedly, much simpler, and many orders of magnitude smaller), I always deploy changes in two stages, with the second stage generally deployed about a week later, once I'm sure that only new code will be running against the database.
This comment is not meant to second guess the Stripe developers (who produced a great postmortem), but to suggest another possible remediation.
In a continuous delivery environment like this, you generally want to test and validate any change you make. Do any DBs support the idea of turning off an index (but keep updating it). That way you could disable it, keep going for a while, and then delete it once you're sure it's unused?
"dev needed to update index and at time .. submitted two tickets for new ibdex creation and old index removal. at time .. Op processed the removal ticket first which caused outage in service .. It was alerted at time .. and on-call op identified it at time .. He proceeded to ...
Just for people who want to know what's happened but dont care for details.
I've have great success doing this with datawarehouses (i.e. star schema, large tables with few writes). You run the tests after each index change on acceptance. It caught a errors.
For OLTP it's harder, you need to record some production workload and reply it. At your scale it's easier said than done, though.
Unless you're disabling a feature, don't push "quick code fixes". You'll pay for it later.
Rolling back later seems to forgotten in most cases (unless it's disabling a feature). Then you end up with this weird behavior and code path that few remember. "Oh yeah we did that when...." You usually only rediscover it after that quick hack is a problem. This is decades of experience here.
The cause was a defect in the tooling. The requests weren't tied together in the way they were displayed and so the DBA removed the old index first.
In one situation I was working for a supplier to a massive corporation (a household name). They had all sorts of red tape in the process. Every change required filling in forms and getting official sign off from several parties before getting the release code over.
Anyway, we had a database user that was so restricted the we couldn't run the install process of a new product. I knew they ran the releases as SA so the start of my release script upgraded all the permissions of our user to give full access to everything.
What you describe as a solution strikes me as an amazing way to destroy production data. Upgrading every user can basically lead to one hell of an amazing outside attack. I now only have to get one user / password to compromise your database.
A certain amount of red tape is a needed thing to make sure you don't affect your customer's business.
Was more just pointing out that there's often this separation between the people making the changes and the people making sure it's safe to release. But really, the safe to release step is often not going to catch things – in many cases because it's barely checked.
To be fair, I only upgraded my user to give full access to my db and I revoked the permissions once the install script had finished running. I'm not a complete monster :-)
I just didn't want to hear that you had set yourself up for a CEE (career ending event). People tend to be a tad bit wacky and whacky after a security breech.
This is just a failure of the tool that executes indexing operations, and not of the db itself
Companies should think carefully before introducing MongoDB (or any immature project) into critical production stacks.
This issue was caused by a failure in communication between team members. That communication is just as important as good engineering.
It's not like Node, where evangelists DO go around saying it's the best thing ever and blindly ignore the problems with it. Now... there's a good target for snippy remarks! :-P
Furthermore, if Stripe already uses devops, then your statement adds nothing to the conversation (maybe this follow-up comment would have, but your original comment didn't), and if they don't, then commentary about a practice that wasn't being used is the definition of an off-topic comment. So in either case, your comment is worthy of downvotes, regardless of the merits of its topic.
I don't think I've ever seen anyone downvoted on HN for being opposed to established wisdom with good reason. I've often seen people downvoted who were being opposed to either established or non-established wisdom in a way that doesn't contribute productively to the conversation. They weren't being downvoted for their beliefs, but for their lack of productive contribution to the conversation.