Микросервисы: опыт
использования в
нагруженном проекте
Вадим Мадисон

М-Тех
• Услуги системной интеграции, начиная от разработки
технологических решений и заканчивая доставкой видео-сигнала до
конечного пользователя
• Интернет-видеоплатформа для каналов МатчТВ и НТВ-ПЛЮС
• 300 000 одновременных пользователей
• > 1 000 000 уникальных посетителей в сутки
• Отдаем контента до 300 Тб/час
Про что эта история?
История про …
• Рост проекта
• Развитие
• Переосмысление работы системы и отдельных компонентов
История про …
Масштабирование
Пройденный путь
Начало времен
• 2 сервера в docker-кластере
• DB запускается на тех же машинах, в контейнерах
• Выделенного хранилища как такового нет
• Инфраструктура минимальна
Docker TeamCity
Середина пути
• 80 серверов в docker-кластере
• Хранилище на базе CEPH
• DB запускается на отдельных серверах
• Пересмотр взаимодействия между сервисами
• Выделенный мониторинг
Наши дни
• Несколько сотен серверов в docker-кластере
• Сотни запущенных микросервисов
• Выделение сервисов в отдельные зоны
• Кластеризация шин обмена сообщениями между сервисами
Транспорт
Транспорт
protobuf → gRPC → JSON
protobuf
Плюсы
• Достаточно компактен
• Есть быстрые реализации
• Условно типизирован
Минусы
• протокол становится
“проприетарным”
• требуется поддерживать в
актуальном состоянии
утилиты для обращению к
сервису
protobuf
Плюсы
• Достаточно компактен
• Есть быстрые реализации
• Условно типизирован
Минусы
• протокол становится
“проприетарным”
• требуется поддерживать в
актуальном состоянии
утилиты для обращения к
сервису
Транспорт
protobuf → gRPC → JSON
Docker TeamCity
gRPC
Плюсы
• HTTP/2
• Эффективность передачи
• Работает из коробки
• Поддержка основных
серверных языков
• Поддержка основных
клиентских языков
Минусы
• Вещь в себе
• Сложность реализации
собственной логики
• Доступ к логам через
собственные обертки и
парсеры
• Сложность работы в
динамичной среде
gRPC
Плюсы
• HTTP/2
• Эффективность передачи
• Работает из коробки
• Поддержка основных
серверных языков
• Поддержка основных
клиентских языков
Минусы
• Вещь в себе
• Сложность реализации
собственной логики
• Доступ к логам через
собственные обертки и
парсеры
• Усиливает зависимости
между сервисами
• Сложно версионируется
Транспорт
protobuf → gRPC → JSON
Docker TeamCity JSON
JSON
Плюсы
• “Можно” HTTP/2
• Есть очень быстрые
реализации
• Поддержка повсеместно
• Не требуется разрабатывать
дополнительный
инструментарий
• Позволяется работать с
“частью данных”
JSON
Плюсы
• “Можно” HTTP/2
• Есть очень быстрые
реализации
• Поддержка повсеместно
• Не требуется разрабатывать
дополнительный
инструментарий
• Позволяется работать с
“частью данных”
Минусы
• Не компактен
• Не типизирован
Версионирование протокола
Версионирование протокола
V1,V2,… → V1 + schema
Версионирование протокола
V1,V2,… → V1 + schema
/api/v1/content
/api/v2/content → /api/v1/content + JSON Schema v1.X
/api/v3/content
{
"id": "507f1f77bcf86cd7994390",
"projectId": "507f1f77bcf86cd7994390",
"content": "broadcast",
"name": "Жопоног - Газмяз",
"date" : {
"start": "2005-08-09T18:31:42-03:30",
"end": "2005-08-09T18:31:42-03:30"
},
"source": "http://.../playlist.m3u8",
"extra": {
"videoType": "хоккей",
"description": "Чемпионат мира по

гребной травле тараканов"
},
"listeningStatus": "fail",
"status": "enabled"
}
{
"id": "507f1f77bcf86cd7994390",
"projectId": "507f1f77bcf86cd7994390",
"content": "broadcast",
"name": "Жопоног - Газмяз",
"date" : {
"start": "2005-08-09T18:31:42-03:30",
"end": "2005-08-09T18:31:42-03:30"
},
"source": "http://.../playlist.m3u8",
"extra": {
"videoType": "хоккей",
"description": "Чемпионат мира по

гребной травле тараканов ;)"
},
"listeningStatus": "fail",
"status": "enabled"
}
{
"$schema": "…",
"type": "object",
"properties": {
"id": { "type": "string" },
"content": { "type": "string" },
"date": {
"type": "object",
"properties": {
"start": { "type": "string" },
"end": { "type": "string" }
},
"required": ["start","end"]
},
"source": { "type": "string" },
"status": { "type": "string" },

…
},
"required": ["id", "content", 

"date", "status"]
}
{
"id": "507f1f77bcf86cd7994390",
"content": "broadcast",
"date" : {
"start": "2005-08-09T18:31:42-03:30",
"end": "2005-08-09T18:31:42-03:30"
},
"status": "enabled"
}
{
"$schema": "…",
"type": "object",
"properties": {
"id": { "type": "string" },
"content": { "type": "string" },
"date": {
"type": "object",
"properties": {
"start": { "type": "string" },
"end": { "type": "string" }
},
"required": ["start","end"]
},
"source": { "type": "string" },
"status": { "type": "string" },

…
},
"required": ["id", "content", 

"date", "status"]
}
Стабильность работы
Docker TeamCity JSON Grafana
Выводы
• Основная проблема — частично работающий сервис
• Мертвый сервис - хорошо!
• Каждый сервис должен знать свой лимит (Rate limit)!
• Защита - паттерн Circuit Breaker
Выводы
• Основная проблема — частично работающий сервис
• Мертвый сервис — хорошо!
• Каждый сервис должен знать свой лимит (Rate limit)!
• Защита - паттерн Circuit Breaker
Выводы
• Основная проблема — частично работающий сервис
• Мертвый сервис — хорошо!
• Каждый сервис должен знать свой лимит (Rate limit)!
• Защита - паттерн Circuit Breaker
Выводы
• Основная проблема — частично работающий сервис
• Мертвый сервис — хорошо!
• Каждый сервис должен знать свой лимит (Rate limit)!
• Защита — паттерн Circuit Breaker
Docker TeamCity JSON Grafana
Hystrix
Исполнение запроса
1 2 3
4 5
Docker TeamCity JSON Grafana
HystrixAppdash
Docker TeamCity JSON Grafana
Hystrix
общее время
общее время
Обращение к БД

