🎙 Develpreneur Podcast Episode

Audio + transcript

Building Better Developers, Episode 543

In this episode, we continue our exploration of software architecture patterns and anti-patterns. We focus on the space-based pattern, which is theoretically infinitely scalable. We discuss the role of virtual machines, middleware, deployment managers, messaging grids, and data grids in this pattern.

2022-02-05 •Space-based pattern in software architecture •Podcast

Summary

In this episode, we continue our exploration of software architecture patterns and anti-patterns. We focus on the space-based pattern, which is theoretically infinitely scalable. We discuss the role of virtual machines, middleware, deployment managers, messaging grids, and data grids in this pattern.

Detailed Notes

The space-based pattern is a complex architecture pattern that uses virtual machines and middleware to route requests to the correct processing unit. It is driven by the need for scalability and high availability. The middleware is a virtualized grid that routes requests to the correct processing unit, while the deployment manager is responsible for bringing up and shutting down virtual machines. The messaging grid is used for communication between components, while the data grid is used for storing and retrieving data. This pattern is theoretically infinitely scalable, but it can be challenging to implement and requires careful planning and execution.

Highlights

  • The space-based pattern is theoretically infinitely scalable.
  • It is driven by virtual machines, which are self-contained processing units.
  • The middleware is a virtualized grid that routes requests to the correct processing unit.
  • The deployment manager is the brains of the distributed solution, responsible for bringing up and shutting down virtual machines.
  • The messaging grid is used for communication between components, while the data grid is used for storing and retrieving data.

Key Takeaways

  • The space-based pattern is a scalable architecture pattern that uses virtual machines and middleware to route requests to the correct processing unit.
  • The middleware is a virtualized grid that routes requests to the correct processing unit.
  • The deployment manager is responsible for bringing up and shutting down virtual machines.
  • The messaging grid is used for communication between components.
  • The data grid is used for storing and retrieving data.

Practical Lessons

  • When implementing the space-based pattern, it's essential to carefully plan and execute the architecture to ensure scalability and high availability.
  • Use virtual machines and middleware to route requests to the correct processing unit.
  • Deploy the middleware as a virtualized grid to ensure scalability and high availability.
  • Use the deployment manager to bring up and shut down virtual machines as needed.
  • Use the messaging grid for communication between components.

Strong Lines

  • The space-based pattern is theoretically infinitely scalable.
  • It's a powerful architecture pattern that can be challenging to implement.
  • The middleware is a virtualized grid that routes requests to the correct processing unit.
  • The deployment manager is the brains of the distributed solution.
  • The messaging grid is used for communication between components.

Blog Post Angles

  • The benefits and drawbacks of the space-based pattern.
  • How to implement the space-based pattern in a real-world scenario.
  • The role of virtual machines and middleware in the space-based pattern.
  • The importance of careful planning and execution in implementing the space-based pattern.
  • The trade-offs between scalability and complexity in the space-based pattern.

Keywords

  • software architecture
  • space-based pattern
  • virtual machines
  • middleware
  • deployment manager
  • messaging grid
  • data grid
