Распределённые системы

Service Discovery

Цели урока

  • Объяснить почему hardcode IP-адресов не работает в облачных архитектурах
  • Сравнить DNS-based discovery и service registry по возможностям и ограничениям
  • Различать self-registration и third-party registration паттерны
  • Выбирать между client-side и server-side discovery для конкретных требований

Предварительные знания

  • Понимание микросервисной архитектуры (сервисы как отдельные процессы)
  • Базовое знание DNS (A-записи, TTL)
  • Знакомство с Kubernetes на уровне Pod и Service концептов

Netflix в 2012 перешёл на AWS: 800 микросервисов, каждый с динамическими IP. Один деплой менял адреса десятков инстансов за секунды. Так появился Eureka - open-source service registry который теперь работает в тысячах компаний.

  • **Kubernetes** - каждый из 5+ млн k8s-кластеров использует CoreDNS + Endpoints для service discovery из коробки
  • **Consul** от HashiCorp - 100 000+ production deployments, включая Stripe, Cloudflare, Adobe
  • **AWS ELB + Route 53** - server-side discovery для сотен тысяч приложений в AWS
  • **Istio service mesh** - расширяет discovery до circuit breaking, canary deployments, mTLS между сервисами
  • **etcd** - каждый Kubernetes API server хранит состояние кластера в etcd, включая Endpoints для discovery

Eureka и рождение cloud-native discovery

Netflix открыл исходный код Eureka в 2012 году после внутренней разработки для миграции на AWS. До Eureka использовался статический конфиг и проприетарные решения. Eureka ввёл ключевые концепции которые стали стандартом: self-registration, heartbeat, client-side caching. Сегодня Eureka - часть Spring Cloud и используется в тысячах Java-приложений, хотя сам Netflix перешёл на Consul для новых проектов.

Проблема: IP-адреса не постоянны

**Netflix, 2012. Переезд на AWS. 800+ микросервисов, каждый масштабируется горизонтально. EC2-инстанс запустился - получил новый IP. Перезапустился - снова новый IP. Hardcode адресов в конфигах стал невозможен.** Так Netflix создал Eureka - первый крупный open-source service registry. Сегодня каждый Kubernetes-кластер решает эту же проблему встроенными средствами.

**Суть проблемы:** в статической архитектуре сервис A знает адрес сервиса B заранее. В динамической - инстансы B появляются и исчезают, масштабируются от 1 до 100 и обратно. Нужен механизм, который отвечает на вопрос: "Какие инстансы сервиса X живы прямо сейчас и готовы принимать трафик?"

Три причины динамических адресов

ПричинаЧто происходитЧастота
AutoscalingНовые инстансы поднимаются под нагрузку, старые гасятсяМинуты-часы
Rolling deployНовая версия заменяет старую поочерёдно - каждый pod получает новый IPПри каждом деплое
Crash + restartKubernetes перезапускает упавший pod на другом узле - снова новый IPНепредсказуемо

Service discovery нужен только в микросервисах с сотнями сервисов

Достаточно двух сервисов с autoscaling чтобы потребовался discovery механизм

Как только один сервис имеет более одного инстанса или перезапускается автоматически - IP-адрес становится нестабильным. Kubernetes решает это для каждого приложения через ClusterIP и CoreDNS.

Почему hardcode IP-адресов не работает в современных облачных архитектурах?

DNS как service discovery

**Kubernetes использует DNS для service discovery из коробки с первого релиза в 2014. Каждый Service получает DNS-имя вида `payment-service.default.svc.cluster.local`. Pod не знает ни одного IP - только имена.** DNS - самый старый и распространённый механизм discovery, но с жёсткими ограничениями.

Ограничения DNS-based discovery

ПлюсМинусПоследствие
Работает везде без доп. инфраструктурыDNS TTL кеширует записиКлиент продолжает слать запросы на мёртвый IP пока не истечёт TTL
Стандартный протокол - любой язык поддерживаетНет встроенных health checksRegistry не знает что инстанс нездоров - только что он существует
Kubernetes CoreDNS обновляет записи быстроНет метаданных (версия, регион, вес)Нельзя делать canary deploy через DNS без доп. инструментов

