In a monolithic application, the components are tightly coupled and binary references are used to communicate among them, thereby requiring the tech stack to be common for all components. Multiple teams working on the same application must communicate and agree on changes among them. Regression testing is required during releases to ensure other functionality is not broken. Downtimes are required for releases, regardless of the change made. Scaling is unified for the entire application irrespective of the most used features in terms of demand.
Microsoft Azure Service Fabric is a distributed systems platform that makes it easy to package, deploy and manage scalable and reliable Microservices and containers. It handles complex infrastructure related issues, thereby enabling developers and administrators to focus on the development of applications which are mission critical, demanding workloads that are scalable, reliable, and manageable.
Service fabric contains a shared set of network connected virtual and physical machines known as a cluster. A machine or VM which is a part of a cluster is known as a cluster node. Clusters can scale to thousands of nodes.
A cluster offers a robust, lightweight runtime for building distributed, scalable, stateless and stateful microservices running in containers. It also provides a rich set of tools to provision, deploy, monitor, upgrade and delete applications deployed, including containerized services.
In a microservice based application, the application is comprised of multiple services/components which communicate with each other via service/API calls, thereby enabling the tech stacks to defer between each service. Microservices are independently deployable, therefore reducing the testing scope when changes are made. Downtimes are minimal during releases as changes made are related to the component being released. Scaling for individual components is based on the bottle-necked services in order to cater to higher demand.
Service fabric also offers capabilities for managing the lifecycle and runtime for applications which are composed of Microservices. Microservices are hosted inside containers that are deployed and activated across the cluster.
Service Fabric can run anywhere including Azure, on-premise, Windows server, Linux and even other clouds. The development environment in the SDK is identical to that of the production environment with no emulators involved.
Service Fabric monitors and automatically mitigates environment related issues. It also provides support for stateless services , stateful services and reliable actors. Service Fabric provides reliability via replication and persistence, enables deployment with zero downtime, provides on-demand auto scaling and caters to runtime of any application code.
Service fabric caters three different types of services to build upon:
Reliable services is a lightweight programming model that lets you integrate with the service fabric runtime which allows the use of the Service Fabric programming API. This avoids complex problems around service management by providing features such as a communication model. This allows services to discover and communicate with each other, generate health reports on services, receive notifications about upgrading services, along with many other capabilities. There are two subtypes of reliable services:
This type of service does not require a state to be maintained. Being a familiar paradigm in web development, typically these services receive requests and processes it. The state is stored in an external data storage tier (if required).
Usually these types of services use caching mechanisms in place, as requests to the external data storage are costly. It also allows for scaling out a stateless service by defining the number of instances (the number of copies of the application logic distributed across the nodes in a cluster). As there is no state maintained with the service, a request can be routed to any instance of the stateless service.
Below is the flow of a stateless service.
Services that do not require the state to be maintained such as application end-points for end-users, web proxies, API Gateways and services where other external stores have better support for the team/application.
The stateful service allows the state to be persisted within the service without a need for an external storage provider.
The overall architecture design is simplified by removing the needs of additional layers like caches, queues and external data tiers. Lower latency and improved throughput are observed during reads and writes and as there is no communication with an external store for state.
A typical stateful service is as follows:
The service fabric runtime uses replicas to manage the reliability of the state by replicating the state into multiple nodes in the cluster. A replica is a running instance of the stateful service with a copy of the state. The number of replicas should be defined for a stateful service. All transactional read and write operations are performed at the primary replica level, and the state changes are automatically replicated to all other active secondary replicas. In the event of a failure of the primary replica, service fabric would make an active secondary replica as the primary replica. Thus, consistent and reliable states are achieved for stateful services. Shopping carts, GPS navigation and games are candidates for stateful services where states are maintained in real-time.
The Actor programming in service fabric is based on the virtual actor model and is built on top of reliable stateful service.
It is suitable for handling massive amounts of client requests by executing them asynchronously and independently of each other. Actors can communicate with each other and they are capable of creating more actors. Actors can be configured to store the state as persisted, volatile or only in memory.
The reliable actor runtime automatically creates an actor when it receives a request. Each actor is defined as an instance of an actor type and they execute their task simultaneously. Each such actor is uniquely identified by an actor id. The actor runtime garbage collector, collects the memory object if the actor has not been used for a period of time.
A good example of a use case would be a hotelbooking system. When a user does a price lookup for a hotel booking, the system sends the request with filter parameters to all the hotels at once, waiting for the response to come back, before sending the result to the user.
A service fabric application may consists of many microservices which need a mechanism to communicate with each other.
In the service fabric cluster, services are distributed across nodes and are not strictly tied to a particular node. Services may be moved from one node to another. A service discovery and resolution service known as the “Naming Service” runs on the cluster which maintains the service instances and endpoint addresses. Service fabric provides a few inbuilt communication methods and the decision on which should be used depends on the communication network, programming model and the programming language the services are written on.
Service remoting is the easiest and fastest way to get service communication up and running. It allows strongly typed remote procedure calls and handles service address resolution, connection establishment, retries and error handling. The service communication is also possible over HTTP and it is an industrial standard choice and supports for language-agnostic communication. Service fabric also supports WCF as an inbuilt communication method. Furthermore, it supports any communication protocol or framework that can be plugged into the service fabric communication API. Other options include integrating any message broker, which enables services to communicate by passing messages.
Partitioning is a core pattern of building large and scalable solutions. The process involves physically dividing the data into smaller, manageable and accessible units to improve scalability and optimize performance. As an example, user information in a system can be partitioned and stored by country. The data can then be retrieved based on the relevant partitions resulting in the retrieval process being much faster compared to a single partition.
Partitioning for stateless services is a rare occurrence as there is no state within the service. Scalability and availability of the service is typically achieved by adding more instances.
Removing an application would be vice-versa of the above steps, where the running application instance is deleted, the application type is unregistered and finally the application package is removed from the image store.
When using Visual Studio, the above is handled automatically using a predefined PowerShell script. When using an external store, the application needs to be packaged as an “sfpkg” and uploaded to the external store.
A container can be looked as a vessel which contains a microservice/software application packaged along with its relevant libraries and frameworks they depend upon for their runtime. Containers are executed over a single host O/S on a server where the containers would talk to the host O/S. Multiple containers may run on a single host O/S. Containers are relatively small keeping the overhead relatively low. Containers enable the application to run anywhere regardless of where it is deployed.
Specialized software such as Kubernetes and Docker are used to manage containers. These software help push the containers to different machines and make sure that the applications in containers run. They even give the ability to spin up more containers with specific allocations and applications based on demand.
Azure functions are mini methods which can be hosted on the cloud. A combination of these functions would make up a microservice. However, writing many functions and shaping them into many microservices can be considered as a cumbersome process.
Microservices enable a large application to be split and decoupled by business responsibilities. Service
The service fabric platform allows any application, written in any language, as a service to be hosted and run as a stateless service. The guest executables benefit from features the platform offers, such as service discovery, health and load reporting, by calling the service fabric REST API.
When building an application in service fabric, typically a combination of these three types of services are visible. All services are deployed into the same service fabric cluster and each of these services are independent and scalable.
For stateful services, Service fabric divides the state into smaller units and replicates them to multiple nodes in the cluster. Thus, a partition is a set of replicas that are distributed and balanced across the nodes and it allows to grow over a specific node’s resources limit. This ensures that service fabric uses hardware resources efficiently.
Applications can be deployed either via PowerShell, Visual Studio Publish Wizard or an external provision. Once an application type is packaged, the package can be deployed into a service fabric cluster.
With regards to the deployment steps, first the application package is uploaded to the image store. This is followed by registering the application type with the image store relative path. Finally, the application instance is created.
Fabric is a powerful platform to host microservices. The developer only needs to focus on the development of the application while service fabric takes care of all infrastructure related issues automatically.
While the key elements were described in the above sections, Service fabric has many other arenas to be explored and useful features such as logging, event tracing and application insights to be discovered.
The service Fabric official documentation on the Microsoft site is a great resource for further reading and discovering the true potential of Service Fabric.