Перейти к основному содержимому

Обратная совместимость интеграций

Обратная совместимость — способность системы работать с более старыми клиентами или потребителями после внесения изменений в интерфейс или формат данных.

В интеграциях это критически важно: если одно приложение изменило контракт, а другое не успело обновиться, возникает сбой во всей цепочке бизнес-процессов.

Последствия нарушения:

  • Остановки бизнес-процессов
  • Потери данных при некорректной обработке сообщений
  • Увеличение затрат на экстренные исправления

Принцип: поставщик данных эволюционирует без требования изменений от потребителей.

Виды совместимостей:

  • Backward compatibility (обратная) — новые версии совместимы со старыми клиентами.
  • Forward compatibility (прямая) — старая версия может работать с будущими данными.
  • Full compatibility (полная) — поддерживаются оба направления.

Для интеграций чаще всего важна обратная совместимость: не ломать то, что уже работает.

Общие подходы обеспечения обратной совместимост

  1. Версионирование: явное указание версии контракта через URI, заголовки или параметры

  2. Добавление новых функций без изменения существующих

  3. Deprecated-стратегия:

    • сначала поле/метод помечается как устаревший - "deprecated", но остается доступным.
    • через несколько релизов удаляется, после уведомления потребителей.
  4. Контрактное тестирование (Consumer-Driven Contracts): подход к тестированию интеграций, при котором контракт (API, сообщение, схема) формируется не со стороны провайдера, а со стороны потребителя

  5. Feature flags и поэтапное внедрение:

    • Дается потребителям время перейти на новую схему.
    • Одновременно поддерживаются старый и новый формат.

Обратная совместимость в REST API

Что может сломать совместимость:

  • Удаление полей.
  • Изменение типа (число → строка).
  • Изменение формата ответа.
  • Требование новых обязательных параметров.

Практики:

  • Поля в JSON только добавлять, не удалять. Обязательные поля не удалять, а помечать deprecated
  • Новые поля делать необязательными (nullable).
  • Переименование заменять на добавление нового поля + "депрекейт" старого.
  • Версионирование через заголовок "Accept", не нарушает структуру URI. (Версионирование в URI: /api/v1/users, /api/v2/users)
  • Сохранять семантики HTTP-кодов и методов для существующих эндпоинтов

Обратная совместимость в gRPC

gRPC использует Protocol Buffers (protobuf). Он изначально учитывает обратную совместимость.

Что может сломать совместимость:

  • Переиспользование удалённых тегов.
  • Изменение типа поля.
  • Удаление метода из сервиса.

Практики:

  • Добавлять новые поля с уникальными номерами тегов.
  • Делать поля optional.
  • Не удалять старые поля, помечать их deprecated.
  • Никогда не менять значения tag-ID.
  • При необходимости переименования — объявлять новое поле с новым tag.
  • Версионировать proto-файлы (package v1, v2).

Обратная совместимость в GraphQL

GraphQL более гибкий, чем REST, так как клиент сам выбирает нужные поля. Но есть риски.

Безопасные изменения:

  • Добавление новых типов и новых полей в существующие типы.
  • Добавление новых аргументов с дефолтными значениями.

Что может сломать совместимость:

  • Удаление полей.
  • Изменение типа существующего поля (например, с String на Int).
  • Сделать необязательный аргумент обязательным (например, необязательное поле (String) исправить на обязательное (String!) для аргументов запроса)

Практики:

  • Использовать директиву @deprecated вместо удаления. Клиенты будут видеть предупреждение.
  • Избегать изменений типов существующих полей
  • Поддерживать старые поля до тех пор, пока все клиенты не перейдут.
  • Для больших изменений — новая схема (например, /graphql/v2).

Примечание: изменение логики в резолвере (например, изменение формулы вычисления поля) может сломать ожидания клиента, даже если схема не изменилась.

Обратная совместимость в асинхронных брокерах

Apache Kafka

Kafka — шина событий. Здесь контракт — это формат сообщения.. Если продюсер изменил структуру, все консумеры должны понимать новый формат.

Schema Registry

