Zookeeper in .Net Microservice Architecture
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
- Set Up Zookeeper with Docker
- Create a .NET Core Web API for Product Service
- Create a .NET Core Web API for Order Service
- Register Services with Zookeeper
- Discover Services from Zookeeper
- 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