Service Discovery
The Problem: Dynamic Locations & Tight Coupling
- Hardcoded IPs: Services need to talk to others (e.g., Order Service needs Product Service), but IP addresses change as instances scale up/down, causing failures.
- Tight Coupling: Hardcoding causes direct dependencies, making systems brittle and difficult to update or test across environments (dev, QA, prod).
- Single Point of Failure: If a single instance is hardcoded and fails, the whole communication breaks.
- Scalability Issues: Difficult to distribute load or add new instances without manual config changes.
The Solution: Service Discovery
- Service discovery is the automatic process where applications and devices find each other on a network, crucial for dynamic environments like microservices.
- Using a central Service Registry to register and look up network locations (IPs/ports) of services, eliminating hardcoded addresses and enabling dynamic scaling and communication.
- Services register themselves, and consumers query the registry to find healthy instances, often using logical names instead of physical ones
- Facilitated by tools like Consul, Kubernetes, or Eureka.
Key Components
- Service Registry: A central database (like Consul, Eureka) holding real-time information about available services and their locations.
- Service Provider: The service offering functionality (e.g., a payment service).
- Service Consumer: The service that needs to use another service's function (e.g., an order service needing the payment service).
How it works
- Registration: When a service starts, it registers its network address (IP/port) and health status with the Service Registry.
Lookup: A service needing to communicate with another queries the registry using a logical service name (e.g., "User-Service").
Resolution: The registry returns the current physical address(es) of healthy instances, allowing the requesting service to connect directly.
Benefits
- Simplified Operations: Automates complex network management in distributed systems.
- Decoupling: Services don't need to know each other's hardcoded locations.
- Health Checks: The registry monitors services to ensure only healthy, available instances are returned.
- Resilience: Routes traffic to healthy instances, improving reliability.
- Dynamic Scalability: Easily add or remove service instances without reconfiguration.
Examples in Practice
- Kubernetes: Uses built-in service discovery for pods.
- HashiCorp Consul: A popular tool for service discovery and configuration.
- Netflix Eureka: A client-side discovery tool for Java/Spring applications
Service Discovery in .NET
- Create ASP.NET Core Project
- Add nuget package
Microsoft.Extensions.ServiceDiscovery
- Add service dependencies in program.cs
builder.Services.AddConfigurationServiceEndpointProvider();
- Configure HttpClient and add service discovery
builder.Services
.AddHttpClient("sampleapi", client =>
{
client.BaseAddress = new("https://sampleapi");
})
.AddServiceDiscovery();
- Add config in appsettings.json
{
"Services": {
"sampleapi": {
"https": [
"jsonplaceholder.typicode.com"
]
}
}
}
- In HomeController.cs, inject
IHttpClientFactory to create httpclient object and call api
public class HomeController : Controller
{
private readonly ILogger<HomeController> _logger;
private readonly IHttpClientFactory _httpClientFactory;
public HomeController(ILogger<HomeController> logger, IHttpClientFactory httpClientFactory)
{
_logger = logger;
_httpClientFactory = httpClientFactory;
}
public async Task<IActionResult> Index()
{
var httpClient = _httpClientFactory.CreateClient("sampleapi");
var result = await httpClient.GetFromJsonAsync<List<Todo>>("todos");
return View(result);
}
}
References