внутри сервиса
TraceID: 19502dcb3e187d615eacf73a0ba1bfe0
Docker TeamCity JSON Grafana
HystrixOpentracing
Логирование
Docker TeamCity JSON Grafana
HystrixOpentracingElastic + Kibana
Логирование: сбор логов
Логирование
• добавляем TraceID в логи
• строим Dashboard фильтром по TraceID
• динамический DEBUG MODE
Логирование
• добавляем TraceID в логи
• строим Dashboard фильтром по TraceID
• динамический DEBUG MODE
Агрегирование ошибок
Docker TeamCity JSON Grafana
HystrixOpentracingElastic + Kibana
Sentry
Масштабирование
Docker TeamCity JSON Grafana
HystrixOpentracingElastic + Kibana
Sentry Nomad
Docker TeamCity JSON Grafana
HystrixOpentracingElastic + Kibana
Sentry Consul VaultNomad
Docker TeamCity JSON Grafana
HystrixOpentracingElastic + Kibana
Sentry Consul VaultKubernetes
Стандартизация: RAM-CPU-NET
Стандартизация: R3-C2-N1
Стандартизация: матрица размерностей
CPU RAM NET
C1 = 500 MHz R1 = 128 MB N1 = 10 Mb
C2 = 1000 MHz R2 = 256 MB N2 = 100 Mb
C3 = 3000 Mhz R3 = 512 MB N3 = 1 Gb
Стандартизация
•N1C3R1 → [10 Mb] [3000 MHz] [128 MB]
•N1C2R3 → [10 Mb] [1500 MHz] [1 GB]
Стандартизация
•N1C3R1 → [10 Mb] [3000 MHz] [128 MB]
•N1C2R3 → [10 Mb] [1000 MHz] [1 GB]
Подготовка: тип масштабируемости
• Сервис полностью независим
→ тестируем предел для одного инстанса
→ тестируем 2 инстанса, чтобы проверить линейность

