Microservices & Scaling — Series 2

Preview — 3 of 10 questions

In a microservices architecture where service instances are frequently created, destroyed, and rescheduled (e.g., by an orchestrator like Kubernetes), why is hardcoding a service's IP address especially problematic, and what does service discovery solve?

javascript
// Hardcoded (fragile)
const response = await fetch('http://192.168.1.42:3001/api/inventory');

// Service discovery (resilient)
const inventoryServiceUrl = await serviceRegistry.lookup('inventory-service');
const response2 = await fetch(`${inventoryServiceUrl}/api/inventory`);
AHardcoding IP addresses is always the recommended, most reliable approach in production microservices.
BService discovery is only relevant for services running on the same physical machine.
CIndividual service instances in a dynamic environment can be replaced, rescheduled, or scaled up/down at any time, meaning their IP addresses change frequently and unpredictably — hardcoding one will inevitably break once that particular instance is gone. Service discovery solves this by maintaining a registry that services can query at runtime to find the current, live network location(s) of another service by its logical name, rather than a fixed address.
DService discovery replaces the need for a network connection between services entirely.

What problem does an API Gateway solve for the client in a microservices architecture?

javascript
async function handleDashboard(req, res) {
  const [user, orders, recommendations] = await Promise.all([
    fetch('http://user-service/me'),
    fetch('http://order-service/recent'),
    fetch('http://recommendation-service/for-user'),
  ]);
  res.json({ user, orders, recommendations });
}
AAn API Gateway's only purpose is to compress HTTP responses to reduce bandwidth.
BWithout a gateway, a client (e.g., a mobile app) would need to know about, individually call, and separately handle authentication/errors for every single backend microservice directly — an API Gateway provides one unified entry point that internally routes/aggregates requests to the appropriate backend services, letting clients interact with a single, stable API surface without needing to know how the backend is actually decomposed into services.
CAn API Gateway eliminates the need for any backend services at all, since it handles all logic itself.
DAn API Gateway is a synonym for a load balancer with no additional responsibilities.

Since each service manages its own separate database, there's no way to wrap reserveFlight, reserveHotel, and chargePayment in one atomic database transaction. What pattern is demonstrated here to keep the overall operation consistent, and what is its core mechanism?

javascript
async function bookTripSaga(details) {
  const flight = await reserveFlight(details.flight);
  try {
    const hotel = await reserveHotel(details.hotel);
    try {
      await chargePayment(details.payment);
    } catch (err) {
      await cancelHotelReservation(hotel.id);
      await cancelFlightReservation(flight.id);
      throw err;
    }
  } catch (err) {
    await cancelFlightReservation(flight.id);
    throw err;
  }
}
AThis is the Circuit Breaker pattern, since it involves try/catch blocks around service calls.
BThis is called "distributed ACID," since it fully replicates traditional single-database transaction guarantees across services.
CThis pattern has no name; it's simply considered bad practice and should always be avoided.
DThis is the Saga pattern — instead of one atomic cross-service transaction (which isn't possible when each service owns its own database), each step is executed individually, and if a later step fails, previously completed steps are undone via explicit compensating actions (like cancelHotelReservation) that semantically reverse their effect, rather than a database-level rollback.

Sign up free to play

Answer all 10 questions (7 more), see explanations for every answer, and track your score.