7 ms·
I've always had a hard time understanding the benefits of supervision trees in today's world. Either the thing you're scaling / respawning is stateless, and th
by bsaul 5y ago
I've always had a hard time understanding the benefits of supervision trees in today's world.
Either the thing you're scaling / respawning is stateless, and then anything from kubernetes to amazon ecs will do.
or it's stateful with a state that you need to persist somehow, and then frankly the hardest part clearly isn't the way web server scale, but rather how the data storage and retrieval mechanism works (along with handling the potential transactionnal behavior requirements).
What am i missing ?
- blacktriangle 5y agoIf the choice is between having my language solve a problem or having to reach for Kubernetes, then I'll take the language solution every time. I'd happily program in Brainfuck if that's what it took to avoid Kube.
- pantulis 5y agoBut then it's the runtime what is solving the problem for you, not exactly the language.
- rapsey 5y agoErlang is completely tied to its runtime. Making a distinction is not really important. The point is Erlang gives you the best parts of much more complex solutions in a simple easy to use package.
- pantulis 5y agoAgreed, it's kind of a pedantic/moot observation.
- hyperhopper 5y agoThats even better! That way, you get to program with much saner assumptions in a more pleasant environment, rather than having to write code to smooth that over manually, or deal with configuration and operational hell to make it work at a deployment level.
- linkdd 5y ago> I'd happily program in Brainfuck if that's what it took to avoid Kube. Why though? Why hate k8s so much that you would choose an unreadable language?
- devoutsalsa 5y agoI don't think anyone actually uses Brainfuck. They were being sarcastic.
- blacktriangle 5y agoI was, but the deeper point really is the tradeoff between code complexity and operational complexity. And I'll choose code complexity every time since it occurs early in the process and is less likely to blow up in my customer's faces.
- deleted 5y ago[deleted]
- void_mint 5y agoRight, but the choice is actually "Being able to hire to solve a problem" or "Being required to upskill any developer to become productive", and most would (rightly) choose the former.
- deleted 5y ago[deleted]
- grw_ 5y agoapplications can be stateful but not require persistence, mostly real-time applications like game servers, VOIP, etc.
- lolinder 5y agoYes, Kubernetes/ECS/whatever solve similar resiliency problems, but that also means that Erlang's supervision trees could be used as a substitute for Kubernetes in many cases. Having your language runtime take care of what would otherwise involve a lot of external configuration is a plus for many people.
- pantulis 5y agoBut for people trying to sell enterprise consulting services, relying on Erlang is not that easy --although it can be done, been there! Which goes on to say that there is no silver bullet but there is strength in using Kubernetes, it's kind of a lingua franca.
- linkdd 5y ago> Erlang's supervision trees could be used as a substitute for Kubernetes in many cases I disagree, do they solve the same kind of problem? Yes. But the same problems? No. If part of your application needs to be restarted, why would you restart the whole application? Kubernetes is not an excuse to avoid application resiliency. Erlang/Elixir is not an excuse to avoid infrastructure resiliency. Part of your program may crash, your node may crash. Both needs to be restarted.
- wolf4earth 5y agoI wonder how Kubernetes would look like if it was built on top of the BEAM.
- dnautics 5y agoI think Amy null is working on that. I got a taste of it since I wrote a vm orchestrator in elixir... It should definitely be possible. With protocols and behaviours it should be easy to build plugins that "just work".
- bostonvaulter2 5y agoIs that project posted anywhere? Or is there a way to follow its development?
- knrz 5y agoSaid another way, why would I reach out to K8s or ECS if I can handle all that within the runtime? In my experience with Elixir, bringing everything into the code reduces the surface area of complexity and makes it much easier to model in your head.
- whalesalad 5y agoYou’re missing a lot! In the case of a simple request/response web app yes it doesn’t do a whole lot. Imagine you’re building a complex system with lots of different behavior patterns. Let’s say a backend that fans out to 100 different 3rd party APIs, like a shipping aggregator that needs to talk UPS, FedEx, USPS, Canada Post, Royal Mail, etc… and you want to be able to carefully control rate limits, batch sizes, etc.. to those endpoints. An actor system with supervision trees is a very good way to build a system like this. Also... the rhetoric here on HN about Erlang/Elixir vs. Kube really needs to stop. People are misinformed. They are not mutually exclusive, you do not need to choose one or the other. We need to reconcile that because the discourse always goes to this weird war in the comments.
- driton 5y agoThat sounds very interesting and specific. If it's not a random example and if you're at liberty to say, would you mind elaborating further how Elixir specifically excels in that particular use case, and what would an alternative approach, regardless how cumbersome, be?
- whalesalad 5y agoI have been meaning to write a blog post - I am going to escalate the priority on that.
- dugmartin 5y agoThis really isn't an elaboration on the grandparent comment but if you are interested in general in learning how Elixir excels at data pipelines I'd suggest looking at this library: https://hexdocs.pm/broadway/Broadway.html https://hexdocs.pm/broadway/Broadway.html
- bsaul 5y agoyour example is interesting. I assume the reason is that it's an in-between situation between stateful and stateless: aka shipping using 3rd party api is a transient state of a complex process that can be ultimately recreated from the orders stored in the DB, but better not for speed reason. I wonder if there are other patterns like that.
- athenot 5y agoWhy not both? Resiliency of a cluster with k8s or similar orchestration, AND resiliency of the individual nodes within that cluster, taking advantage of supervision trees. (Also, to complete this picture and provide resiliency of the service as a whole, add load balancing across multiple availability zones.)
- linkdd 5y agoThis. Restarting an Erlang process and restarting a Docker container is not the same. Let's say you create an Erlang process per request and that process crash, you don't want to restart the whole node, do you? Application resiliency and Infrastructure resiliency are not incompatible, in fact, they are complementary. Also, use libcluster[1] and horde[2], and you will never deal with leader election again. (which Kubernetes does not provide). I've seen many Kubernetes Operators not handling more than one replicas, and that's a shame if you want High Availability. [1] - https://hexdocs.pm/libcluster/readme.html [2] - https://hexdocs.pm/horde/getting_started.html
- rapsey 5y agok8s is the rest of the world playing catchup to what Erlang has been doing for decades. Sure it is more powerful and does a lot more things. It is also insanely more complex and hard to use compared to Erlang.
- dnautics 5y ago> but rather how the data storage and retrieval mechanism works if you are going to rely on a stateful service to do this for you eventually the latencies will add up. for in-memory data, you're going to take a trip to redis and back. For persisted data, you're going to take a trip to postgres and back. Plus internal locks in those systems. Plus if you get bigger, you will need sharding logic, and maybe even another distributed shim (like galera or greenplum) on top, which adds even more latency. For a real-world example of where supervision trees were very important, I once managed a virtual machine orchestrator I'd written in elixir, and they periodically polled the virtual machines to retrieve state. It's a nontrivial question, what do you do when the state of the system is not what you expect? (perhaps something IRL has changed though a side door) And what do you do if you have multiple concurrent independent systems that are dependent on that real-world state? With a supervision tree, the solution is simple (1 LOC), you slay the parent supervisor and trigger ALL the relevant processes (and no processes, say, checking in on a different machine) to re-establish the ground truth. And you don't have to wait for containers to spin up, etc, because erlang processes are snappy, so there is less downtime. In the system I was managing there were many, many internal errors (netsplits, etc) and the customers generally didn't notice.
- jerf 5y ago"I've always had a hard time understanding the benefits of supervision trees in today's world.... What am i missing ?" I've retained the principle even as I've left the Erlang ecosystem because it turns out to be a fairly convenient way of structuring a lot of concurrent network problems. Reifying servers as explicit things in your codebase is really helpful; at that point you might as well have them restart and all that jazz, but to me the real virtue is just the utility of the organizational scheme to my code. That they are composable is also pretty useful. I am literally taking a brief break just now from taking one server that I was writing that was maintaining a connection to an authorization service and translating that into local actions and splitting it into two servers, one that maintains and manages the connection and one that is solely responsible for the logic of dealing with what's coming in and out from that server, turning what was becoming rather nasty intermingled code into two separated bits of code that each make their own sense. Because the server abstraction is composable, the entire rest of the program doesn't notice; previously I had one "service", and now I've replaced that service with a (sub-)supervisor that starts the two services up. The interface to the rest of the program is identical; the same "start" and "stop" operations are done, and the "tree"-ness is automatic. The rest of the program doesn't care that what used to be one running server is now two cooperating servers because the composability of the concept of "server" hides that away cleanly. With the servers reified, the process of starting the system is also clean and easy to explain to other people, rather than bespoke processes for starting each one. I've got fairly granular services here compared to some people, but it's still pretty easy to end up with 5-10 distinct types of "servers" in my programs providing internal services. It's nice that they don't all have their own code for handling errors, getting restarted, managing shutdowns, etc. It is not night and day. I don't want to oversell this, either. It's not like you'd be crazy to not be using this as an organization technique. You can certainly make large programs without this technique. But it is quite convenient to reify the concept of a "manageable tree of services" as explicit objects in your code, and then be able to deal with them as reified objects, just like anything else that we've found convenient to reify as explicit objects over the years rather than leaving implicit, with bespoke unique interfaces for dealing with each individual object. It's one of those things where, individually, each individual such concept isn't a huge deal, but one of the reasons why 2020s programming can be more effective than 1980s programming is precisely that we've done this to some many things and reduced the number of bespoke one-offs we have to deal with. Explicit service trees aren't going to change your life forever but it's one more incremental improvement that's worth adding to the stack.
- tahon 5y agoJose wrote a blog post on this exact question http://blog.plataformatec.com.br/2019/10/kubernetes-and-the-erlang-vm-orchestration-on-the-large-and-the-small/ http://blog.plataformatec.com.br/2019/10/kubernetes-and-the-...
- nivertech 5y agoThese concepts are roughly similar conceptually, but have very different implementations and usecases. The common idea is: there is a current (possibly wrong) state of the world, and there is a desired state. Let the system use control feedback to automatically bring itself into a desired state. i.e. the current state: I have 3 workers. the desired state: I want 5 workers. Now on top of that add an hierarchy or workers. K8s has a predefined workers topology: deployment -> replica set -> pod -> container. Which uses a small number of patterns (service, StatefullSet, etc.) While Erlang/OTP allows arbitrary supervision trees composed out of several primitives: one-for-one, one-for-all, etc. Both have a concept of a cluster composed out of nodes. K8s does this on the [micro]services level, while Erlang/OTP does it on the clustered monolith level. K8s has a coarse-grained scheduler, while BEAM has fine-grained.
- Fire-Dragon-DoL 5y agoThe language is immutable, but hardware is stateful, as well as external software. So genservers are abstracting that,while keeping your code pure