• Масштабируемость зависит от внешних ресурсов
→ при нагрузочном тестировании проводим

несколько раундов тестирования с увеличением 

количества инстансов

• Масштабируемость ограничена определенным лимитом
→ порог указывается в точке конфигурирования сервиса
Подготовка: тип масштабируемости
• Сервис полностью независим
→ тестируем предел для одного инстанса
→ тестируем 2 инстанса, чтобы проверить линейность

• Масштабируемость зависит от внешних ресурсов
→ при нагрузочном тестировании проводим

несколько раундов тестирования с увеличением 

количества инстансов

• Масштабируемость ограничена определенным лимитом
→ порог указывается в точке конфигурирования сервиса
Подготовка: тип масштабируемости
• Сервис полностью независим
→ тестируем предел для одного инстанса
→ тестируем 2 инстанса, чтобы проверить линейность

• Масштабируемость зависит от внешних ресурсов
→ при нагрузочном тестировании проводим

несколько раундов тестирования с увеличением 

количества инстансов

• Масштабируемость ограничена определенным лимитом
→ порог указывается в точке конфигурирования сервиса
Подготовка: нагрузочное тестирование
Docker JSON Grafana
HystrixOpentracingElastic + Kibana
Sentry Consul VaultKubernetes Gitlab CI
TeamCity
Рекомендации
• Начинайте разработку сразу с использованием системы
оркестрации
• В каждый момент времени помните, что каждого инстанса
сервиса должно быть не меньше 2-х
• Шина сообщений, блокировки и очереди - наше все
• Не нужно пытаться поднять/починить сервис - нужно
отстрелить его и потом попробовать понять, что не так
• Собирайте метрики и работайте с ними
• Выдавайте алерты только там, где требуется реакция
Рекомендации
• Начинайте разработку сразу с использованием системы
оркестрации
• В каждый момент времени помните, что каждого инстанса
сервиса должно быть не меньше 2-х
• Шина сообщений, блокировки и очереди - наше все
• Не нужно пытаться поднять/починить сервис - нужно
отстрелить его и потом попробовать понять, что не так
• Собирайте метрики и работайте с ними
• Выдавайте алерты только там, где требуется реакция
Рекомендации
• Начинайте разработку сразу с использованием системы
оркестрации
• В каждый момент времени помните, что каждого инстанса
сервиса должно быть не меньше 2-х
• Шина сообщений, блокировки и очереди — наше все
• Не нужно пытаться поднять/починить сервис - нужно
отстрелить его и потом попробовать понять, что не так
• Собирайте метрики и работайте с ними
• Выдавайте алерты только там, где требуется реакция
Рекомендации
• Начинайте разработку сразу с использованием системы
оркестрации
• В каждый момент времени помните, что каждого инстанса
сервиса должно быть не меньше 2-х
• Шина сообщений, блокировки и очереди — наше все
• Не нужно пытаться поднять/починить сервис — нужно
отстрелить его и потом попробовать понять, что не так
• Собирайте метрики и работайте с ними
• Выдавайте алерты только там, где требуется реакция
Рекомендации
• Начинайте разработку сразу с использованием системы
оркестрации
• В каждый момент времени помните, что каждого инстанса
сервиса должно быть не меньше 2-х
• Шина сообщений, блокировки и очереди — наше все
• Не нужно пытаться поднять/починить сервис — нужно
отстрелить его и потом попробовать понять, что не так
• Собирайте метрики и работайте с ними
• Выдавайте алерты только там, где требуется реакция
Рекомендации
• Начинайте разработку сразу с использованием системы
оркестрации
• В каждый момент времени помните, что каждого инстанса
сервиса должно быть не меньше 2-х
• Шина сообщений, блокировки и очереди — наше все
• Не нужно пытаться поднять/починить сервис — нужно
отстрелить его и потом попробовать понять, что не так
• Собирайте метрики и работайте с ними
• Выдавайте алерты только там, где требуется реакция
Спасибо!
Вадим Мадисон
М-Тех
vadim.madison@gmail.com
vmadison@media-t.ru