Transcript Text
Welcome to Building Better Developers, the Developer podcast, where we work on getting better step by step professionally and personally. Let's get started. Well, hello and welcome back. We're continuing our season where we're looking at software architecture patterns and anti-patterns. At this first half, we're focusing on patterns and we're going to wrap up our look at patterns today with the space based pattern, also sometimes known as the cloud pattern. This is a very popular pattern in modern big solutions because it is theoretically infinitely scalable. It is a thing where a solution where you can just keep adding on components as you need to support more users, processing data, whatever. It is driven as most things in the cloud world seem to be by essentially virtual machines. In the pattern, we're going to refer to them as processing units. You have these processing units that are self-contained. Essentially, they have processor, they have CPU, memory, some sort of data storage or connection to data. It's all you need. It's a legacy sense. It is a desktop or a machine. In our world, in the cloud world, it's a virtual machine. And then the other part of the pattern is the middleware. It's a virtualized middleware. Again, the virtual piece being that we can spin up within each of these components, we can spin up multiple machines that take care of that piece of it so that we don't have a single point of failure. And then also when we need more power, whatever that happens to be, we can add that through more machines. We can bring up another virtual machine. The first part is the processor, the processing unit. This is where the work gets done. If you think of a web application, you have typically some sort of like a router or something like that that you come into. Then you have these web servers. And then maybe behind that, you have application servers. Depending on how it's set up, at some point you get to a point where we've passed through the layers of the request and we're now working on or doing the work. We have the task or series of tasks that we're supposed to be doing or that we've requested. This is where the work gets done. That is the processing unit. Now in other patterns, we've seen where that processing unit may itself be distributed out into various ways. You may have a multiple, for example, services, like in a microservices architecture, you may have multiple services, where each of them have their own little memory space and life and things like that. Technically you can do that with a processing unit, but we think of this pattern usually as the processing unit being a little more self-contained. So that I could send a request to a processing unit. It can do everything. It doesn't have to go reach out to a bunch of different places. It's sort of its own self-contained component that can do the needed work to provide whatever answers are needed for the requests. Now the key behind these processing units is basically how do I get a request to the right place, track it down, how do I make sure that all of the processing units are in sync? This is where the virtualized middleware comes in place, comes in play. Now within that, there are little components, which themselves could be virtualized and thus have multiple machines or sets of resources doing that required work. Within this we have, and we're going to refer to most of them as grids because it's essentially what they are. A bunch of services in a technical network grid kind of setup where we have request command and then whatever has bandwidth does it, sends a request back. We do this for messaging. We do this for data. We do this for processing. And then we have a deployment manager. Deployment manager is typically not going to be a grid. I will sort of, I guess, jump to the end of that list. Because the deployment manager is the brains of the distributed part of this solution. The deployment manager is what brings up and shuts down different virtual machines. So you've got all these processing units. Well if one doesn't need to be up or if one is erroring out, failing to respond properly, needs to be restarted, or if we've got too many requests and not enough resources to handle those requests, the deployment manager is the piece that says we can shut stuff down, we can restart stuff, we can start more resources, we can adjust essentially the pool sizes as needed to make sure that things keep running and that it scales appropriately. So that's the deployment manager. That is really a piece of smarts. You can have that distributed as well, but generally speaking it's going to be just one thing because really all it's doing is sort of checking statuses of stuff, sort of doing heartbeat checks, and then making adjustments accordingly. The other three pieces within the middleware, the messaging, the data, and the processing, here we are taking traditional layers and splitting them up. Now messaging is a little different because we typically don't think about messaging as much. It occurs, but it occurs with inside a system and we don't really, we sort of get it for free. So if we have a standalone application and we have calls going to functions or methods or whatever they happen to be, there is messaging going on. There is, for example, you click on a button, when that happens a message is sent to maybe a certain block of code and then with that code maybe it translates what's sent and says oh, I've got to send messages to these other things, which are essentially, you think of messages in this case as calls, function calls, method calls, things of that nature. Now we've got to do that in any situation, but now we specifically have this messaging grid in this solution because when we go to the space base pattern we're spreading all this stuff out. We have all of these objects that are somewhat interrelated and they're going to have to be talking to each other in some way. You've got all these, especially conversations going on. So you need this messaging component to be able to properly route that stuff. And it is a grid because really you don't have to, if you think of a message manager, it really only needs to know about one conversation at a time. It could be handling dozens and dozens at a time, but really for a proper flow it just needs to know about one because if I'm a go-between I just need to know what message am I carrying to who and what response am I giving back. And that could be me going back and forth between dozens of people or it could be dozens of people going back and forth for these dozens of conversations. And that's where that grid part comes to is that we basically can just start throwing conversations into the grid and then available resources will say, okay, I'm available. I'm going to take this on. And that means that we could have our message controllers within that grid only deal with one conversation at a time or tens or thousands or millions of conversations at a time. And then as it gets overloaded, overwhelmed, we spawn another one. So that's the message. That's the communication side, which can be, when you think about it, you've got all of these players in the solution. There's a lot of conversations that can go on. So that becomes a big piece and one that we want to ensure scales along with everything else. The data grid is very challenging because what we want to do is be able to have multiple places that the data can be retrieved and updated, but it needs to be the same across all of those places. So normally we would have a database or a data store of some sort that we're going to talk to. We're going to send some information to it. We're going to get information back. And all of the players, all of the requesters go to the same database. So if caller A goes in and makes a change, when caller B goes and gets the latest data, they automatically get it because they're going to the same place that A just changed it. It's a little tricky when we go to a data grid because now we want to have multiple instances of that database or data store, whatever it is, and they need to be kept in sync. So if I make a change to data store one, but somebody else comes in and hits data store two for that data, they need to see my change. And so we have lots of issues that now can come up that deal with guaranteed delivery and the rollbacks and state. Because if I'm in the middle of an update, should that data that has been partially updated, be available to others or not? It's part of our logic, part of our rules. Maybe not. Maybe we have to do everything as a single transaction, which typically what happens. And then when the transaction is complete, then that is what triggers the synchronization across all of the other, however many other virtual machines for the data grid there are. If it's two, it's a little easier. But if once you go to three, four, five, then you have this waterfall, this sort of cascade of updates that potentially are needed. And of course you can be updating two things at the same time. And then you have to deal with things like race conditions, where what happens if this guy gets updated before that guy, but then that guy didn't get his update in time and things like that. You could also have conflicting stuff where two basically two transactions effectively go in at the same time, but they aren't the same. So you have issues like that you may have to work around, including maybe you use a locking mechanism, something of that nature. So this can get very complicated. The processing grid is where we do the work for the computation part of our response. This may feel very much like a microservices solution. It may actually be a microservice solution, because if you think about it, the processing side should not be coupled to memory data and things like that. It should be using the data grid for its data. So it should be, the processing things should be essentially pretty thin. They should really just be code and should have inputs and outputs or results. So that one should be fairly easy to replicate because you're just replicating source or compiled code, however you look at it. However, you do have issues with what happens if we do an update. get basically how does that get translated throughout the grid? And how do we ensure that if I've got 100 items in the grid for the processing piece, when I update item number one, how do I ensure that somebody trying to connect to item 100 get the latest as opposed to the prior version? Or even do I care? There's things like that. And again, you deal with things like locks and you may have a temporary pause or something like that. Or you may have to do some sort of a flush type mechanism where basically you push all the updates, but they don't actually go live until you restart each of the services. So you basically have what's sometimes referred to as a ripple start where you start bringing stuff down and then bringing it back up. And so as it comes up, it comes up in the new version. And once you've got one up in the new version, that becomes sort of the new pool. You can expire the old pool and then you start bringing everything up to fill out the new pool with the newest, the latest version so that people can be properly served with it. If you feel like this is one of the more complicated patterns we've talked about, I would agree with you. There is a lot to think about when you talk about an application that you are trying to scale this way. This is a lateral scaling kind of thing. This is saying we don't need to do anything but just spin up another machine and hook it up appropriately. And then we've built another resource into whichever grid it is that we happen to be working from. It's very powerful, but you really need to be intentional about how you think about the ways that things could go wrong. With each of those grids, what happens during updates and outages and how do you make sure that no matter which element within the grid gets hit, it is the same as every other element as far as maybe the same data, the same state, the same whatever so that there is no distinguishing between those. Because that's key, is it should essentially feel like a couple of single components as opposed to this grid behind it. That's the challenge is making that grid work in a way that it is just a highly available, highly scalable component. There is overhead, obviously, with all of that. So when you look at downsides, that would be a downside. If you've got a smallish application, maybe even a medium, mid-level type application, it may be that you don't want to do this fully blown space-based pattern because it's just too much. You're over-architecting for situations you're not going to get enough. Also, if there's certain components that are just not used as much or is not a critical part of the application, for example, maybe you've got a database but it has almost no information. It's just holding user login information. Something like that, you may not want to go do a big distributed solution to it because going to get enough traffic or usage to make that scalability needed. It may be that just one of those things is all you need. The deployment manager is a good example. You probably only need one deployment manager, not to mention the whole headaches around having multiple deployment managers. So maybe you just have one. Similarly, maybe you don't need all of these database things. You just need one. You're not going to be hitting stuff that often. Maybe you're just doing reads or you're doing updates or something. It's easy to do that, get it done, and it's not going to lock other users. You can have literally thousands and thousands, tens of thousands, hundreds of thousands, millions of users hitting this thing. It's able to handle that. Again, we're talking about large number of users and scalability. If you're only ever going to have 10 or 100 users, you probably aren't going to need to worry about this. There are other ways that you can scale that may be more effective than doing it within the architecture. So this is going to wrap up this pattern and also going to sort of change our focus as we move forward. We'll start diving into some anti-patterns and that will come next episode. But until then, go out there, have yourself a great day, a great week, and we will talk to you next time. Thank you for listening to Building Better Developers, the Develop-a-Nor Podcast. You can subscribe on Apple Podcasts, Stitcher, Amazon, anywhere that you can find podcasts. We are there. And remember, just a little bit of effort every day ends up adding into great momentum and great success. There are two things I want to mention to help you get a little further along in your embracing of the content of Develop-a-Nor. One is the book, The Source Code of Happiness. You can find links to it on our page out on the Develop-a-Nor site. You can also find it on Amazon, search for Rob Brodhead or Source Code of Happiness. You can get it on Kindle. If you're an Amazon Prime member, you can read it free. A lot of good information there. That'll be a lot easier than trying to dig through all of our past blog posts. The other thing is our mastermind slash mentor group. We meet roughly every other week, and this is an opportunity to meet with some other people from a lot of different areas of IT. We have a presentation every time. We talk about some cool tools and features and things that we've come across, things that we've learned, things that you can use to advance your career today. Just shoot us an email at info at Develop-a-Nor dot com if you would like more information. Now go out there and have yourself a great one.