**DNS TTL ловушка:** JVM и многие HTTP-клиенты агрессивно кешируют DNS-ответы. Даже при TTL=10s приложение может держать устаревший IP минутами. Решение - использовать Kubernetes Service (ClusterIP), который сам управляет routing через iptables/ipvs без DNS-кеш проблем.

Клиент получил IP сервиса через DNS. Сервис упал. DNS TTL = 30 секунд. Что произойдёт?

Service Registry: Consul, etcd, ZooKeeper

**Consul запущен HashiCorp в 2014. За первые 2 года - 10 000 production deployments. Причина популярности:** health checks из коробки, watch API для мгновенных обновлений, и KV store для конфигов в одном инструменте. etcd выбрал Kubernetes в 2014 как хранилище состояния кластера - с тех пор etcd работает в каждом k8s-кластере планеты.

Self-registration vs Third-party registration

ПаттернКто регистрируетПлюсМинус
Self-registrationСам сервис при стартеСервис контролирует свои метаданныеКаждый сервис требует registry SDK
Third-partyВнешний registrar (Kubernetes, Registrator)Сервисы не знают о registryRegistrar - доп. компонент, SPOF

**Kubernetes использует third-party:** Endpoints controller следит за pods через API server и автоматически обновляет Endpoints объект при изменениях. Сервис не содержит ни строки кода для регистрации.

Популярные реестры

СистемаКонсенсусHealth checksПрименение
ConsulRaftHTTP / TCP / gRPC / scriptService mesh, multi-datacenter
etcdRaftЧерез TTL-ключи или watchKubernetes state store, конфиги
ZooKeeperZABEphemeral nodes (исчезают при отключении)Legacy: Kafka, Hadoop
Kubernetes DNS + EndpointsВстроен в k8sReadiness probeВ k8s-кластере из коробки

Heartbeat = health check: если процесс шлёт heartbeat, значит сервис здоров

Heartbeat проверяет живость процесса, health check проверяет работоспособность сервиса

Процесс может быть жив (шлёт heartbeat), но зависнуть в deadlock, исчерпать connection pool или потерять соединение с БД. Health check endpoint /health должен проверять зависимости (БД, кеш, очереди) и возвращать 503 при проблемах.

Инстанс сервиса завис (процесс жив, но не отвечает на запросы). Какой механизм registry это обнаружит?

Client-side vs Server-side discovery

**Netflix OSS (2012-2015) стандартизировал client-side discovery через Ribbon + Eureka. AWS ELB и Kubernetes реализуют server-side. Оба паттерна живут в production прямо сейчас** - выбор зависит от требований к сложности клиента и допустимости дополнительного hop.

Client-Side Discovery

Клиент сам запрашивает registry, получает список живых инстансов и выбирает один по алгоритму балансировки.

Server-Side Discovery

Клиент отправляет запрос на фиксированный адрес load balancer. LB сам консультируется с registry и выбирает инстанс.

ПодходПлюсыМинусыПример
Client-SideГибкость в балансировке, нет SPOFКаждый клиент нужно обновлять при смене логики балансировкиNetflix Ribbon + Eureka
Server-SideКлиент прост - один фиксированный адресДополнительный сетевой hop, LB - потенциальный SPOFAWS ELB, Kubernetes Service

В **Kubernetes** server-side discovery встроен: обращение по имени сервиса (`http://payment-service`) через CoreDNS резолвится в ClusterIP, а kube-proxy направляет трафик на один из живых Endpoints. Инфраструктура полностью прозрачна для приложения.

Команда хочет делать canary deployments: 10% трафика на v2, 90% на v1. Какой подход discovery подходит лучше?

Вопросы для размышления

  • В Kubernetes Service discovery работает прозрачно - приложение не знает ни о каком registry. Что происходит внутри кластера когда pod падает и поднимается новый? Какие компоненты обновляют информацию о доступных инстансах?

Связанные уроки

  • ds-09-gossip-protocols — Gossip (SWIM) is used for health propagation in discovery
  • dist-09-raft — Consul uses Raft for consistent service registry reads
  • ds-11-distributed-locks — Registry and lock service are both linearisable KV stores
  • dist-12-consistency — Discovery reads need monotonic consistency guarantees
  • net-18-dns-basics
Service Discovery

0

1

Войти