Zookeeper in .Net Microservice Architecture

DotNet Full Stack Dev
3 min readJul 23, 2024

--

Service discovery is a key component in microservice architecture. It allows services to find and communicate with each other without hardcoding the network locations of services. Zookeeper is a widely-used tool for this purpose. In this example, we will integrate Zookeeper for service discovery in a microservice architecture with Product and Order services.

Embark on a journey of continuous learning and exploration with DotNet-FullStack-Dev. Uncover more by visiting our https://dotnet-fullstack-dev.blogspot.com reach out for further information.

Why Service Discovery?

  • Dynamic Scalability: Microservices can scale up or down without manual reconfiguration.
  • Fault Tolerance: Services can be replaced if they fail, and new instances can be automatically registered.
  • Decoupling: Services can interact without knowing the network locations of other services.

What is Zookeeper?

  • Centralized Service for Configuration Management: It maintains configuration information, naming, providing distributed synchronization, and providing group services.
  • Service Registration and Discovery: Services register themselves with Zookeeper, and other services query Zookeeper to discover services.

Example Overview

We’ll use Zookeeper for registering and discovering the Product and Order services.

Prerequisites

  • .NET Core 6.0
  • Apache Zookeeper
  • Docker (for running Zookeeper)

Steps

  1. Set Up Zookeeper with Docker
  2. Create a .NET Core Web API for Product Service
  3. Create a .NET Core Web API for Order Service
  4. Register Services with Zookeeper
  5. Discover Services from Zookeeper
  6. Integrate Services

Step 1: Set Up Zookeeper with Docker

docker run -d --name zookeeper -p 2181:2181 zookeeper

Step 2: Create a .NET Core Web API for Product Service

Create a new Web API project

dotnet new webapi -n ProductService

Add Zookeeper dependencies

dotnet add package ZooKeeperNetEx --version 3.4.6.1

Implement Service Registration

using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using System;
using ZooKeeperNetExClient;

public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddSingleton<IHostedService, ZookeeperHostedService>();
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}

app.UseRouting();

app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}

public class ZookeeperHostedService : IHostedService
{
private readonly IZooKeeper _zooKeeper;

public ZookeeperHostedService()
{
_zooKeeper = new ZooKeeper("localhost:2181", TimeSpan.FromSeconds(10), new ZookeeperWatcher());
}

public Task StartAsync(CancellationToken cancellationToken)
{
var path = "/services/product";
var data = Encoding.UTF8.GetBytes("http://localhost:5000");

if (_zooKeeper.Exists(path, false) == null)
{
_zooKeeper.Create(path, data, Ids.OPEN_ACL_UNSAFE, CreateMode.Ephemeral);
}
else
{
_zooKeeper.SetData(path, data, -1);
}

return Task.CompletedTask;
}

public Task StopAsync(CancellationToken cancellationToken)
{
_zooKeeper.Dispose();
return Task.CompletedTask;
}
}

public class ZookeeperWatcher : IWatcher
{
public void Process(WatchedEvent @event)
{
// Handle events
}
}

Step 3: Create a .NET Core Web API for Order Service

Create a new Web API project

dotnet new webapi -n OrderService

Add Zookeeper dependencies

dotnet add package ZooKeeperNetEx --version 3.4.6.1

Implement Service Registration

using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using System;
using ZooKeeperNetExClient;

public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddSingleton<IHostedService, ZookeeperHostedService>();
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}

app.UseRouting();

app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}

public class ZookeeperHostedService : IHostedService
{
private readonly IZooKeeper _zooKeeper;

public ZookeeperHostedService()
{
_zooKeeper = new ZooKeeper("localhost:2181", TimeSpan.FromSeconds(10), new ZookeeperWatcher());
}

public Task StartAsync(CancellationToken cancellationToken)
{
var path = "/services/order";
var data = Encoding.UTF8.GetBytes("http://localhost:5001");

if (_zooKeeper.Exists(path, false) == null)
{
_zooKeeper.Create(path, data, Ids.OPEN_ACL_UNSAFE, CreateMode.Ephemeral);
}
else
{
_zooKeeper.SetData(path, data, -1);
}

return Task.CompletedTask;
}

public Task StopAsync(CancellationToken cancellationToken)
{
_zooKeeper.Dispose();
return Task.CompletedTask;
}
}

public class ZookeeperWatcher : IWatcher
{
public void Process(WatchedEvent @event)
{
// Handle events
}
}

Step 4: Discover Services from Zookeeper

Create a service that will discover other services registered in Zookeeper.

public class ZookeeperServiceDiscovery
{
private readonly IZooKeeper _zooKeeper;

public ZookeeperServiceDiscovery()
{
_zooKeeper = new ZooKeeper("localhost:2181", TimeSpan.FromSeconds(10), new ZookeeperWatcher());
}

public async Task<string> GetServiceUrlAsync(string serviceName)
{
var path = $"/services/{serviceName}";
var data = await _zooKeeper.GetDataAsync(path, false);
return Encoding.UTF8.GetString(data);
}
}

Step 5: Integrate Services

Integrate the Product and Order services using the discovered URLs.

OrderService Controller Example:

[ApiController]
[Route("api/[controller]")]
public class OrderController : ControllerBase
{
private readonly ZookeeperServiceDiscovery _serviceDiscovery;

public OrderController(ZookeeperServiceDiscovery serviceDiscovery)
{
_serviceDiscovery = serviceDiscovery;
}

[HttpGet("products")]
public async Task<IActionResult> GetProducts()
{
var productServiceUrl = await _serviceDiscovery.GetServiceUrlAsync("product");
var client = new HttpClient();
var response = await client.GetStringAsync($"{productServiceUrl}/api/products");
return Ok(response);
}
}

Conclusion

In this example, we’ve set up a service discovery mechanism using Zookeeper in a .NET microservice architecture. The Product and Order services are registered with Zookeeper, and they can discover each other dynamically. This approach ensures that services can scale, failover, and evolve without manual configuration updates. Integrating Zookeeper simplifies the management of service instances and provides a robust solution for service discovery in microservices.

You may also like : https://medium.com/@siva.veeravarapu/api-gateway-in-net-microservice-architecture-411cdf52c22d

--

--

DotNet Full Stack Dev
DotNet Full Stack Dev

Written by DotNet Full Stack Dev

Join me to master .NET Full Stack Development & boost your skills by 1% daily with insights, examples, and techniques! https://dotnet-fullstack-dev.blogspot.com

No responses yet