Микросервисы: опыт использования в нагруженном проекте / Вадим Мадисон (М-Тех)

  • 1.
  • 2.
    • Услуги системнойинтеграции, начиная от разработки технологических решений и заканчивая доставкой видео-сигнала до конечного пользователя • Интернет-видеоплатформа для каналов МатчТВ и НТВ-ПЛЮС • 300 000 одновременных пользователей • > 1 000 000 уникальных посетителей в сутки • Отдаем контента до 300 Тб/час
  • 3.
    Про что этаистория?
  • 4.
    История про … •Рост проекта • Развитие • Переосмысление работы системы и отдельных компонентов
  • 5.
  • 6.
  • 7.
    Начало времен • 2сервера в docker-кластере • DB запускается на тех же машинах, в контейнерах • Выделенного хранилища как такового нет • Инфраструктура минимальна
  • 8.
  • 9.
    Середина пути • 80серверов в docker-кластере • Хранилище на базе CEPH • DB запускается на отдельных серверах • Пересмотр взаимодействия между сервисами • Выделенный мониторинг
  • 10.
    Наши дни • Несколькосотен серверов в docker-кластере • Сотни запущенных микросервисов • Выделение сервисов в отдельные зоны • Кластеризация шин обмена сообщениями между сервисами
  • 12.
  • 13.
  • 15.
    protobuf Плюсы • Достаточно компактен •Есть быстрые реализации • Условно типизирован Минусы • протокол становится “проприетарным” • требуется поддерживать в актуальном состоянии утилиты для обращению к сервису
  • 16.
    protobuf Плюсы • Достаточно компактен •Есть быстрые реализации • Условно типизирован Минусы • протокол становится “проприетарным” • требуется поддерживать в актуальном состоянии утилиты для обращения к сервису
  • 17.
  • 18.
  • 19.
    gRPC Плюсы • HTTP/2 • Эффективностьпередачи • Работает из коробки • Поддержка основных серверных языков • Поддержка основных клиентских языков Минусы • Вещь в себе • Сложность реализации собственной логики • Доступ к логам через собственные обертки и парсеры • Сложность работы в динамичной среде
  • 20.
    gRPC Плюсы • HTTP/2 • Эффективностьпередачи • Работает из коробки • Поддержка основных серверных языков • Поддержка основных клиентских языков Минусы • Вещь в себе • Сложность реализации собственной логики • Доступ к логам через собственные обертки и парсеры • Усиливает зависимости между сервисами • Сложно версионируется
  • 21.
  • 22.
  • 23.
    JSON Плюсы • “Можно” HTTP/2 •Есть очень быстрые реализации • Поддержка повсеместно • Не требуется разрабатывать дополнительный инструментарий • Позволяется работать с “частью данных”
  • 24.
    JSON Плюсы • “Можно” HTTP/2 •Есть очень быстрые реализации • Поддержка повсеместно • Не требуется разрабатывать дополнительный инструментарий • Позволяется работать с “частью данных” Минусы • Не компактен • Не типизирован
  • 25.
  • 26.
  • 27.
    Версионирование протокола V1,V2,… →V1 + schema /api/v1/content /api/v2/content → /api/v1/content + JSON Schema v1.X /api/v3/content
  • 28.
    { "id": "507f1f77bcf86cd7994390", "projectId": "507f1f77bcf86cd7994390", "content":"broadcast", "name": "Жопоног - Газмяз", "date" : { "start": "2005-08-09T18:31:42-03:30", "end": "2005-08-09T18:31:42-03:30" }, "source": "http://.../playlist.m3u8", "extra": { "videoType": "хоккей", "description": "Чемпионат мира по
 гребной травле тараканов" }, "listeningStatus": "fail", "status": "enabled" }
  • 29.
    { "id": "507f1f77bcf86cd7994390", "projectId": "507f1f77bcf86cd7994390", "content":"broadcast", "name": "Жопоног - Газмяз", "date" : { "start": "2005-08-09T18:31:42-03:30", "end": "2005-08-09T18:31:42-03:30" }, "source": "http://.../playlist.m3u8", "extra": { "videoType": "хоккей", "description": "Чемпионат мира по
 гребной травле тараканов ;)" }, "listeningStatus": "fail", "status": "enabled" } { "$schema": "…", "type": "object", "properties": { "id": { "type": "string" }, "content": { "type": "string" }, "date": { "type": "object", "properties": { "start": { "type": "string" }, "end": { "type": "string" } }, "required": ["start","end"] }, "source": { "type": "string" }, "status": { "type": "string" },
 … }, "required": ["id", "content", 
 "date", "status"] }
  • 30.
    { "id": "507f1f77bcf86cd7994390", "content": "broadcast", "date": { "start": "2005-08-09T18:31:42-03:30", "end": "2005-08-09T18:31:42-03:30" }, "status": "enabled" } { "$schema": "…", "type": "object", "properties": { "id": { "type": "string" }, "content": { "type": "string" }, "date": { "type": "object", "properties": { "start": { "type": "string" }, "end": { "type": "string" } }, "required": ["start","end"] }, "source": { "type": "string" }, "status": { "type": "string" },
 … }, "required": ["id", "content", 
 "date", "status"] }
  • 31.
  • 33.
  • 34.
    Выводы • Основная проблема— частично работающий сервис • Мертвый сервис - хорошо! • Каждый сервис должен знать свой лимит (Rate limit)! • Защита - паттерн Circuit Breaker
  • 35.
    Выводы • Основная проблема— частично работающий сервис • Мертвый сервис — хорошо! • Каждый сервис должен знать свой лимит (Rate limit)! • Защита - паттерн Circuit Breaker
  • 36.
    Выводы • Основная проблема— частично работающий сервис • Мертвый сервис — хорошо! • Каждый сервис должен знать свой лимит (Rate limit)! • Защита - паттерн Circuit Breaker
  • 37.
    Выводы • Основная проблема— частично работающий сервис • Мертвый сервис — хорошо! • Каждый сервис должен знать свой лимит (Rate limit)! • Защита — паттерн Circuit Breaker
  • 38.
    Docker TeamCity JSONGrafana Hystrix
  • 41.
  • 42.
  • 44.
    Docker TeamCity JSONGrafana HystrixAppdash
  • 46.
    Docker TeamCity JSONGrafana Hystrix
  • 47.
  • 48.
    общее время Обращение кБД
 внутри сервиса
  • 49.
  • 50.
    Docker TeamCity JSONGrafana HystrixOpentracing
  • 51.
  • 52.
    Docker TeamCity JSONGrafana HystrixOpentracingElastic + Kibana
  • 53.
  • 54.
    Логирование • добавляем TraceIDв логи • строим Dashboard фильтром по TraceID • динамический DEBUG MODE
  • 55.
    Логирование • добавляем TraceIDв логи • строим Dashboard фильтром по TraceID • динамический DEBUG MODE
  • 56.
  • 57.
    Docker TeamCity JSONGrafana HystrixOpentracingElastic + Kibana Sentry
  • 58.
  • 59.
    Docker TeamCity JSONGrafana HystrixOpentracingElastic + Kibana Sentry Nomad
  • 60.
    Docker TeamCity JSONGrafana HystrixOpentracingElastic + Kibana Sentry Consul VaultNomad
  • 61.
    Docker TeamCity JSONGrafana HystrixOpentracingElastic + Kibana Sentry Consul VaultKubernetes
  • 62.
  • 63.
  • 64.
    Стандартизация: матрица размерностей CPURAM NET C1 = 500 MHz R1 = 128 MB N1 = 10 Mb C2 = 1000 MHz R2 = 256 MB N2 = 100 Mb C3 = 3000 Mhz R3 = 512 MB N3 = 1 Gb
  • 65.
    Стандартизация •N1C3R1 → [10Mb] [3000 MHz] [128 MB] •N1C2R3 → [10 Mb] [1500 MHz] [1 GB]
  • 66.
    Стандартизация •N1C3R1 → [10Mb] [3000 MHz] [128 MB] •N1C2R3 → [10 Mb] [1000 MHz] [1 GB]
  • 67.
    Подготовка: тип масштабируемости •Сервис полностью независим → тестируем предел для одного инстанса → тестируем 2 инстанса, чтобы проверить линейность
 • Масштабируемость зависит от внешних ресурсов → при нагрузочном тестировании проводим
 несколько раундов тестирования с увеличением 
 количества инстансов
 • Масштабируемость ограничена определенным лимитом → порог указывается в точке конфигурирования сервиса
  • 68.
    Подготовка: тип масштабируемости •Сервис полностью независим → тестируем предел для одного инстанса → тестируем 2 инстанса, чтобы проверить линейность
 • Масштабируемость зависит от внешних ресурсов → при нагрузочном тестировании проводим
 несколько раундов тестирования с увеличением 
 количества инстансов
 • Масштабируемость ограничена определенным лимитом → порог указывается в точке конфигурирования сервиса
  • 69.
    Подготовка: тип масштабируемости •Сервис полностью независим → тестируем предел для одного инстанса → тестируем 2 инстанса, чтобы проверить линейность
 • Масштабируемость зависит от внешних ресурсов → при нагрузочном тестировании проводим
 несколько раундов тестирования с увеличением 
 количества инстансов
 • Масштабируемость ограничена определенным лимитом → порог указывается в точке конфигурирования сервиса
  • 70.
  • 74.
    Docker JSON Grafana HystrixOpentracingElastic+ Kibana Sentry Consul VaultKubernetes Gitlab CI TeamCity
  • 75.
    Рекомендации • Начинайте разработкусразу с использованием системы оркестрации • В каждый момент времени помните, что каждого инстанса сервиса должно быть не меньше 2-х • Шина сообщений, блокировки и очереди - наше все • Не нужно пытаться поднять/починить сервис - нужно отстрелить его и потом попробовать понять, что не так • Собирайте метрики и работайте с ними • Выдавайте алерты только там, где требуется реакция
  • 76.
    Рекомендации • Начинайте разработкусразу с использованием системы оркестрации • В каждый момент времени помните, что каждого инстанса сервиса должно быть не меньше 2-х • Шина сообщений, блокировки и очереди - наше все • Не нужно пытаться поднять/починить сервис - нужно отстрелить его и потом попробовать понять, что не так • Собирайте метрики и работайте с ними • Выдавайте алерты только там, где требуется реакция
  • 77.
    Рекомендации • Начинайте разработкусразу с использованием системы оркестрации • В каждый момент времени помните, что каждого инстанса сервиса должно быть не меньше 2-х • Шина сообщений, блокировки и очереди — наше все • Не нужно пытаться поднять/починить сервис - нужно отстрелить его и потом попробовать понять, что не так • Собирайте метрики и работайте с ними • Выдавайте алерты только там, где требуется реакция
  • 78.
    Рекомендации • Начинайте разработкусразу с использованием системы оркестрации • В каждый момент времени помните, что каждого инстанса сервиса должно быть не меньше 2-х • Шина сообщений, блокировки и очереди — наше все • Не нужно пытаться поднять/починить сервис — нужно отстрелить его и потом попробовать понять, что не так • Собирайте метрики и работайте с ними • Выдавайте алерты только там, где требуется реакция
  • 79.
    Рекомендации • Начинайте разработкусразу с использованием системы оркестрации • В каждый момент времени помните, что каждого инстанса сервиса должно быть не меньше 2-х • Шина сообщений, блокировки и очереди — наше все • Не нужно пытаться поднять/починить сервис — нужно отстрелить его и потом попробовать понять, что не так • Собирайте метрики и работайте с ними • Выдавайте алерты только там, где требуется реакция
  • 80.
    Рекомендации • Начинайте разработкусразу с использованием системы оркестрации • В каждый момент времени помните, что каждого инстанса сервиса должно быть не меньше 2-х • Шина сообщений, блокировки и очереди — наше все • Не нужно пытаться поднять/починить сервис — нужно отстрелить его и потом попробовать понять, что не так • Собирайте метрики и работайте с ними • Выдавайте алерты только там, где требуется реакция
  • 81.