Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Как поддерживать согласованность в микросервисн...

Как поддерживать согласованность в микросервисной архитектуре

Как мы поддерживаем согласованность API между микросервисами в ЦИАН.
Выступление на PyCon Russia 2018

Avatar for Maxim Mazaev

Maxim Mazaev

July 23, 2018
Tweet

More Decks by Maxim Mazaev

Other Decks in Programming

Transcript

  1. О ЦИАН - 11 млн покупателей и арендаторов в месяц

    - Ресурс федерального уровня - 10x разработка за 2014-2018 3
  2. 2016 год Монолит на Django 6 2018 год 100+ микросервисов

    Python, С#, Node.js *и остатки монолита
  3. Почему мы используем микросервисы? 9 • Легче поддерживать и релизить

    • Ограниченная зона ответственности • Платформонезависимость
  4. Почему мы используем микросервисы? 10 • Легче поддерживать и релизить

    • Ограниченная зона ответственности • Платформонезависимость • Масштабирование
  5. Почему мы используем микросервисы? 11 • Легче поддерживать и релизить

    • Ограниченная зона ответственности • Платформонезависимость • Масштабирование • Отказоустойчивость
  6. Но есть и проблемы 14 • Накладные расходы на каскадные

    вызовы • Много точек отказа • Сложно поддерживать согласованность
  7. • Не знаем, кто потребитель микросервиса • Мы не защищены

    от одностороннего изменения контракта Проблема согласованности 16
  8. • Не знаем, кто потребитель микросервиса • Мы не защищены

    от одностороннего изменения контракта • Меняется семантика поля существующего контракта, а мы не в курсе Проблема согласованности 17
  9. • Не знаем, кто потребитель микросервиса • Мы не защищены

    от одностороннего изменения контракта • Меняется семантика поля существующего контракта, а мы не в курсе • Сложно поддерживать множество микросервисов Проблема согласованности 18
  10. Контракты API 19 HTTP API - Найти пользователя по ID

    - Получить список объявлений
  11. Контракты API 20 Отчетные события RabbitMQ Информируем внешний мир о

    результатах своей работы - Пользователь сменил тариф - Объявление отредактировано
  12. Проблема №1. Кто клиент API? 22 /api/v1/get_data → /api/v2/get_data Хотим

    обновить всех клиентов и не поддерживать устаревшую версию Но как их найти?
  13. Решение. Фиксируем контракты 23 pip install marshmallow - Описываем Request/Response

    схемы - Сериализуем/Десериализуем - Валидируем
  14. Решение. Фиксируем контракты 24 class CreateUserRequestSchema(Schema): name = fields.String(required=True) age

    = fields.Integer() >>> schema = CreateUserRequestSchema() >>> user = schema.load({'name': 'Ivan'}) <User(name='Ivan')> >>> schema.dump(user) {'name': 'Ivan'}
  15. Запросы к микросервисам 25 # фабрика API-клиентов users_api = Api(‘users’)

    get_user = users_api.make_client( path='/v1/get-user-by-id', method=GET, request_schema=GetUserSchema, response_schema=GetUserResponseSchema, ) user = get_user(id=1)
  16. Решение. Генерируем Swagger 27 m_name = '%s.http.apis' % APP_NAME module

    = importlib.import_module(m_name) for obj in module.__dict__.values(): if isinstance(obj, Api): yield obj Получаем информацию об API-клиентах Генерируем Swagger и отдаем его по адресу <microservice_host>/swagger/
  17. Несогласованность контрактов - боль • Мы знаем все связи между

    микросервисами • Давайте на лету проверять согласованность Проблема №2. Кто сломал API? 29
  18. github/zallek/swagger-diff/ error-code Решение. Сравниваем схемы клиента и сервера 30 В

    методе /api/get-map-data/ есть обязательное поле location, которого нет в microservice-offers delete-object- property-required error-description
  19. Решение. Автотесты 33 Запускаем тесты на проде каждый час Генерируем

    запросы по swagger-схеме Смотрим отчеты в Allure Framework
  20. Хотим: - своевременно обновлять зависимости - всегда иметь под рукой

    swagger Проблема №4. Микросервисов стало слишком много 34
  21. Бонус. Кодогенерация API- клиентов 37 [cian-codegen:users] swagger_url = users.msc.cian.ru/swagger/ output_dir

    = repositories/users_repository paths = /v1/get-user-by-email/ Задача: - Писать меньше кода - Абстрагировать разработчика от HTTP-вызовов
  22. Бонус. Кодогенерация API- клиентов 38 user = get_user_by_email(‘[email protected]’) <User(id=8793874, name='Ivan')>

    Результат: - Генерируем схемы и API-клиенты - Работаем с API сервиса как с обычной функцией
  23. Выводы 42 • Фиксируем схемы запросов • Автоматизируем проверку в

    CI • Пишем функциональные автотесты API • Больше кодогенерации!