Welcome to Innominds Blog
Enjoy our insights and engage with us!

Azure Service Fabric & Stateless Services: The Gateway to Development and Management of Microservices

By Tushar Tyagi,

Introduction

With distributed computing being the solution for cloud-era applications, which needs to scale with the user load, one obvious solution is to use Microservices. It allows the application domain to be segregated into different logical parts, which can scale up and down as per the user load.

Today, a lot of big platforms use Microservices Architecture: Netflix, Facebook, Uber, Microsoft and Twitter to name a few. Even the comparatively smaller platforms are looking at microservices since these allow rapid prototyping and publishing, dynamic scaling and can use only the required amount of the cloud infrastructure.

This is part 1 of the series of taking a look at the technical aspects of Azure Service Fabric. In this part, we will cover the Stateless Services offered by the platform.

Azure Service Fabric

Azure Service Fabric (ASF) is a Platform-as-a-Service offering by Microsoft, which allows fast development and management of microservices. Existing applications can be containerized and plugged into the ASF. The management, routing, and all other mechanics are taken care by the platform.

With ASF, Microsoft supports Azure and other cloud service providers, as well as, on-premise installations, although, using ASF with Azure infrastructure allows seamless integration of other Azure offerings like Azure Service Bus, Azure Event Bus, Azure Cosmos DB, Azure SQL Database, etc.

Types of Services

ASF provides three types of services:

  1. Stateless
  2. Stateful
  3. Actor based services

The best principles of Microservices Architecture state that each service should have its own API and data store, and any changes to the data store needs to go through the exposed API. With ASF, both Stateful and Actor based services provide their own data store, and Stateless Services are mostly used to do operations, which do not require any state to persist: creating profile pictures of a given size from a large size image is one such example of Stateless Service.

In this blog, we will focus on the Stateless Service type and how to use it to create a simple rot13 application.

But first, it's important to understand some technical details with respect to services and ASF.

Stateless Service

A Stateless Service, as mentioned earlier, is ideally used for data transformation operations where no state needs to be persisted in the service itself. Note that this doesn't mean that it cannot save any state in a centralized data store. It can. Having said that, the data store cannot be owned by the service. For example, an image transformation service will just transform the image, with the logging, analytics and other information being sent to either a centralized data store or to other services.

Stateful Service

A Stateful Service, on the other hand, is only used when the state needs to be persisted in the service. This could be a shopping service, which stores all the products that the user has in the shopping cart, or a history service, which stores all the products ever purchased by the user. All of this state is kept in the internal data store of the service, which is not directly accessible by any other service. Any access is provided via the exposed APIs.

Actors

Reliable Actor Service is a service, which uses the Actor Model pattern wherein the application logic allows to create a large number of "units of computation" that run concurrently and communicate to each other via message passing.

In Service Fabric, Actor Service is a subclass of Stateful Service, which uses a specific partitioning scheme. In case your application uses a pattern wherein a large number of concurrent users are present at any given time, one can go with the actor pattern. Examples for this can be an e-commerce application where each customer is an actor, a library where each book is an actor, an online game server where each player is an actor, etc. The common idea is that each such Actor type has same properties and a large number of them are present at any given time.

Partitions & Replicas

Since ASF is a distributed architecture, each active data medium should have multiple backup copies so that a backup copy can be deployed if the current active copy is inaccessible due to network or other issues. This is done by partitioning the application data into what are simply called Partitions and have multiple "Replicas” of each partition.

Only one of the replicas are ever active, with all other being passive. Any data changes first go to the active replica and is then synced to the passive replicas. To provide redundancy, ASF tries not to keep replicas of same partitions on the same node or VM. In case any VM goes down, another replica on a different VM is activated. All this is done without user knowledge and is managed by ASF.

Replicas in Stateless Service

Since Stateless Service doesn't have any data, each replica is just a copy of the service running. For example, if the service has 5 replicas, it means that it has 5 copies running across 5 different nodes in the ASF cluster.

Replicas in Stateful Service

For Stateful Service, the application designer needs to provide the partitioning logic so that each partition accounts for similar data size and similar request load.

For example, a city voting application can create partitions across different districts. If the city has 20 districts, then we can create a partition for each district, but that is not helpful if district A has 70% of the population. It will account for a lot of load and user requests. One option could be to break the districts into subdistricts and mix subdistricts from different areas so that each caters to around 10%-12% of the user load. We can then work with around 10 partitions or mix them so that each caters to 25% of the population and we can have just 4 partitions.

In the end, what you do depends on the logic of the application underneath.

Writing a Stateless Service for Rot13

Rot13  cipher is a simple encryption method where all the letters of the alphabet are rotated by 13 positions.

rot13

Since this is just a data transformation operation, where we pass in a string and get back a rotated string, it will not persist any state and therefore using a Stateless Service will work here.

Setup New ASF Project

*Kindly note that this project requires Azure Service Fabric SDK to be installed on the development machine to run a local Azure Service Fabric cluster. The steps to install SDK are on the Microsoft official site here.

We first create a new Service Fabric project using Visual Studio:

create1create2

When prompted for service type, pick "Stateless ASP.NET Core Service" and give the name as Rot13.

create3

Pick API on the next screen.

create4

Details

Visual Studio automatically generates the baseline code for this microservice. Checkout Program.cs file:

/// <summary>
/// This is the entry point of the service host process.
/// <summary>
private static void Main() {
    try{
        // The ServiceManifest.XML file defines one or more service type names.
        // Registering a service maps a service type name to a .NET type.
        // When Service Fabric creates an instance of this service type,
        // an instance of the class is created in this host process.

        ServiceRuntime.RegisterServiceAsync("Rot13Type",
        context => new Rot13(context)).GetAwaiter().GetResult();

        ServiceEventSource.Current.ServiceTypeRegistered(Process.GetCurrentProcess().Id, typeof(Rot13).Name);

        // Prevents this host process from terminating so services keeps running. 
        Thread.Sleep(Timeout.Infinite);
    }
    catch (Exception e){
        ServiceEventSource.Current.ServiceHostInitializationFailed(e.ToString());
        throw;
    }
}

We are essentially registering "Rot13Type" into the service fabric. This line means that whenever there's a request for "Rot13Type", create a new Rot13 instance, pass it the service fabric context and infinitely wait for the input (using Thread.Sleep).

Rot13Type, on the other hand, is defined in the PackageRoot/ServiceManifest.xml file.

<?xml version="1.0" encoding="utf-8"?>
<ServiceManifest Name="Rot13Pkg"
                 Version="1.0.0"
                 xmlns="http://schemas.microsoft.com/2011/01/fabric"
                 xmlns:xsd="http://www.w3.org/2001/XMLSchema"
                 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <ServiceTypes>
    
    <StatelessServiceType ServiceTypeName="Rot13Type" />
  </ServiceTypes>

Implementation

With details on the side, we implement the Rot13 operation in our controller class.

Rename the default ValuesController to RotController.

Now, we implement the Post method to take in a string, and return it after rotating it by 13 letters. We use Post because we want the API to support input of arbitrary size, and adding too many stuff in the URL doesn't look good. Moreover, it causes problems for bookmarks.

Following is the code we will implement in the controller.

namespace Rot13.Controllers
{
    [Route("api/[controller]")]
    public class RotaterController : Controller
    {
        private readonly Rotater _rotator;

        public RotaterController(Rotater rotator)
        {
            _rotator = rotator;
        }
        
        [HttpPost]
        public IActionResult Post([FromBody]string value)
        {
            try
            {
                return Ok(_rotator.Rotate(value));
            }
            catch(Exception _)
            {
                return StatusCode(500);
            }
        }        
    }
}

Let's create the Rotater class used by the controller. We will create a new folder called Common and add the Rotater class in it.

namespace Rot13.Common
{
    public class Rotater
    {
        public string Rotate(string value)
        {
            var chars = value.ToCharArray().Select(Rotate).ToArray();
            return new string(chars);
        }

        private char Rotate(char c)
        {
            if (char.IsLetter(c))
            {
                var rotated = c + 13;
                var alphabetSize = 26;

                // Handle Overflow
                if ((char.IsUpper(c) && rotated > 'Z') || (char.IsLower(c) && rotated > 'z'))
                    rotated -= alphabetSize;

                // Handle Underflow
                if ((char.IsUpper(c) && rotated < 'A') || (char.IsLower(c) && rotated < 'a'))
                    rotated += alphabetSize;

                return (char)rotated;
            }
            else
            {
                return c;
            }
        }
    }
}

We just need to do one last thing. Since the controller uses the Rotater class, we have to get it. Since .NET core supports Dependency Injection without any third-party library, we benefit from it and add the following line to the Rot13.cs file:

/// <summary>
        /// Optional override to create listeners (like tcp, http) for this service instance.
        /// </summary>
        /// <returns>The collection of listeners.</returns>
        protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
        {
            return new ServiceInstanceListener[]
            {
                new ServiceInstanceListener(serviceContext =>
                    new KestrelCommunicationListener(serviceContext, "ServiceEndpoint", (url, listener) =>
                    {
                        ServiceEventSource.Current.ServiceMessage(serviceContext, $"Starting Kestrel on {url}");

                        return new WebHostBuilder()
                                    .UseKestrel()
                                    .ConfigureServices(
                                        services => services
                                            .AddSingleton<StatelessServiceContext>(serviceContext)
                                            .AddTransient<Rotater>())
                                    .UseContentRoot(Directory.GetCurrentDirectory())
                                    .UseStartup<Startup>()
                                    .UseServiceFabricIntegration(listener, ServiceFabricIntegrationOptions.None)
                                    .UseUrls(url)
                                    .Build();
                    }))
            };
        }

This will add an instance of Rotator class wherever it is required - one instance per http request because we've added it as Transient.

Running the Application

Since everything is in place, we double check if ASF Application is the Startup project and hit F5. VS will deploy the application and open the browser.

In the current environment, the service is deployed on port 9017 and is accessible on the following endpoint : http://localhost:9017/api/rot The actual URL will change based on the settings provided in Visual Studio "

I usually use Postman or Fiddler to test APIs. Here's the screenshot of Postman testing the endpoint:

fiddler

Since the application is now deployed, you can access the Service Fabric Cluster on its default url: http://localhost:19080/Explorer/index.html and see the status of service.

 

Summary

Azure Service Fabric is one of the key components when it comes to building great software. Azure resources are of utmost importance for clients who are using Azure cloud services as they can switch to Azure Service Fabric and reap benefits of the Service Fabric platform features.

Innominds, specializes in ideating, designing, and developing cost-effective, cutting-edge digital product and application solutions and services for your business’ IT needs. Starting from inception of ideas, offering Product Lifecycle Management Services, Legacy Transformations, Cloud Engineering and Design Architecture among others, we have got it covered for you. We help companies in accelerating their digital transformation evolution. With over 12 years of experience in building digital products from scratch and 100 products engineered, Innominds is well placed to cater to all your products and applications requirements. 

Interested! For any demos or project discussions, please write to us at marketing@innominds.com and know more about our offerings.

Topics: Digital Products & Applications

Tushar Tyagi

Tushar Tyagi

Tushar Tyagi - Senior Engineer - Software Engineering

Subscribe to Email Updates

Authors

Show More

Recent Posts