Finding Services

In microservices, services are constantly starting, stopping, and moving. How does Service A find Service B?

The Problem

Challenge

Services run on different servers with dynamic IP addresses. Hardcoding addresses doesn't work!

Service Registry

A central directory where services register themselves and discover others.

Service Registration
import consul

# Service registers itself on startup
def register_service():
    c = consul.Consul()
    c.agent.service.register(
        name='order-service',
        service_id='order-1',
        address='192.168.1.100',
        port=8080,
        tags=['v1', 'production']
    )

# Service discovers others
def find_service(service_name):
    c = consul.Consul()
    services = c.health.service(service_name, passing=True)
    return services[0]  # Returns healthy instance

Load Balancing

When multiple instances of a service exist, distribute requests evenly.

  • Round Robin: Send requests to each instance in turn
  • Least Connections: Send to instance with fewest active connections
  • Random: Pick random instance

Service Discovery Patterns

Client-side vs server-side discovery, health checks, and more.

Client-Side Discovery

Client queries the registry and load balances requests.

Python - Client-Side Discovery
import consul
import requests
import random

class ServiceClient:
    def __init__(self):
        self.consul = consul.Consul()

    def call_service(self, service_name, endpoint):
        # 1. Query service registry
        _, services = self.consul.health.service(service_name, passing=True)

        if not services:
            raise Exception(f"No healthy instances of {service_name}")

        # 2. Client-side load balancing
        service = random.choice(services)
        url = f"http://{service['Service']['Address']}:{service['Service']['Port']}{endpoint}"

        # 3. Make request
        return requests.get(url)

Server-Side Discovery

Client makes request to load balancer, which handles discovery.

Aspect Client-Side Server-Side
Complexity Client handles it Infrastructure handles it
Control More control Less control
Example Netflix Eureka AWS ELB, NGINX

Health Checks

Services must report their health so unhealthy instances aren't used.

Health Check Endpoint
from flask import Flask, jsonify

app = Flask(__name__)

@app.route('/health')
def health_check():
    # Check dependencies
    db_healthy = check_database()
    cache_healthy = check_cache()

    if db_healthy and cache_healthy:
        return jsonify({"status": "healthy"}), 200
    else:
        return jsonify({"status": "unhealthy"}), 503

Advanced Discovery Patterns

Service mesh, DNS-based discovery, and multi-datacenter setups.

Service Mesh Discovery

Service mesh handles discovery, routing, and load balancing automatically.

Istio Service Mesh
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: order-service
spec:
  host: order-service
  trafficPolicy:
    loadBalancer:
      consistentHash:
        httpHeaderName: user-id
    connectionPool:
      tcp:
        maxConnections: 100
      http:
        http1MaxPendingRequests: 50
        maxRequestsPerConnection: 2
  subsets:
  - name: v1
    labels:
      version: v1
  - name: v2
    labels:
      version: v2

Netflix Eureka

  • Scale: 1000+ microservices
  • Pattern: Client-side discovery
  • Features: Self-preservation mode during network issues
  • Resilience: Works even if Eureka server is down
  • Key Insight: Cache service locations locally
Best Practices
  • Cache Service Locations: Don't query registry on every request
  • Graceful Degradation: Use stale data if registry is unavailable
  • Circuit Breakers: Protect against cascading failures
  • Multi-Region: Route to nearest healthy instance