In short
Podcast Notes: Modern Distributed Applications with Stephan Ewen
Podcast Overview
- Title: Software Engineering Daily
- Description: Technical interviews about software topics.
- Episode Title: Modern Distributed Applications with Stephan Ewen
- Episode Description: Discusses the challenges of creating resilient, reliable, and fault-tolerant distributed applications. Explores the impact of event-driven models and the solutions provided by Restate.
Key Points Discussed
Challenges in Distributed Applications
- Resilience & Fault Tolerance: Complexity in ensuring applications are resilient and can recover from failures.
- Non-Functional Concerns: Engineering time is spent on retries, state synchronization, and distributed coordination.
- Event-Driven Model: Intended to simplify process but may complicate debugging and operational challenges.
Stephan Ewen’s Background
- Founder of Restate: Previously co-created Apache Flink, focusing on stream and batch processing.
- Professional Journey: Experience began with early stream processing systems, evolved into developing Flink, and now focuses on transactional event-driven applications.
Introducing Restate
- Definition: A durable execution framework aimed at building resilient distributed applications.
- Core Features:
- Durable execution that allows reliable recovery of steps in processes.
- A holistic framework that incorporates distributed communication and state management.
Trends Driving Interest in Durable Execution Frameworks
- Challenges of Current Systems: Many developers face issues with microservices, leading to complexities that detract from core business logic.
- Backlash Against Microservices: Difficulty in managing distributed infrastructures leading some to revert to monolithic architectures, while others seek better foundational tools.
Current Solutions vs. Restate
- Traditional Approaches: Use of queues and databases, manual retry loops, leading to complex and brittle systems.
- Restate’s Approach: A shift towards durable, stateful function executions that simplify the development process.
Life Cycle of Restate’s Durable Execution
- Event Triggering: External client initiates an execution which is recorded in Restate’s log.
- Service Invocation: The service is invoked through a persistent connection.
- Contextual State Management: Ensures that state and results are consistently managed across retries and failures.
- Durable Processing: Results and logs are committed to a consensus log, allowing for reliable recovery.
Incremental Adoption of Restate
- Implementation: Teams can integrate Restate gradually without the need for a complete overhaul.
- Educational Shift: Developers must adapt to thinking of services as durable and stateful, rather than adhering to traditional workflow paradigms.
Use Cases for Restate
- Ideal Scenarios:
- Applications requiring strong transactional guarantees.
- Workflows that involve multiple state updates.
- Use in environments needing both cloud and self-hosting capabilities.
- Unexpected Use Cases:
- Replacement of complex queuing systems.
- Custom workflow engines for internal processes and even machine control in factories.
Challenges and Future of Durable Execution
- Education and Awareness: As durable execution becomes more known, there is a need for broader understanding beyond traditional workflow paradigms.
- Future Impact: Anticipated widespread adoption that could redefine how distributed systems are designed, particularly with the integration of AI-generated business logic.
Upcoming Developments
- Next Version: Focuses on enabling distributed deployment, including replication and scaling, set to be released shortly after the podcast airing.
- User Engagement: Actively seeking feedback and collaboration with users to refine understanding and usage of Restate.
---
Key Takeaways
- Restate aims to revolutionize how developers approach distributed systems, making them easier to build and manage.
- The transition towards durable execution frameworks is seen as a necessary evolution in the face of increasing complexities in software architecture.
- Incremental adoption of Restate allows teams to gradually shift their architecture, minimizing disruption while enhancing reliability and resilience.
This episode offered a deep dive into the challenges and innovations in modern distributed application development, highlighting Restate as a transformative tool in the software engineering landscape.
Written by AI. May contain mistakes. Listen to the episode to check what was said.
Transcript
Automatic transcript. May contain errors.0:00A major challenge with creating distributed applications is achieving resilience, reliability, and fault tolerance. It can take considerable engineering time to address non-functional concerns like retries, state synchronization, and distributed coordination. Event-driven models aim to simplify these issues, but often introduce new difficulties in debugging and operations. Stefan Yuen is the founder at Restate, which aims to simplify modern distributed applications. He is also the co-creator of Apache Flink, which is an open-source framework for unified stream processing and batch processing. Stefan joins the show with Sean Falconer to talk about distributed applications and his work with Restate.
0:44This episode is hosted by Sean Falconer. Check the show notes for more information on Sean's work and where to find him.
1:02Stefan, welcome to the show. Thanks for having me. Hi, Sean. Yeah, absolutely. Thanks for doing this. I'm excited to get into it. So I wanted to start off with a bit of your background. What was your journey and experience from working on Flink to now being the CEO and founder of Restate? Yeah, most of my professional life was Apache Flink so far. As part of the team that started it in 2014, and in a way, probably I'm responsible for a lot of the early architecture of Apache Flink around the way the data plane, the coordination, the snapshots, and all of that worked. The journey actually started even earlier.
1:42In a way, it started when I was still at university and grad school, and we're working in this sort of intersection between Hadoop and databases and some of the very, very early steps of stream processing had just come up, you know, like Storm was a new thing back then. And after that, we actually took the project that we worked on at university and turned it into an open source project. It was sort of a mix of a pipeline batch processing system and maybe some early steps of a streaming system. And like as part of the open source journey, we found our sort of sweet spot with users and stream processing, turned it into a stream processor.
2:14And then, you know, I kept writing that wave of Kafka, Flink, the sort of advent of real-time stream processing, stateful stream processing, unified version stream processing, and so on. I left that space roughly 2021 to focus on something new and sort of a project that, or a set of problems that caught my eye back then was kind of similar to the problems that we're trying to address with Flink. Flink being sort of an analytical system for robust analytical real-time pipelines. And we're more and more being asked for how do you build more like transactional event-driven application, not the applications that aggregate events and join events and so on.
2:52And yeah, feed dashboards, feed recommenders and so on. But the type of pipelines that in the end actually process payments, invoicing, orchestrate orders and shipments and so on. Like these types of applications that folks are sort of stitching together manually with databases and queues and lots of custom logic. And it felt like folks were looking for a solution. They even turned to systems like Flink to kind of implement that. It's not a great match. You don't use an analytical system for transactional processing as a general rule of thumb. But I guess this question came up more and more. We thought, okay, we should probably start looking into that space and building something.
3:27And that is when we started working on Restate. We've been doing this for around about two years now. And there we are. So how do you sort of describe Restate? Do you term it or do you sort of bucket it into this class of like durable execution frameworks? Yeah, it's definitely puts durable execution as one of the main ingredients on its list. So you're right, there's this big bucket of durable execution engines. It almost seems like there's a Cambrian explosion of those right now, like there's a new one every few months. And Reset is definitely a good candidate if you're looking for a durable execution engine.
4:02It's a little more than that, though. It's really, I would say, a more holistic platform for building distributed resilient application. It doesn't just include durable execution as in being able to sort of journal different steps in your process and being able to reliably recover them, which is this notion of, you know, like workflow style logic, but implemented in general code and general purpose code, not in like DSLs or so. So Restate goes quite a bit beyond that. Restate sort of tackles the more holistic problem of like, what if we try to apply this idea of durable execution, not just to a single workflow, but what if we sort of incorporate concepts like distributed communication, a state that outlives an individual like workflow or an individual durable execution?
4:45How would all those things interact? How do you build sort of a more general platform that applies that level of durability and resilience to distributed services in general and not just like an individual workflow? Going back to the sort of rise of durable execution frameworks and the idea that there's sort of like, seems like there's a new one every six months or whatever. What do you think that is the case? Like, this is something that people are investing time into, and it seems like there's growing interest in it. Yeah, I think this is because the state of the art is sort of, it's not feasible.
5:18I think it's more and more developers and companies reaching that conclusion that the challenges that you're facing today when you're implementing distributed apps, it's just not something that many software development teams can handle. And the ones that can handle that, they're not really using their time well, because they're spending most of their time really on problems that have nothing to do with the business logic. They're spending their time on problems like, you know, figuring out race conditions and how to avoid split brains and how to avoid lost updates if a zombie process appears and all those things, you know, they should be focusing no one making, you know, adding features to the application and not creating the workarounds around distributed systems problems.
5:58I think this has gotten particularly bad with the rise of microservices. And I think it's a big part of why there's a little bit of a backlash even against microservices right now, like for all the benefit they give you, I think many people realize how challenging distributed infrastructures with lots of microservices are. And, you know, some are just saying, okay, let's go back to the monolith. It was just a bad idea in the first place. And then there's a whole group of people that say like, no, no, we actually like a lot of the benefits that microservices give us. We just want like a stronger foundation to build them on.
6:27We want something that sort of frees us from dealing with many of these problems. And I think this is where the whole wave of durable execution systems got started, kind of that movement. And I would say it gets actually more and more necessary to have those systems because applications get increasingly distributed, right? And it's not only the services you built yourself, but more and more functionality that you access is hidden behind APIs provided by SaaS vendors and so on. These are all services that you interact with. They become part of your microservice architecture, even if you don't really own them and so on.
6:59But they add to the complexity of the problem. And that's a trend that's only increasing. I think that's not going back. Yeah. Even though he said, like, I hate microservices and down with microservices, I'm going to go back to the monolith. Even if I build that monolith and I deploy it and I'm able to manage that, I doubt that application exists in isolation. It's going to have interdependencies to third-party services, which then are going to reintroduce essentially all these distributed system problems. So if I'm connecting up microservices or even I'm calling like a third-party API, then there's all kinds of things in a distributed system that can go wrong.
7:33There can be certain outages. So without using some sort of framework to help me solve those problems, what are teams typically doing to do that? Are they just sort of making those requests and then at best they're doing some sort of retry scheme with exponential back off to see if they can push that through and they're okay with sometimes that not happening? Or what is it that, you know, companies are doing to try to solve these problems now? Yeah, I think there's a lot of different approaches to that problem. There's, I think the first observation I would throw in is like, there's a lot of companies that actually don't really get it right.
8:06You know, just the fact that there's still so many websites that tell you like, don't hit F5 while you're undergoing a booking on order process is like one indication that they can't really handle these like things well, like concurrent requests. You still see lots of like a lot of artifacts that if you are a developer, you can, you something has gone wrong in their backend right now. I would say just like, first of all, a lot of times it's not actually getting solved correctly. And I actually heard a quote in another podcast from somebody who works at a food delivery startup who said like for many, many years, their solution was just like ignored and sent a voucher until it like at some point just became really expensive.
8:39Ignore the problems and send vouchers. I would say if you want to actually solve the problem, one of the ways to do it typically is to stitch together different systems. The typical ingredients will be use a queue, a database, build your own retry loops with backoff. But it's not just as simple as implementing a few retries with backoff, right? Like you have to always kind of worry about, okay, what actually, if I guess the retry actually happening, if you're triggering this as an RPC call, you know, you might be trying it, the whole process might actually go away. Then there's a next step, you probably put a queue in front, actually say, you know, even if the process gets away, the event gets redelivered somewhere else.
9:14Now you have to actually worry about the fact, you know, you might actually have two processes that work on the same event twice. Like, are they overriding each other with their retries? Do you want to throw in a lock? Do you want to introduce versioning and conditional updates and so on? Then, you know, you might be interacting with APIs. You might call them, get a result, crash afterwards, recall them, might get a different result the second time you call that. So the next retry actually follows a different control flow than the first one. And things go completely haywire. It doesn't stop with a retry.
9:39I would say it's very often you start with a queue and a retry, and then you incrementally just add like bits to guard against that bucket that you discovered at that. And then incrementally, it just grows really complex. And it makes a hidden assumption on this is exactly how that queue behaves. And that's exactly how that API behaves. And then somebody changes that and everything breaks again. And then you're back to fixing this. I don't know. I don't think there are really good solutions. If you go to the extreme end of saying, okay, here's an extremely sensitive, high value process, then sometimes folks throw in workflow engines as one solution, right?
10:08Let's say here's an order process that we really don't want to go wrong because that can actually cost us a lot of money. you might pull in a heavyweight workflow orchestrator, but it's really not something you typically pull in for like small microservice logic, first of all, because it's really a complicated component to have in the stack. And second of all, it's sort of really foreign citizen. It doesn't interact well with a lot of the other logic. Yeah. And it's probably a little heavyweight for the majority of the types of calls that you might be making in between microservices or even to external services.
10:40Yeah. And this is actually one of interesting things that durable execution brings in specifically in like an implementation like we're looking at at restate if you can actually make durable execution cheap cheap as in low latency having a durable step introduces a very moderate latency overhead then what you can actually do is you can start assuming these workflow style guarantees for a lot of code in your application it's no longer sort of prohibitive to do that from two sides like it's no longer so slow and expensive that you say oh i really don't want this here this is in the synchronous path of the user interactions is going to make everything really sluggish, but it's going to feel still fast doing that.
11:15And the second thing is you're still writing code. It still fits in with all your tools and with all your deployment and pipelines and all your versioning, all your schema registries. You can still keep using that. So it feels like you can keep doing mostly what you are. You're just adding this fine-grained reliability to your functions and get a lot of the problems out of the door. That's actually the ultimate goal of systems library state. Okay. Going back to 2021, when you started working on this, where did that project start? How did you even begin to try to tackle this problem? Yeah. So we started initially actually trying to solve this from the side of Apache Flink.
11:54And as I mentioned, we were working with a bunch of users on analytical pipelines. And then this question came up, users building sort of transactionally meant driven pipelines on Flink and we really didn't find that a good match and, you know, very moderate success. There were a few that could make it work with like specific approaches, but not generally good experience. And then we started a subproject in Flink. It's kind of still around. It's called Stateful Functions. The idea was just like, let's do the thing that folks really like, which is just reliable communication, transactional state, and sort of encapsulate that into an individual piece, an individual function.
12:26Think of it as like a Lambda function, but when it's invoked, it has contextual state. It's invoked in the concept of a key, sort of attached to a key. And when it's invoked, it's sort of hydrated with the state of that key, can interact with that, modify that. It can basically produce a set of sort of RPC or messages that go out to other functions. And then this is all like transactionally committed, like the messages are sent to other functions, the state is committed. It's almost like a stateful, disaggregated, serverless actor system. I think of it like that. So that, in principle, raised a lot of interest.
12:55Like there were a lot of folks that did like that as an abstraction could see there's like, this is great for building anything from digital twins to, well, yeah, transactional state machines, which represent orders, even invoicing payments, and so on. Fox did actually build payment processors on that. We learned that only years later. Fox was quite crazy. There's just like one linchpin that this had. And this is, it was built on Flink as an analytical system. And Flink's really throughput optimized. It's like low latency for an analytical system, but that is mostly if you sort of use the at least once semantics in the things, meaning you sort of like you push events right when they come.
13:33If you want actually transactional results, you're introducing a huge latency, namely Flink is checkpoint based, and you have to wait until the next checkpoint happens. That's sort of the latency you introduce if you want to say, I don't want to take a second step before the first step is really durable. And that is in the seconds, right? And imagine using this as a foundation for workflow style logic. It means like every workflow step is sort of a, let's say 10 second latency. It was like completely impossible to do that. And it is also something that the EFLink architecture could never like fully remedy.
14:01So we thought if we really want to make that happen, if we want to make that vision happen of durable execution being something that's so low latency that you can use it without worrying about introducing latency overhead, even in sort of latency critical paths that are like synchronous interaction paths. So then we'd really have to build a new stack. We'd have to start from the bottom building on a low latency log, on a low latency architecture that emphasizes fast durability and not analytical throughput. And that's how we then got started with Restate. So what are the core building blocks of Restate?
14:32Both from a user perspective, like what am I sort of stitching together from the developer experience? And then what is sort of the architecture behind the scenes that's helping me essentially support that in a way that is going to shield me against these kind of like outages or other issues that you might run into in distributed systems? So yeah, there are very different levels from which to look at. Let's look at it first from the sort of infrastructure side. What does Reset actually sit in your infrastructure? You can think of it, it takes a similar place as a message queue or a message broker.
15:00It's kind of a, or a workflow orchestrator. It's kind of a marriage of, let's say, the Kafka-esque event-driven application and sort of the temporal-esque durable execution workflow world. So it sits where a broker would sit. You're writing your logic as service handlers. The abstraction is, we try to keep microservices really as the abstraction. So you're writing services like almost as if it would be like a Spring Boot application or Express.js application or so, so like handlers grouped into services. And then restate is the queue through which those services sort of get triggered, right? So if you want to actually trigger a handler, you put an event in that queue that's supposed to invoke the handler and then restate invokes that service.
15:39So in that sense, sort of classical queue in front of the service. The abstraction that we exposed, though, is not really that of an event, but it's more that restates or looks at the services and their handlers, re-exports them and sort of becomes a reverse proxy. So we're really trying to get away from people thinking in terms of like queues and events and trying to keep thinking in terms of like synchronous and asynchronous RPC. So that's really how you build it. Think of it. It sits in the infrastructure like a Kafka services, but it exposes itself as a reverse proxy that sits in front of the services.
16:11So is the main advantage in sort of comparing this to doing something like event-driven architecture with Kafka, like is the main advantage just having like sort of a level of distraction from having to think about events and queues and so forth as the person doing the implementation? If I'm doing the implementation, I can kind of just focus on the work that I need to do and that stuff sort of distracted away by restate. I guess that's one way to think about it. I think if we go in the details of what the programming model has, maybe we'll see this. But in general, you can think of it as it's like it's a level up from sort of Kafka style event-driven application.
16:46You're not thinking in terms of queues and events. You're thinking in terms of durable, stateful, resilient invocations or functions. Yeah. And that sounds like maybe an academic detail, but it actually is a word of a difference because that actually means that Restate takes on a lot more responsibilities. It doesn't just take on the responsibility of say, okay, I'll deliver the event and make sure the function is triggered. and it's, you know, it's redelivered, it's retriggered on a failure. It also understands, okay, how do I fence retries against, you know, earlier executions? How do I log contextual state, attach contextual state?
17:20How do I track progress if I have like multiple steps that happen as part of a function invocation? And I want to actually understand that I record the result of the previous step before I start the next one, just, you know, to give ourselves an easier life when it comes to implementing, you know, complex control flow that would be thrown up if it's on different results during different retries. All those things, if you implement them manually, you're typically not just looking at a queue at Kafka, you're typically looking at combining a queue with a locking service, with a database, with a scheduler, and so on.
17:48And so Restate wraps that all together and says, we're going from queue and event to doable stateful, resilient function executions. And then, as I mentioned before, the core sort of programming model is services that are meant to mimic RPC style service frameworks. And the sort of the simplest building block you have is really service handlers that get durable execution and then resets of layers, a few things on top of that. Like one concept is virtual objects that are stateful handlers that remember state across individual invocations, shard around keys, and then, you know, more like high level workflow constructs where you can actually add signal handlers and query handlers and so on.
18:29But all of that is sort of built on top of the general service abstraction. So if I'm implementing one of these handlers and it gets executed, what is sort of the life of that process behind the scenes? Let's assume you're implementing a payment processing handler or something like this, and that gets invoked. And let's say the logic that you have in there is, I first have to check the status. Like, was that already processed? Was it maybe canceled? Was it blocked before? So let's say the payment's identified by an ID. I might want to call a fraud detector. I might want to update a database, send them out a message, and so on.
19:02The lifecycle of executing this would be the following. Some external trigger, some external client says I want to execute that function. That enters Restate, the Restate server, the broker component, as an event. And Restate will understand, okay, where does that service live? You can think of it that the service has to be registered at Restate, the service endpoint. You know, where is that deployed? Is that like here, URL on Lambda? Is that an HTTP2 server endpoint? Is Kubernetes deployment and so on? You have to register that at the server and then the server connects and pushes the invocation.
19:33You've worked with, for example, like Amazon EventBridge or things like that. It's kind of a very similar model. So Reset will then look up, okay, that, you know, that handler is on that endpoint and I'm connecting to that. Let's assume it's an endpoint on Kubernetes or so. In this case, it would open a streaming connection, HTTP2, put the invocation and then hold on to the connection. and that is sort of the lifeline to that single invocation or execution attempt, which allows the service to stream back things like general progress, state update, outgoing messages. The function, let's say, or payment handler would also get when it's invoked.
20:07You know, if it's a stateful handler, a virtual object, ReState would attach all the contextual data it knows for that individual handler to the invocation so that the handler could directly look up things like, okay, what's the status that the previous status that was committed, like, okay, it's still new. So let's start and execute that payment. And then let's say we're calling things like the, let's say we'll call an external fraud detector API, we get the result, and we say, okay, this is actually a durable step. Then the handler would put the result of that step into that stream that goes back to restate.
20:37Restate internally has a consensus log that persists all the things it receives. And it has a bunch of sort of logic around this to understand, okay, is that information that still comes from, you know, like a valid execution attempt? Or does that come from an attempt that has been fenced off in the past? Does that, you know, it has like a sort of, yeah, it has sort of an elaborate consensus log that supports a conditional append of that operation to the journal. And it links that operation or that entry, that's the result of calling the fraud detector API onto the original event. And if we'd say, okay, there's a failure after that point now, that failure could be, you know, like just the connection is ruptured, the process goes away, or there's a timeout, then the reset server would understand, okay, that event hasn't been completed at the execution.
21:24I didn't actually get an acknowledgement back for that yet. And it would send the event to another process. It would retry sending it to that endpoint, and it would attach everything it has to that event. And that's the contextual state like last time. But now also it would attach things like the journal entries that it already collected, like here's the result from the previous step, wraps that all up and sends it there. Then let's that service basically say, as I'm going through the code again, I can skip over steps that I've already completed. This is what the SDK library basically does for you, like understands, okay, that's already found in the journal.
21:58We can ignore this. This is a new step. We actually add an action or an event for that in the journal. And then it goes on. That applies to pretty much any operation. Recording the result of an API call, updating state, sending out a message, all these things basically become events that are streamed to the reset server. And the research server understands how to process these events. They all get sort of attached to the original invocation, but sometimes they also represent more. Like they present an outgoing event that is then routed to another service, or they represent a state update, which is applied to an internal state index, and so on.
Read the full transcript
22:31So it's generally an extensible event-driven architecture on the server side that synchronizes over streaming protocol with the service. I install this SDK. I set up this client. I'm wrapping my call essentially around some of the SDK semantics or whatever. And that's going to call the restate server. Restate is going to do its magic to make sure that that call is able to essentially be facilitated in a way that it's reliable, durable, and so on. How do you make sure that the call from essentially the client to the server is done in such a way that it's reliable? So if you want to just the initial event, the initial call that triggers our durable handler, you have a bunch of ways to do this.
23:16You can do this through HTTP, through a client library, or you can actually just connect Kafka and it will just like pull these events from Kafka that represent these invocations. There's a few ingredients in there that help you, that make this reliable. Like number one, like the reset server will not acknowledge anything before it has persisted that in its internal consensus log. So even the original event has to go through the consensus log first before even an asynchronous submit or so is acknowledged. So we already have that durable. And the second thing is you can attach out of potency keys to the invocation.
23:49And then the sort of event processor inside restate server can use that to deduplicate invocation events. So that, you know, all the goodness of saying we deduplicate steps inside a durable handler doesn't really help you much if you can't deduplicate the invocation. So like the item potency key support is there to do that. And then if you integrate this with Kafka, it automatically does the sort of Kafka offset mapping to our impotency mechanisms and basically gives this end to end in exactly one's integration. So if I want to start using something like Restate and I have an existing project, do I have to kind of think about re-architecting everything to start with?
24:25Or can I do it sort of bit by bit based on where maybe my most critical workflows are, like a payment system, for example? Yeah. So we've really built it to avoid having to re-architect everything. And that kind of shows in many of the core abstractions. Like we do have to adjust the code to use the SDK to have access to some of the durable execution mechanisms. Like execute this code block as a durable step. Or access the built-in transactional state. Or let restate deliver that message to another service. Like you have to use the SDK, the library to do that. So there's some adjustment in the code.
25:01But the way you're deploying this, the way you're generally packaging this is meant to be very much in line with what you're doing anyways. Hence this sort of idea to abstract it or to give it the shape of microservice, service handlers, the way you deploy it. From the outside, you can very often just say, okay, this was a non-restate service. You know, I'm importing the reset SDK. I'm starting using these restate actions inside my code. connecting this to the reset server, which becomes the reverse proxy. And now the services that initially used to call the service directly, they call the reset server, which becomes the reverse proxy for the service.
25:42It's really meant to sort of allow you to plug it in incrementally, to sort of look at it one service at a time. There are a few things that really become very powerful only once you start attaching a few more services, like between services that are attached to the same reset server, you get kind of end-to-end exactly once RPC messaging, which is pretty nice. But even in the absence of that, you're still getting a lot of goodies. So yeah, it's totally meant for incremental adoption. For someone like adopting this or for teams that are adopting this approach, like does it take some work for them in terms of their thought process and the way they've traditionally developed to kind of come around to this mode of like operating and calling services?
26:24Yeah, I think it does a bit. And I would say mostly it almost requires unlearning a few things that they have learned in the past. So if you're coming from a traditional workflow system, we often have folks asking, okay, I'm writing this, but like, where's, you know, how do I make something a persistent activity now? Or yeah, just looking for the concept of like a workflow and an activity. And then the interesting thing is like in Restate, every durable step is like an activity, or if you want to separate it out, then make it a separate service that you call. and you don't really need workflows as a special construct anymore.
26:59It's sort of, you get similar guarantees just from your regular sort of service abstraction. Even the same observability and telemetry, you just get out of that. So you have to kind of maybe take back a step from looking for exactly the concepts you might know and just understand that a lot of the reasons why you were using those concepts, the guarantees you were really looking for, they're sort of like everywhere now in almost all the code you write with restate. So you don't have to go to like these special constructs anymore. The second thing is understanding that many of the operations you do are now durable across failures and crashes.
27:35For example, if I'm doing something like an RPC call, a sequential RPC call request response to another system, and the caller actually fails and gets recovered into a different node, that's not something that you usually assume still works, right? Because, you know, like the network call might be lost or like even if something gets sent back, The code that actually issued the call is now waiting for the response was recovered in a completely different process. But it still works in case of reset because all the building blocks are actually durable, persistent distributed building blocks. The RPC is basically connected to a persistent future that gets recovered in a different process and completed there.
28:10So the entire code that made the call gets recovered, restored to the point where it made the call, and then completed with the result of that call. And it just like works, even if it moves around. So this is something that a lot of people don't expect to work. And that's why they're trying to code ways around that. And then they come into the Discord and say, like, okay, I'm not really connecting the dots here. And you basically tell them not just like delete that. It just works. That's an interesting experience. Are there certain kinds of projects that this makes more sense for than others? Like, at what stage it makes sense to go with an approach like this versus, you know, something alternatively?
28:46I think there's a few cases where it does not make sense. And then there are a few cases where probably lots of durable execution systems could make sense. And then there are some cases where I would say that's a really good reset use case in particular. I mean, in general, durable execution makes sense for workloads that orchestrate many steps that update stuff. Like if you have mostly, you know, read heavy workloads or read only workloads, it's like doesn't really make sense to plug in a system like this. you know then there then there are workflows that with something like durable execution is a nice convenient piece because it helps you you know encapsulate restart retries you don't have to do them yourself it helps you to to implement asynchronous primitives a bit easier and you know but if anything goes wrong and some state gets lost and everything gets retried and recomputed there's really no big deal like a lot of let's let's say let's say a rack pipeline or So retrieval augmented generation, I'd like, you know, if you lose something, you recomputed worst cases, you call your LLM a few more times, and that's like half a cent to your bill.
29:46Maybe that's not a big deal. And then there's cases that where that actually really matters, where you absolutely care about transactional correctness, where you say, okay, like, no matter what kind of funky failure happened, I can never go back before a previous step. Or cases where you do explicitly need transactional state that outlifts individual workflows that you can rely on that other services can integrate with them. This is a very good restate use case because we've kind of architected it with that level of resilience in mind. Restate is implementing really its own stack. It isn't built on a database.
30:17It implements its own consensus log. It's an unprocessed on top of that. It's a complete self-contained single binary. You just deploy it and run. And it has internally an extremely well thought through consensus architecture that allows you to make very strong assumptions on your semantics. And I think payment processing is a good example. like if you want that, there's a good use case for restate. I would say specifically also when you want something that works both in the cloud, but has also, I guess, a credible story for self-hosting, then the converged single binary architecture is actually feasible to self-host.
30:50It's not just like theoretically you can, it's open source and you can host it, but it's actually fun to operate. You mentioned like RAG pipeline there, maybe not being the ideal use case because if it fails, you can run it again or something like that. It's a use case, but it's a good use case even. It's very convenient to do that on top of ReState. It's just not a use case where you would rely on strong transactional correctness. Right. That's, I guess. But what about a user-facing application that leverages a foundation model of some sort there? Especially if I'm doing something where I'm making multiple inference calls or some sort of agentic workflow, I would think it would make a ton of sense there because you could be calling the tools, to various data systems, multiple models, and so forth.
31:35Is that a use case that you're seeing? Yeah, I think that's actually a very interesting one. As soon as you come more into the AI agent space, I think it becomes a lot more interesting for a couple of reasons. Number one, I think agents are a good match for durable execution in general because they are a bit like dynamic workflows. Workflows with a control flow is not known upfront. It's determined by the responses of the LLM and durable execution. has this flexibility that you don't need to define the sequence of steps and the control flow up once. You can kind of create dynamic control flow, just like record it and replay it after a failure.
32:11So I think durable execution in general matches agents very well. And then the second thing is agents are usually contextually stateful. So they map really well to these like virtual objects kind of concept that we have in restate where you have this exclusively scoped state that you have access to that you can use to remember basically not just previous steps, but also previous context. But it's still not something that is just like, it's hidden in the workflow, but it's still an open state that you can probe from other services. Yeah, that you can even interact and put additional context in from other services if that comes up.
32:48The whole abstraction just matches really nicely. What are some of the unexpected use cases that you've seen of people applying Restate? Yeah, so there's some very expected use cases like, you know, classical workflow sagas, distributed state machines, the unexpected ones, it seems there are lots of folks that have fairly complicated sort of distributed queuing setups where they're starting with something like Kafka, and then they're also pulling in a RabbitMQ and they have some, I don't know, some routers and some actors in between. I think often this is kind of a workaround to build something like you have maybe a common log and then you fan this out into like more fine grid entities that you interact with.
33:29And we have a bunch of users that basically could replace a whole zoo of sort of distributed queue orchestration, just like with a single restate service. That's something we hadn't quite expected to happen so often. The second one that I found fascinating is that we've seen folks do in fact build a lot of custom workflow engines and custom rule engines. Apparently, that's a thing. Many companies build for internal processes, internal tools, and so on. So that's a quite common use case that we've seen. My favorite one is actually folks building a custom workflow and rule engine that they ship into factories to evaluate sensor data and trigger actions that controls machines.
34:08That was not on my list for one of the early use cases. So that was quite fun to see. What would you say is the biggest challenge that you face when designing and implementing Restate? I mean, there's technical challenges, right? The mission is extremely ambitious to say we're building a full stack that starts on the bottom with a consensus log that has low latency, but also you can deploy it in extremely complicated setups across availability zones, across regions. It tries to make good use of modern cloud architecture, like object stores, but at the same time, it bridged the gap to low latency.
34:43That's a technical challenge that we've worked quite some time, actually up to over two years by now, on making this happen. I would say beyond that, the biggest challenge really is, I'd say, education of the space. Durable execution is becoming more and more known, but it still is not necessarily a mainstream concept. A lot of folks still associate it also primarily with workflows. So if you're doing like durable execution for workflows, maybe you get more and more folks that like, not okay, yeah, I know that. But if you're trying to say, okay, no, we're actually sort of talking about durable execution in a more general way.
35:20It also includes state communication. Like think of it as a microservice paradigm, not a workflow paradigm. That's like, okay, well, I need to think about that a bit. Like I think this education is something that is a big challenge, but also I would look at it positively. It's also something that is making progress. Most folks, after they've gone through the initial, okay, I hadn't expected that. Let me think through it a bit. Once they actually crack it, they usually get quite excited about it. So they start help spreading the word. So that's good. Yeah, I mean, I think that part and partial with any sort of new category creation, like if this is not the way that people are used to doing things, then it's hard for people to even know that they have a problem and there's maybe a better way of doing something.
36:02so they're not necessarily actively searching for it until you sort of cross the barrier of this, you know, like educational awareness, essentially. Definitely. I'm not sure if I would go as far as to say, like, this is a brand new category that we're creating. Like, durable execution as a category existed before we started. I think the new, we're bringing a bit of a new twist into it. Definitely, like, you know, treating it as more than a workflow paradigm is probably something new. And then adding this, like, low latency capabilities that actually allow you to use it in places where you might previously not have thought it being applicable is maybe something new as well that people need to wrap their heads around.
36:40But yeah, we're also sort of working with other folks that have worked on creating this durable execution category are basically like leveraging their work for sure. What do you think overall, like the impact will be to how we design distributed systems in the future if more and more people adopt this approach of durable execution? I would venture a guess and say we're going to, this type of solutions are going to be very, very widely adopted in a couple of years. I think they're going to replace a lot of workflow, queuing, and other sort of distributed orchestration systems that are out there.
37:23Just because they're a nicer, like more approachable way of solving these problems. and yeah, they just interact better with the rest of your application stack. And they can actually do things like, they can actually support use cases that you might not have been thinking of before. And vice versa, not using these systems, as we said before, it's just like it's getting harder and harder. This is one of the drivers. I would actually throw in a second element why I think this is going to be extremely widely adopted in the future. And that is, if you look at the whole AI trends and AI cogeneration, you can actually see that these systems are getting increasingly good.
37:58at doing things like even complicated business logic, where assuming you have all the domain context, you really need a bunch of steps, a bunch of non-trivial steps to happen. But those systems are not the ones that solve distributed race conditions for you or understand, okay, hey, here is a case where if that process stalls just here and then a retry happens and forks off a copy here, and then those are going to interfere in a weird manner. I don't see that happening. even if you think they can conceptually do that, that's probably a waste of compute power. I think if you just use a foundation like verbal execution and say like, it's just an incredibly good target for our foundation for AI-generated code because it's solid semantics.
38:41A lot of the problems that you really don't want anything unexplainable, semi-unpredictable to be reasoning about and then put the much simpler generated business logic on top of that, it's a nice package. Yeah, that'd be great. So what's next for Restate? So at the moment, we're working very hard on releasing the next version, which is our first distributed release. I guess by the time this comes out, it's probably going to be released already. So we're targeting like two to three weeks from now. The moment if you use Restate, you can think of it as it deploys like a single node database, like a Postgres, you give it a persistent volume and good.
39:20The next version gives you the complete distributed deployment power, distributed replication, scale out and everything. So that's actually a big thing that we've seen a lot of excitement building up for and we're pretty anxious to get it out there. That's the biggest immediate step. And then after that, we're at the moment at the phase where we're really just excited to be working with as many users as possible, learn from them what they're using it for, what they see as good use cases, how they think about the problem, how would they explain it to others? How would they explain this category?
39:53How would they explain the abstraction and the mental model you'd have to have? And really, you know, share this with the world and work with whoever is excited to work with us. Awesome. Well, Stefan, thanks so much for being here. thank you for having me cheers
From the publisher
A major challenge with creating distributed applications is achieving resilience, reliability, and fault tolerance. It can take considerable engineering time to address non-functional concerns like retries, state synchronization, and distributed coordination. Event-driven models aim to simplify these issues, but often introduce new difficulties in debugging and operations. Stephan Ewen is the Founder at Restate which
The post Modern Distributed Applications with Stephan Ewen appeared first on Software Engineering Daily.
