|
# Embracing Microservices with Django
|
|
# Embracing Microservices with Django
|
|
|
|
|
|
|
|
Welcome! You are on the verge of embarking on an adventure of discovery and understanding with this book, I hope you enjoy reading it as much as I enjoyed writing it!
|
|
|
|
|
|
|
|
On this journey, you will learn all you need to know to build your own micro-services-based application with Django. But before we get started we need to get a few definitions out of the way! This is what this chapter will be about...
|
|
|
|
|
|
## Micro-services Vs monoliths
|
|
## Micro-services Vs monoliths
|
|
|
|
|
|
|
|
First off, what is a micro-service and how is it different from more traditional architectures? For most of computing history, programs have been entities running on a single computer; either yours or another, remote computer. Think about Adobe Photoshop as one example of a program running on your own computer. Think about these old mainframe programs, rendered on green monochrome screens as programs running on another computer; but server-side rendered websites are another type of code that runs mostly on another computer (the web server), your own computer or mobile device just being there to render whatever the server has built.
|
|
|
|
|
|
|
|
In the very beginning, those programs were held on a stack of punch-cards, computers usually only able to run a single program at a time.
|
|
|
|
|
|
|
|
The next evolution after punch cards were files, we still mostly use file to store code, but in the beginning programs were stored in single files without the ability to reference any other file, everything program was its single entity only capable of using the, often limited, standard library of the language they were programmed in. Think of the .bas files on a Commodore 64 for example.
|
|
|
|
|
|
|
|
![Margaret Hamilton standing next to the navigation software that she and her MIT team produced for the Apollo Project](./imgs/ch1/Margaret_Hamilton_-_restoration.jpg) (image courtesy of [wikimedia](https://commons.wikimedia.org/wiki/File:Margaret_Hamilton_-_restoration.jpg))
|
|
|
|
|
|
|
|
You can see here a picture of Margaret Hamilton standing next the code she and her team wrote to send the Apollo mission to space. Seeing that stack of paper, the term monolith probably starts to make sense.
|
|
|
|
|
|
|
|
The next evolution of software engineering was to be able to reference other code files, modules or libraries from the main file, allowing you to split your code, try to use the separation of concerns principle and group code in different files, each file dedicated to a specific concern. We still use this principle in Python today. Whenever we write an `import` statement to make some code available, whether that code was written by us or by someone else, whether is only being used for this one program or if it was intended to be re-usable.
|
|
|
|
|
|
|
|
Jump forward a few years and re-usable code has now become a thing. One of the techniques that made re-usability a success is, in my opinion, Object-Oriented-Programming (or OOP for short). A technique at which Python was one of the first languages to excel at. Having to write class definitions encouraging developers to then use them more than ones, having them think about inheritance and grouping common features in parent classes.
|
|
|
|
|
|
|
|
But, at this point, programs still exist as a single unit, each of them spread among multiple files, using several libraries but still running as a single unit, designed to accomplish one main goal, every task required to accomplish this goal being performed by that single program or project unit. This is what we reference as a **monolith**.
|
|
|
|
|
|
|
|
The next evolution of software development was to make these libraries and modules that had a specific purpose or concern into services of their own. Those services made accessible to the main program by different means. XML-RPC and COM might come to mind when you think of those early services.
|
|
|
|
|
|
|
|
The final evolution as far as we are concerned, made easier by the rise of the cloud, was to make these service smaller and smaller so that they would not be responsible of a whole concern but rather one or only a few tasks. This architecture is what we call **micro-services**.
|
|
|
|
|
|
## Different types of micro-services
|
|
## Different types of micro-services
|
|
|
|
|
|
|
|
Now that we are clear on the concept of micro-service, let's have a look of different types of implementation people commonly refer to as micro-service.
|
|
|
|
|
|
|
|
One of the simplistic type of micro-service around is probably Amazon's single-function Lambdas. Those are very isolated pieces of code performing one single task, they are often used to perform compute-heavy tasks as they are also on-demand, giving the user access to a lot of processing power but only having to pay for the actual CPU time they have been using over time. It is very cost-effective for tasks that do not have to run often but that, when they do, need a lot of CPU time.
|
|
|
|
This architecture can be very scalable as several instances running the same Lambda can be spun up at the same time if needed, therefore easily handling peaks in traffic and having it all managed by the top-level infrastructure; in this case, Amazon but most cloud providers are now either providing their own version of this or looking into it.
|
|
|
|
|
|
|
|
Lambda's are not as well suited for thing like low-to-medium traffic services that require an "initialization time", ie: reading a configuration file or connecting to other services as, after being unused for a given amount of time, they will be spun down (shut off) meaning that the next time a request is mad to that function it will have to be "cold booted" again, performing all those initialization tasks ones more. This is a significant overhead, both in time and money.
|
|
|
|
|
|
|
|
|
|
|
|
On the other end of the spectrum, we have services deployed as distinct hosts on one or more bare-metal server(s). Each service having its own separate host and host configuration, it is not hard to move them to a different bare-metal service in case they become too CPU- or IO-intensive. This is probably the easiest way one can get from deploying regular monolith web applications to deploying micro-services.
|
|
|
|
This, although possible makes scaling non-trivial bringing the need to manage things like internal DNS, load-balancing and other somewhat more complicated issues depending on how comfortable you are with server configuration and management.
|
|
|
|
|
|
|
|
|
|
|
|
In between those two extremes, there is managed container-based deployments using tools like Docker and Kubernetes (or K8s for short), this has the advantage of each container being pre-configured to handle a specific task (like serving as a database host or performing complex computations) with all the required dependencies, making it easy to deploy it to any machine or service that is compatible with the chosen container type.
|
|
|
|
The top-level system will also take care of concerns mentioned above like load-balancing and DNS management, making it easier to deploy and manage each service.
|
|
|
|
|
|
## Benefits of using micro-services
|
|
## Benefits of using micro-services
|
|
|
|
|
|
|
|
As mentioned earlier, micro-services being an evolution of the use of libraries and modules for the purpose of separation of concerns, they should each have a very limited scope. Of course, this is something people working with monolith and modules often try to achieve as well; but when all your code resides in the same place, it is rather easy to get side-tracked and inter-reference modules with each other, turning the code in a spaghetti-bowl-like structure where it gets harder and harder to make the difference between one module and the other, wondering if a function should be added here or there, having to open a multitude of files to find out that the piece of code you were looking for was finally in the first file you open.
|
|
|
|
|
|
|
|
In short, **micro-services makes separating concerns and architecturing your code easier.**
|
|
|
|
|
|
|
|
Since **micro-services** address a limited scope they **are** often **easier to test**.
|
|
|
|
|
|
|
|
Having each service now running completely independently also makes deploying a certain piece of code that is more CPU-heavy or IO-intensive on a separate node (or server). You can even mic and match, putting a CPU-heavy service with an IO-intensive one in order to try to make the most of that node.
|
|
|
|
|
|
|
|
**Micro-services are more flexible when it comes to hardware**
|
|
|
|
|
|
|
|
Running completely separated from each other, different microservices may use different versions of the same library with one service for example taking advantage of that brand new feature that was just introduced while another service depending heavily on security is sticking to the LTS version of that same library. Be careful though, this is a double-edged sword!
|
|
|
|
|
|
|
|
**Micro-services are more flexible when it comes to library usage**
|
|
|
|
|
|
## Batteries included Vs minimalist framework
|
|
## Batteries included Vs minimalist framework
|
|
|
|
|
|
## Is Django really too bloated?
|
|
## Is Django really too bloated?
|
|
|
|
|
|
## Storing extra batteries safely (configuring Django for micro-services) |
|
## Storing extra batteries safely (configuring Django for micro-services) |
|
\ No newline at end of file |
|
|