A Foolish Consistency: Consul at Fly.io
fly.io
fly.io
Google around company has down time with consult
https://www.protocol.com/newsletters/protocol-enterprise/rob...
https://danveloper.medium.com/on-infrastructure-at-scale-a-c...
I had use consul extensively in 2016-2017 with consul template.
The problem with consul is it's very easy to reject connection. Accidently have a node with too old or too new version join and entire cluster will be down. Which can happen easily in an autoscaling env.
Another issue is again, agent takes a lot of time to be cleanedup and removed, say in autoscaling vm where node come and go all the time you ended up with so many dead node on consul ui. Again, this is 2017 so It might changed now.
I have been replace consul with something suprisingly simple, and I think in retrospective that's all I want.
A local process run a key value API on top of a local database(can be SQLite or anything up to your taste. Its replace its state with a central server.
If the central server is down, the local agent still has its state to continue serving stale data.
As I understand it, the reasonable-person thing to do here is to have federated Consul clusters in different regions. We run up against the problem that we're not hosting one application globally, but rather a zillion applications; every node needs to know about every instance of every application. So things like losing the global KV store are problematic for us.
Have you considered nerd-sniping colmmacc? ;)
If fly.io found the upper bound on a Consul scale out, what do you think a reasonable threshold looks like for a smaller system?
First, I love this blog post and I tweeted about it, so please don’t interpret any of my feedback here negatively.
> If fly.io found the upper bound on a Consul scale out, what do you think a reasonable threshold looks like for a smaller system?
I don’t know the exact scale of Fly.io’s Consul usage, but I would imagine they’re far, far from the upper bound of Consul scale out. We have documented some exact scale numbers here[1]. And of course these are only the customers we can talk about.
I didn’t read this post as talking about scale limits. Instead, it discusses the tradeoffs of certain Consul deployment patterns, and considers whether their particular usage of Consul is the best way to use a system with the properties that Consul has. And this is a really important question that everyone should be asking about all the software they use! I appreciate Fly sharing their approach.
To answer your second part (what is a reasonable threshold), we have documented recommended hardware requirements and scale limits here: https://learn.hashicorp.com/tutorials/consul/reference-archi... This is the same information we share with our paying customers.
It scaled very well from "nugget of an idea" to "whoah maybe this is going to be a big company".
I think the best software buys time for the users. Consul bought us years.
That's (really) good documentation, but doesn't directly address the Fly.io situation nor my situation: multiple data-centers in multiple jurisdictions around the globe.
> https://learn.hashicorp.com/tutorials/consul/federation-goss...
> To start with, we have a single Consul namespace, and a single global Consul cluster. This seems nuts. You can federate Consul. But every Fly.io data center needs details for every app running on the planet! Federating costs us the global KV store. We can engineer around that, but then we might as well not use Consul at all.
I think a better way to ask my question might be: Is there a threshold below which can we safely run Consul in a single global cluster like Fly.io tried before it got too unwieldy?
Really, a node doesn't want a consensus on what services are available, it wants to know what services are available to it. Hopefully that's the same globally, but waiting for global consensus means sending more traffic to the wrong place than if you had full mesh announcements (probably not great at scale) or announcements sent to a designated node(s) in each datacenter (possibly gossiped from there to each node, if desired, could be looked up on demand from the monitor node). Of course, that works only if you're ok assuming that a service reachable by one node in a datacenter is reachable by all nodes in a datacenter.
Anyway, you still may want to deal with requests that were sent to the right place, but are received by the wrong place, because the right place changed beyond the observation window for the routing decision. (This is also touched on in the article).
Distributed systems are fun and exciting! And, there was another post today noticing that even a single computer is really a distributed system (and they have been for quite a while)
When I referred to a 'scaling problem', I was referring to scaling that specific Fly.io architecture. The bad one, the one without federation. I'm interested in the safe operating limits for that configuration precisely because Fly.io seemed to make a really good go of it for a long time.
I mean, it isn't NY Times style lede buried in a wall-of-text 10-feet deep. It is right in the title, A foolish consistency... (:
Ok, look, I know CAP and distributed databases are hard, but this article is presumably about to go into some deep wading, and it basically does the Barbie "Math is Hard"? Come on.
"Consul is designed to make it easy to manage a single engineering team's applications. We're managing deployments for thousands of teams. It's led us to a somewhat dysfunctional relationship."
Um, I don't know consul's gotchas because I am a Cassandra guy, and a demi-Dynamo guy. Yes yes, I know any problem that is attempted to be solved by cassandra fits the joke "well, now you have two problems". But it does scale.
Why is raft needed for a simple quorum write for a key-value <service name> = <ip> ?
Thousands of teams does not sound like a hard database scaling problem. How often is this read? How often is this written?
I didn't go into detail about Raft because it isn't the point of the article, and because I don't want people checking out because they feel like they need to grok distributed consensus to understand what we're saying. If that means we lose people with strong opinions about Raft, I'll accept the tradeoff.
I've been deep into distributed consensus the past year—working on a 1 million TPS replicated state machine called TigerBeetle [1]. I would have enjoyed even more detail, only to understand the problem better, but I loved this line: "With me so far? Neither am I."
I don't really follow k8s, but is etcd no longer required for it?
(But if you liked this article at all, I also blame Kurt for the feedback that got it from the tangled mess it was to the slightly-less-tangled mess it is now).
Or have someone else deploy it for you: https://www.vultr.com/docs/configuring-bgp-on-vultr/ | https://netactuate.com/anycast/
All big cloud providers have anycast load balancer offerings. In my experience, Fly's load balancer is wayy more simpler than those to use (because it is the only way to load balance, like with Cloudflare).
Note that in the case of fly you don't directly get traffic to an anycast IP but through a reverse proxy.
I could imagine that they replicate connection states to all pops so that traffic that arrives in the wrong pop can be rerouted.
In the past people were concerned more about route flapping disrupting TCP connections. It seems that people aren't worried about that anymore. Google does it.
Aha, that brings up technical articles, thanks. TFA does mention it multiple times so mea culpa.
I like Nomad a lot. I think it's a better fit for what we're doing than Consul is (they're both great, but I think Consul is the bigger sticking point). You'd get different opinions from different people on our team, but I think Nomad's going to be around for awhile. But there are things we very much want to ship that we can't ship on Nomad.
I would 100% use Nomad again if I had a somewhat complicated app I needed to deploy and couldn't use Fly.io for. (I'd use Consul too, for that matter.)
Per the sibling comment: we are indeed writing a new orchestration system in Go, called `flyd`.
We also need precise placement. We have people who want to run 8 VMs in London, 3 VMs in Los Angeles, and one VM in Sydney. They also want to do rolling deploys that revert on failure. Nomad's scheduling is not that precise.
Databases too. Both Nomad and k8s have ways to do persistent workloads, but they rely heavily on the underlying infrastructure to "move" volumes between throwaway containers. We don't want that, we actually want something closer to old school VM provisioning than "orchestration".
I did this with Nomad by writing a small API to "place" host volumes which Nomad can use for job placement constraints automatically. It works shockingly well for my use-case which I think is somewhat similar to Fly's? A smallish number of containers that require host persistent storage, and don't expect anything to move -- just disappear forever (persistent til' it ain't).
What we need is to be able to target machines to specific volumes. And for things like database clusters, we need to control restart order during upgrades.
Is this for scaling existing apps up (eg flyctl regions add ...) or for new deployments (flyctl deploy)?
I suspect the former (scaling existing) as artifact distribution and deployment parameters like health checks seem like they prevent subsecond deployments (even ignoring the time for initial artifact uploading/building). Although my view is probably quite biased by Nomad having a much better chance at solving the former than the latter!
(Also hi! I appreciate our chats in the past and feel free to reach out if you're willing to brain dump Nomad gripes on me. :) )
Some machines operations are slow, some are fast. Create is slow, update is slow. Start and stop are fast. Future "suspend" and "resume" are very fast.
For the regions case, people use these by having a couple of machines per region they care about. Then they start and stop as needed. A stopped machine can be migrated between nodes, but we ensure it's ready to start quickly if we do that.
Some interesting things happen with this model. Create is slow, but we are able to make it fast _sometimes_ because we can target creates at hardware that already has the rootfs cached.
Updates don't work like nomad, we update machines in place for a rolling deploy. This lets us do things like pull an image in parallel, then stop the machine, update, and restart very quickly.
We're also doing things differently with health checks. We may not wait for an active health checks before sending a machine an HTTP request. Many workloads don't even care about health checks, they just want a VM running and streaming logs back as fast as possible.
There are features I could ask for in Nomad to do what we'd need, but they'd make it not Nomad. :D
I know it's just a wild coincidence, but I couldn't help but be reminded of https://github.com/flynn/flynn
This line from the post indicates to me that they're writing it themselves (since they wouldn't be worrying about being baked into orchestration code if it's Consul and Nomad). Still, I'd also be interested in what they're doing.
As an Elixir developer, fly.io has been a tempting option because it has a lot of buy-in in the community, but counterintuitively posts like this make me question if fly.io is really for me and my relatively small and local apps. Apps with a global presence requiring low latency everywhere, as this post shows, invites a lot of technical complexity. Is fly.io mostly for the "big dogs" then? Is it still a good, affordable solution with nice developer UX if you only ever intend to deploy to a single region?
If you run your app on your own servers with your own load balancers and terminate your own TLS, you avoid a lot of this infrastructure. If you use anyone with a "cloud" load balancer, you get almost exactly what we've described here.
Complexity is a legitimate reason to manage your own server. A single server with a single database and nothing between you and the users avoids a lot of complexity.
I will say that I think the days of single region deployments are coming to an end, even for “the little guys”. Regulation all over the world is demanding your application be region aware and the nature of the internet means your users will come from those jurisdictions.
If anything we need simple web stacks that acknowledge this and hosts (like fly) and data tiers that enable it trivially.
Sorry for the tangent-y rant.
overall though, the application sounds unique enough to where a custom directory/catalog/distributed load balancer may make sense.
NATS has the benefit of being p2p, so when a VM comes up in Sydney, the other Sydney nodes see:
- The nats message in about 5ms
- Time passes (call it 1-10s when things are working well)
- Consul data includes new entry
We also use "hints" to broadcast things that we can afford to never see. Load on VMs is an example. When a VM hits its max concurrency, we broadcast a NATS message so other nodes can take that into account for load balancing.
It's super gross!
The basic use case here is: you start or stop a VM in Tokyo; our Consul Server cluster is halfway around the world, and every other host in Tokyo needs to wait for Consul to update to see that change, even though it happened right next door. With the hints, the change percolates instantly, and eventually Consul catches up and we reconcile.