(This is an abstract from the book Scalability Patterns authored by CEO of Cazton, Chander Dhall. The book can be purchased both in paperback as well as eBook formats from Amazon.com)
Transitioning from monolith apps to services was a logical progression. In order to have services or APIs that could communicate with external as well as internal systems, it made sense to take a particular component of the system and convert it into services. For example, in an eCommerce website it makes sense to take the payments functionality and create a completely different service that only has one responsibility which is taking care of payments. Similarly, we can create the following services; pricing, customer, product, inventory etc.
As we can see this allows us to have more flexibility it having the services contract with other components within and outside our system. This also helps in scaling development and testing efforts. In large corporations, some of the services could be the responsibility of different teams. This has the potential to scale as well. However, if we do not scale the System of record, this architecture would not scale beyond the point.
In the recent years, microservices architecture has become very popular. Quite interestingly, the SOA was implemented quite differently across the industry. Microservices architecture is the natural progression from SOA towards a more well-defined architecture that is meant for scale and is lightweight. Traditional monolithic apps were hard to scale. At the same time deployment could be a nightmare depending on the size of the system. I have personally worked on monolithic systems that took days of preparation for the deployment teams and would take hours for successful deployment. Quite unfortunately, this would mean deploying new features in a product every few weeks a very huge cost. Sometimes, this would mean being able to deploy only 3 to 4 times a year. With the microservices architecture the same system could be deployed faster and partial updates to the system could happen even few times a day.
To be fair to SOA, it wasn’t that the architecture was insufficient, it was really the way it was implemented that’s some monolithic projects became such. For the most part, the industry had to learn from experiences from implementing monolithic projects before progressing to a more elegant architecture. The reason I call microservices the natural progression to SOA is because is almost like SOA done right. However, with the standardization of the microservices architecture across the industry, the DevOps (Development and Operations) tooling has become so much better in the last few years. DevOps to practice that aims to unify the software development and operations in order to achieve automation and monitoring at all steps of software construction. This would include testing, integration and deployment with infrastructure as code. The direct benefits of DevOPS include shorter development cycles, increase in deployment frequency, partial releases of the system and a more controlled and dependable deployment cycle.
In the last decade, we have witnessed our growth of internet-enabled devices all across the world. Be it cell phones, tablets, desktops, IOT enabled devices the amount up activity on the web has skyrocketed. This means every business that has the potential to grow quickly, needs to be able to scale according to the usage patterns no matter how unpredictable they are. Let’s take an example of an on-demand online library that has videos and pictures. In a monolithic architecture, it might be very normal to assume that all the videos and pictures would be served from the same service. Let’s call the service media service. After some time with the increase in number of users, we should be able to add multiple instances of the same service in different servers. As you can see that even if we grow the business drastically we able to scale the service using a simple SOA architecture for services.
Figure 4-3. Scaling the Media service that has video, picture and thumbnail functionality.
Next, the business has grown and we are asked to display thumbnails on all the videos. That will mean changing the media service to add certain functionality for the thumbnails. This means that even though the video and picture functionality was working correctly, we will still need to re-deploy the media service to add the new functionality. Let’s assume that we have really long videos. That could mean that scaling the video portion is as easy as creating copies of videos close to the users. However, imagine the number of thumbnails needed for videos that are about an hour long. Quite interestingly, depending on the operating system, if the thumbnail size grows beyond a certain number it might mean crossing the limit of files allowed in a folder. Scaling the thumbnail is a completely different problem then scaling the video.
What about the situation where certain videos are extremely popular? In that case, we might need to look into moving such videos on faster hard drives. We might need to cache some of these videos as close to the user as possible. In the current case we have no other option but to deploy the media service as it is everywhere. What if we wrote the Media service in a language or framework that gets discontinued or wasn’t async-first. The only way to take advantage of a better, faster, async-first language would mean rewriting the whole service in a different language. These are just some problems with this architecture. To summarize, it’s not just a cost problem. It’s a scalability issue. It’s a deployment problem. It’s a management problem. It’s a resource allocation problem.
In the microservices model, we develop software applications that have independently deployable and modular services that serve a business goal. If, we work to solve the same problem using microservices, we would have created two different services to begin with: the Video service and the Photo service. Let’s assume, that the Video service is written in .NET and the Photo service is written in Java. After some time, we could have added the Thumbnail service which could have been written in a completely different language like Node.js.
Figure 4-4. Scaling independent microservices for video, photo and thumbnail.
In the diagram above, we have four versions of Video Service (VS1-4) and Thumbnail Service (TS1-4) each and two versions of Photo Service (PS1-2).
You can see the benefit of microservices architecture is that we can not only deploy but also scale the services independently. We can also use different languages and frameworks to create these services. System architecture is modular and independently deployable; we can now fix the problem we had with the videos by caching the videos close to the users. The major benefit of that approach is that it would require no change whatsoever do the photo service or the thumbnail service. Below you can find a very simplified version of the architecture where we can have multiple different clients accessing the services.
Figure 4-5. Independently scaled microservices being consumed by different types of clients.
Another huge problem that comes in the way of continuous delivery for monolithic services (not microservices) is versioning. Let us assume, that after some time we have users wanting us to parse the data that comes from the video and display subtitles. They would also like to listen to just an audio file. In the monolithic architecture, we will need to add functionality to create an audio file and then consume it via some kind of text parsing functionality that will also have to be a part of the media service now. In most of the cases text parser would be a completely different package. What if the video service wants to upgrade to the latest text parser version and for some reasons the audio service cannot? The media service is still a monolithic service. It’s written in one language and it uses shared packages. Even though video and audio are different sets of the same service they are bound to use the same versions of the packages. Independent upgrade of package is simply not feasible. The diagram below is an illustration of all the different functionalities cheering shared packages in the video and audio service sharing the text parser.
Figure 4-6. Media service using the same version of shared packages (including the text parser) for the video, photo, thumbnail and audio functionality.
In a microservices based architecture, we can surely use shared packages. However, we also have the flexibility to use different versions of the same packages with different services. So in this case we can have the video service using Text Parser version 1 and the audio service using Text Parser version 2 or the other way around. The great news here is that upgrading the package for audio service will in no way affect the video service. This way we do not have conflicting dependencies, we can do independent deployments by using multiple technology stacks and scale our development efforts. The sole benefit of being able to use multiple technology stacks in itself goes a long way in being able to retain talent as well as be able to use the latest and greatest technologies to get better results. Below you can find a diagram illustrating the same.
Figure 4-7. Microservices architecture showing use of different versions of the Text Parser in Audio and Video service.
HTTP is stateless but the application does have needs for statefulness. Microservices could be stateful or stateless depending on the application architecture. Most systems of scale would most probably have both stateless as well as stateful services. In case of a cloud offering like Microsoft Azure, we can use Azure Service Fabric that allows us to create Stateful as well as Stateless service. Both the services are created similarly and have code, config and data separated out. Based on the need of the application as well as the state of it, we can scale all the three components accordingly. Stateful microservices have no need for queues and caches and have low latency. In case of stateless microservices we need queues, caches and partitioned storage so we can store the application state in a scalable fashion. It’s strongly recommended to start with stateless microservices and introduce state as described earlier in the book rather than looking for an out of the box stateful architecture. This will go a long way in making sure that the system is scalable, deployable and will be flexible enough to newer changes in business needs as well as architecture. When in doubt refer back to the REST principles for creating a scalable solution.
Cazton is composed of technical professionals with expertise gained all over the world and in all fields of the tech industry and we put this expertise to work for you. Our experts are able to quickly identify, predict, and satisfy our clients' current and future need. Our hierarchy of consultants include Principal Consultants, Senior Architects, Senior Managers, Lead Senior Consultants, Senior and Junior Level Consultants and Developers available at your disposal with flexible engagements. Our services related to Microservices include but not limited to...
We specialize in Big Data and Big Data related technologies like Spark, Spark.NET, Hadoop, Kafka, PIG, Cassandra, HBase, HIVE, Zookeeper, Solr, and ElasticSearch. TensorFlow, DevOps, Microservices, Docker, Kubernetes, Blockchain, .NET, .NET Core, ASP.NET Core, Java, Node.js, Python, iOS Development, Cosmos DB, iOS Development, Cloud Computing, Salesforce, Agile Methodologies, Software Architecture Consulting and Training, Check out our consulting services for more details.
Cazton has expanded into a global company servicing clients not only across the United States, but in Europe and Canada as well. In the United States, we provide our Microservices Consulting and Microservices Training services across various cities like Austin, Dallas, Houston, New York, New Jersey, Irvine, Los Angeles, Denver, Boulder, Charlotte, Atlanta, Orlando, Miami, San Antonio, San Diego and others. Contact us today to learn more about what our experts can do for you.