Для Apache Kafka - это модуль Confluent

  • Schema Registry - централизованный сервис для хранения и управления схемами. Поддержка форматов: Avro, Protobuf, JSON Schema.
  • При регистрации новой схемы Schema Registry проверяет ее на совместимость со старой.

Практики:

  • Использование Schema Registry для управления схемами
  • Применение политик совместимости:
    • Backward — новые сообщения читают старые консумеры.
    • Forward — новые консумеры читают старые сообщения.
    • Full— поддерживаются оба направления.
  • Возможность перечитывания исторических данных
  • Добавлять новые поля с дефолтами.
  • Не менять типы полей.
  • Не удалять поля без "депрекейта".
  • Для критичных изменений — новый топик (orders.v2).

RabbitMQ

В отличие от Kafka, здесь нет встроенного Schema Registry, поэтому контроль контрактов - на разработчиках.

Риски:

  • Каждый продюсер и консумер должен явно согласовывать формат.
  • Изменение payload ломает всех подписчиков.

Практики:

  • Валидация по схеме на стороне производителя и потребителя
  • Версионирование в теле сообщения. Например, "metadata": {"schema_version": "1.2.0"}.
  • Использование content-type для указания формата. Например, content_type = "application/vnd.mycompany.order.v2+json"
  • Поддержка нескольких форматов в переходный период.
  • Использование разных очередей для несовместимых версий
  • Договорённость об изменениях: добавляем поля, не трогаем старые.

Сводная таблица подходов

ИнструментГде ломается чащеКонтроль контрактовПоддержка версионированияПрактики
RESTИзменения JSON, удаление полейOpenAPI/SwaggerURL, headers, paramsДобавлять, не менять; депрекейт; версии API
gRPCНеправильное изменение proto-файлаProtobuf compilerPackage v1/v2Не трогать теги; новые поля; депрекейт
GraphQLУдаление/изменение полейGraphQL schemaНовая версия схемы@deprecated; постепенная эволюция
KafkaИзменение схем сообщенийSchema RegistryНовый топикBackward schema; новые поля; дефолты
RabbitMQИзменение payloadНет встроенногоВручнуюВерсия в payload; content-type; поддержка нескольких форматов

Материалы

  1. Обеспечение обратной совместимости gRPC API с помощью protolock в GitHub Actions
  2. Постановка проблемы обратной совместимости
  3. Интеграции глазами аналитика: 5 типичных ошибок, которые ломают систему
  4. Что такое обратная совместимость
  5. Как правильно разрабатывать API с поддержкой обратной совместимости. Семинар в Яндексе
  6. GraphQL: от восторга до разочарования
  7. API без версий — делаем API обратно совместимыми НАВСЕГДА, чтобы позволить бизнесу сотрудничать
  8. Типы совместимости в Schema Registry для Apache Kafka
  9. Как мы Schema Registry для Kafka настраивали, и что могло пойти не так…
  10. Управление схемами в Kafka с использованием Schema Registry
  11. Как работают клиенты реестра схем Apache Kafka: подробный разбор
  12. Лучшие практики для надёжной работы с RabbitMQ
  13. confluent_kafka API documentation (en)
  14. Confluent REST Proxy for Apache Kafka (en)
  15. Kafka как интеграционная платформа: от источников данных к потребителям и в хранилище (часть 1)

Видео

  1. Подкаст: Версионирование API. Обратная совместимость в API
  2. ИТМО Микросервисы - лекция 10 - Эволюционирование API, обратная совместимость, форматы данных
  3. Михаил Ершов — Разработка совместимого API
  4. Евгений Калинин, Александр Лампель — Обратная совместимость, инструменты и подходы
  5. Как спроектировать хороший api: 20 лучших практик

Конференции

  1. Analystdays: Обратная совместимость за пределами API
  2. MoscowJS 35: Как не сломать обратную совместимость в Public API — Виктор Розаев

Книги

  1. API - Сергей Константинов (Раздел III. Обратная совместимость)
  2. Высоконагруженные приложения. Программирование, масштабирование, поддержка - Мартин Клеппман