51 comments

[ 0.27 ms ] story [ 71.5 ms ] thread
Yes, pretty basic looking mistakes that, from the outside, make many wonder how this got through. Though analyzing the post-mortem makes me think of the MV Dali crashing into the Francis Scott Key bridge in Baltimore: the whole thing started with a single loose wire which set off a cascading failure. CF's situation was similar in a few ways though finding a bad query (and .unwrap() in production code rather than test code) should have been a lot easier to spot.

Have any of the post-mortems addressed if any of the code that led to CloudFlare's outage was generated by AI?

I agree it should not have happened, but I don’t agree that the database schema is the core problem. The “logical single point of failure” here was created by the rapid, global deployment process. If you don’t want to take down all of prod, you can’t update all of prod at the same time. Gradual deployments are a more reliable defense against bugs than careful programming.
This sort of Monday morning quarterbacking is pointless and only serves as a way for random bloggers to try to grab credit without actually doing or creating any value.
pointing out that the basics matter is a valuable insight

if this comes with the side-effect of some random blogger getting "easy" credit then so be it

the same thing happens in economics, where the bitter lessons have to be learned again and again, and nowadays in politics (and even in ethics) too

and of course here people very correctly immediately started talking about the trade-offs involved in making sure that these aforementioned basics are really taken care of, and whether are there low-hanging fruits (does having a better DB schema provide enough benefit for it to worth it? or do you need to couple it with this or that compiler too? but isn't that simply too much? when the critical infrastructure provider should transition to the mindset that most people expect from a critical infrastructure provider? and so on...)

whereas in ethics (and intersectional politics) for example there's an unfortunate bitter denial of trade offs

"If they had a perfectly normalized database, no NULLing and formally verified code, this bug would not have happened."

That may be. What's not specified there is the immense, immense cost of driving a dev org on those terms. It limits, radically, the percent of engineers you can hire (to those who understand this and are willing to work this way), and it slows deployment radically.

Cloudflare may well need to transition to this sort of engineering culture, but there is no doubt that they would not be in the position they are in if they started with this culture -- they would have been too slow to capture the market.

I think critiques that have actionable plans for real dev teams are likely to be more useful than what, to me, reads as a sort of complaint from an ivory tower. Culture matters, shipping speed matters, quality matters, team DNA matters. That's what makes this stuff hard (and interesting!)

What I have seen work in the past is testing using a production backup as a final step prior to releasing, including applying database scripts. In this case, the permissions change would have been executed, the query would have run, and the failure would have been observed.
Formally verifying code is an enormous endeavor.

But a normalized database without NULL should not be a significant burden.

database normalization and formal verification aren't on the same level of difficulty in terms of implementation, and we all could do the former from the beginning, if we choose to (nobody ever chooses to)
> It limits, radically, the percent of engineers you can hire (to those who understand this and are willing to work this way), and it slows deployment radically.

Never seen the amoral-capitalist argument to stunting progress at the expense of profit put so succinctly!

> That may be. What's not specified there is the immense, immense cost of driving a dev org on those terms

I'm happy that we agree on the solution, but disagree only if it is cost worthy. About the cost, I took that into consideration when I wrote the conclusion:

> FAANG-style companies are unlikely to adopt formal methods or relational rigor wholesale. But for their most critical systems, they should. It’s the only way to make failures like this impossible by design, rather than just less likely.

There is an actionable plan in the article. It is possible to run teams like these. It is an economical decision of upper management to run the risk of having these outages vis-a-vis this alternative.

"This massive, accomplished engineering team whose software operates at a scale nearly no one else operates at missed this basic thing" is a hell of a take.
> A central database query didn’t have the right constraints to express business rules. Not only it missed the database name, but it clearly needs a distinct and a limit, since these seem to be crucial business rules.

In a database, you wouldn't solve this with a distinct or a limit? You would make the schema guarantee uniqueness?

And yes, that wouldn't deal with cross database queries. But the solution here is just the filter by db name, the rest is table design.

* The unwrap() in production code should have never passed code review. Damn, it should have been flagged by a linter.

* The deployment should have followed the blue/green pattern, limiting the blast radius of a bad change to a subset of nodes.

* In general, a company so much at the foundational level of internet connectivity should not follow the "move fast, break things" pattern. They did not have an overwhelming reason to hurry and take risks. This has burned a lot of trust, no matter the nature of the actual bug.

* The step in front of this query created updates to policies. It should have been limited in the number of changes it would do at once (and ideally per hour and per day and so on), and if it goes over that limit, stop updating, alert and wait until explicitly unblocked. DO NOT generate invalid config and start using that invalid config, use the previous one that worked and alert.

If this happens during startup use a default one.

That would still create impact (customers and developers would not see updates propagate), but would avoid destroying the service. When it comes to outages, people need to learn to go over what happens in the case of violating an invariant and look at what gets sacrificed in those cases, to make sure the answer isn't "the whole service".

If I get to be impolite, you do this because software architects, as seems to be the case here, often choose "crash and destroy the service" when their invariants are violated instead of "stop doing shit and alert" when faced with an unknown problem, or a problem they can't deal with.

This also requires test-crashing. You introduce an assert? Great! The more the merrier, seriously, you should have lots of them. BUT you will be including a test that the world doesn't end when your assert is hit.

Cloudflare doesn't seem to have called it a "Root Cause Analysis" and, in fact, the term "root cause" doesn't appear to occur in Prince's report. I bring this up because there's a school of thought that says "root cause analysis" is counterproductive: complex systems are always balanced on the precipice of multicausal failure.
It did happen, and cloudflare should learn from it, but not just the technical reasons.

Instead of focusing on the technical reasons why, they should answer how such a change bubbled out to cause such a massive impact instead.

Why: Proxy fails requests

Why: Handlers crashed because of OOM

Why: Clickhouse returns too much data

Why: A change was introduced causing double the amount of data

Why: A central change was rolled out immediately to all cluster (single point of failure)

Why: There are exemptions or standard operating procedure (gate) for releasing changes to the hot path for cloudflares network infra.

While the Clickhouse change is important, I personally think it is crucial that Cloudflare tackles the processes, and possibly gates / controls rollout for hot path system, no matter what kind of change they are when they're at that scale it should be possible. But that is probably enough co-driving. It to me seems like a process issue more than a technical one.

They are not going as far as to blame PostgreSQL, but their switch to ClickHouse seems to suggest that they see PostgreSQL as part of the equation. Would ClickHouse really prevent this type of error from occurring? PostgreSQL already has so many options for setting up solid constrains for data entry. Or do they not have anyone on the team anymore (or never had) who could set up a robust PostgreSQL database? Or are they just piggybacking on the latest trend?
Nothing in this thread about "this should not have happened because Cloudflare is too centralized?"

We have far better ideas and working prototypes in terms of how to prevent this from happening again to be up here trying to "fix Cloudflare."

Think bigger, y'all.

Hindsight bias is always easier but:

> FAANG-style companies are unlikely to adopt formal methods or relational rigor wholesale. But for their most critical systems, they should. It’s the only way to make failures like this impossible by design, rather than just less likely.

That relational rigor imposes what one chooses to be true, it isn’t a universal truth.

The frame problem and the qualification problem apply here.

The open domain frame problem == HALT.

When you can for a problem into the relational model things are nice but not everything can be reduced to a trivial property.

That is why Codd had to as nulls etc..

You can choose to decide that the queen is rich OR pigs can fly; but a poor queen doesn’t result in flying pigs.

Choice over finite sets == finite indexes over sets == PEM

If you can restrict your problems to where the Entscheidungsproblem is solvable you can gain many benefits

But it is horses for courses and sub TC.

I expect the downvotes here but it is important.

It doesn’t matter if you get there through Trakhtenbrot or Rice.

Codd’s normal form is a projection, it will turn your fancy model logic into classic logic.

IMHO it is always something to look for to use as a default, but fails if it is a hard requirement.

One classic way to describe the problem is the White king and Alice.

> ‘I see nobody on the road,’ said Alice.

> ‘I only wish I had such eyes,’ the King remarked in a fretful tone. ‘To be able to see Nobody! And at that distance, too! Why, it’s as much as I can do to see real people, by this light!’

Codd added nulls to handle unknowns or missing data.

The proper use of them is a complex subject. But they are required if you care about semantic correctness and not just logical validity in many cases.

Diaconescu-Goodman-Myhill theorem[0] will show the equivalence between PEM, finite indexes, and choice

[0] https://ncatlab.org/nlab/show/Diaconescu-Goodman-Myhill+theo...

> but it clearly needs a distinct and a limit, since these seem to be crucial business rules.

Isn't that just... wrong ? Throwing arbitrary limit (vs maybe having some alert when the table is too long) would just silently truncate the list

Anybody can be backseat engineer by throwing out industry's best practices like they were gospel but you have to look at entire system, not just the database part

Would be interesting to see the DDL of the table, to see if it had unique constraints.

The query not utilising an unique constraint/index should have raised a red flag.

Sure, a different database schema may have helped, but there are going to be bugs either way. In my view a more productive approach is to think about how to limit the blast radius when things inevitably do go wrong.
rolls eyes

No, their error was that they shouldn't be querying system tables to perform field discovery; the same method in postgresql (pg_class or whatever its called) would have had the same result. The simple alternative is to use "describe table <table_name>".

On top of that, they shouldn't be writing ad-hoc code to query system tables, but having a separate library instead to perform those kind of task mixed with business logic (crappy application design).

Also, this should never have passed code review in the first place, but lets assume it did because errors happen, and this kind of atrocious code and flaky design is not uncommon.

As an example, they could be reading this data from CSV files *and* have made the same mistake. Conflating this with "database design errors" is just stupid - this is not a schema design error, this is a programmer error.

Of course it shouldn't have happened. But if you run infrastructure as complex as this on the scale that they do, and with the agility that they need, then it was bound to happen eventually. No matter how good you are, there is always some extremely unlikely chain of events that will lead to a catastrophic out. Given enough time, that chain will eventually happen.
> No nullable fiels.

If you take away nullability, you eventually get something like a special state that denotes absence and either:

- Assertions that the absence never happens.

- Untested half-baked code paths that try (and fail) to handle absence.

> formally verified

Yeah, this does prevent most bugs.

But it's horrendously expensive. Probably more expensive than the occasional Cloudflare incident

Are there outages that should have happened?
One of the things I recommend most engineers do when they write a bug is to first take a look and see if the bug is required. Very often, I see that the codebase doesn't need the bug added. Then I can just rewrite that code without the bug.
I was expecting a critique on the centralized nature of the infrastructure and the fragility that comes with it.
Do you mean Cloudflare's design, or the widespread reliance on Cloudflare?

I was hoping for a critique of the latter.

I think the author is trying to apply a preconceived cause on to the cloudflare outage, but there’s not a fit.

E.g., they should try to work through how their own suggested fix would actually ensure the problem couldn’t happen. I don’t believe it would… lack of nullable fields and normalization typically simplify relational logic, but hardly prevent logical errors. Formal verification can prove your code satisfies a certain formal specification, but doesn’t prove your specification solves your business problem (or makes sense at all, in fact).

I initially read the title as "Cloudflare outrage.." and I was thinking how nice someone is thinking of the poor engineers who crashed the Internet.
Adding distinct or group by to a query is not some advanced technic comments are suggesting. It does not slow down development one bit, if you expect distinct result you put explicit distinct in the query, it's not a "safety measure for insulin pumps". Scratching my head what I've missed here, please enlighten me.
DISTINCT would just be masking the query bug

Random DISTINCT is usually a code smell that indicates an incorrect join / filter

> I base my paragraph on their choice of abandoning PostgreSQL and adopting ClickHouse(Bocharov 2018). The whole post is a great overview on trying to process data fast, without a single line on how to garantee its logical correctness/consistency in the face of changes.

I'm completely mystified how the author concludes that the switch from PostgreSQL to ClickHouse shows the root of this problem.

1. If the point is that PostgreSQL is somehow more less prone to error, it's not in this case. You can make the same mistake if you leave off the table_schema in information_schema.columns queries.

2. If the point is that Cloudflare should have somehow discovered this error through normalization and/or formal methods, perhaps he could demonstrate exactly how this would have (a) worked, (b) been less costly than finding and fixing the query through a better review process or testing, and (c) avoided generating other errors as a side effect.

I'm particularly mystified how lack of normalization is at fault. ClickHouse system.columns is normalized. And if you normalized the query result to remove duplicates that would just result in other kinds of bugs as in 2c above.

Edit: fix typo