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

Лимитируй это

Лимитируй это

Однажды я провел день на колоссальном девятичасовом созвоне в попытке понять «а почему продакшн не работает?» и выводы, которые я вынес из этого дебага, я хочу принести вам в этом докладе.

Что же у нас за система? Мы делаем чат, это современная event-driven архитектура, все наши бэкенды — это rest-like части на fastapi и основная часть системы базируется на kafka продюсерах/консьюмерах. Весь наш код асинхронный, а баз две штуки — postgres и keydb.

Моя история будет о том:
— как уронить keydb;
— как kafka может уничтожить ваше асинхронное приложение;
— как неправильно планировать ресурсы в кубер кластере;
— как можно покалечиться всей системой, если у тебя кривая библиотека для работы с БД;
— какие мониторинги делать обязательно;
— что такое плохой healtcheck;
— почему документация может быть очень коварной.

Доклад стыдный, но, надеюсь, полезный!

Avatar for Denis Anikin

Denis Anikin

July 31, 2023
Tweet

More Decks by Denis Anikin

Other Decks in Programming

Transcript

  1. Денис Аникин 2 Что я делаю — работаю в Райфе

    — teamlead в 3 командах — community lead в Python Community — fullstack: typescript, python, devops — шучу шутки со средней оценкой 4 балла https://xfenix.ru
  2. Денис Аникин 3 Что я делаю — работаю в Райфе

    — teamlead в 3 командах — community lead в Python Community — fullstack: typescript, python, devops — шучу шутки со средней оценкой 4 балла ИЗ 100 https://xfenix.ru
  3. Что у нас за система? 6 — Распределенная — Чат

    — Две основных базы данных: KeyDB (redis) & PostgreSQL — Наш MQ это Kafka — Пишем на FastAPI, Starlette — НЕ ХАЙЛОАД (!!!11) — Ну конечно же любимые и ненавистные всем микросервисы (настоящие)
  4. Пару слов о «НЕ ХАЙЛОАД» 7 — Порядок: сотни RPS

    от пользователей — Система постоянной доступности (непрерывный режим работы) — «Последняя» линия, к нам приходят когда уже что-то сломалось
  5. Ещё пару слов обо мне 12 — У меня не

    очень много опыта с распределенными и особенно event driven системами — Я не идеально разбираюсь в мониторинге
  6. Ещё пару слов обо мне 14 — У меня не

    очень много опыта с распределенными и особенно event driven системами — Я не идеально разбираюсь в мониторинге — Kubernetes на момент разработки системы был для меня новой технологией
  7. По полям, по полям архитектор едет к нам! Так как

    в докладе будет много хороших решений и классных практик…
  8. Но зачем столько соединений-то? 39 Ну правда! — Корутины! —

    Распределенная система — Куча реплик — Несколько зон доступности — И секретный ингредиент!
  9. Немного о пулинге 49 Пулинг — прекрасно, но если вы

    его конфигурируете правильно — В документации Sentinel клиента ни слова о пулинге — Но самый сок нас ожидает под капотом…
  10. 50 Цитата из redis-py (aioredis туда вмержен) def __init__( …

    max_connections: Optional[int] = None, … ): max_connections = max_connections or 2 ** 31 # ß Добрый вечер! С sentinel сработает вот так
  11. 51 Вот вам и Redis Cluster class redis.asyncio.cluster.RedisCluster(host=None, port=6379, startup_nodes=None,

    require_full_coverage=True, read_from_replicas=False, reinitialize_steps=5, cluster_error_retry_attempts=3, connection_error_retry_attempts=3, max_connections=2147483648, # ß Привет! Как дела? Спишь? Наберу? db=0, path=None, credential_provider=None, username=None, password=None, client_name=None, encoding='utf-8', encoding_errors='strict', decode_responses=False, health_check_interval=0, socket_connect_timeout=None, socket_keepalive=False, socket_keepalive_options=None, socket_timeout=None, retry=None, retry_on_error=None, ssl=False, ssl_ca_certs=None, ssl_ca_data=None, ssl_cert_reqs='required', ssl_certfile=None, ssl_check_hostname=False, ssl_keyfile=None, address_remap=None)
  12. Тут всё довольно скромно 55 — Наш consumer потребляет сообщение

    — Создает обработчик с помощью create_task — Идёт дальше
  13. Пулинг Очень много корутин Один знаменитый программист сказал: it’s get

    crashing, when I pull (pull из pool’а соединений имеется ввиду)
  14. Давайте глянем как оно там без них 61 — По

    началу неплохо — Но когда что-то пойдет не так… — Пожалуйста, проставляйте реквесты и лимиты!!1111
  15. Прежде чем говорить, предыдущие пункты 64 — Что-то замедляет обработку

    топика (возможно, краш) — Мы не видим топик лаг, ребутаемся — Корутины плодятся без всяких на то ограничений — Коннекшены «хватаются» из пула огромными пачками — Мы и об этом не знаем — KeyDB умирает, уничтоженный в щепки — В кластере плохеет нодам, ложатся соседние сервисы (не все!)
  16. И добиваем лоу-киком 67 Чтобы KeyDB не имел шанса подняться

    и всем было веселее, мы сверху полируем реконнектами… …в каждой корутине
  17. Как не стоить делать хелсчеки консьюмеров 74 — Берем асинхронный

    консьюмер — Рядом в треде запускаем асинхронный фреймворк с одной ручкой — Вешаем пробу на эту ручку
  18. 77 Что же может пойти не так? Я, пытающийся понять

    почему topiclag 10055000, консьюмеры мертвее моей архитектурной карьеры, а хелсчеки говорят Мой продакшн
  19. Есть такая классическая проблема в EDA 80 Довольно классическая —

    К нам приходит сообщение в консьюмер — Мы обрабатываем это сообщение, но у нас не выходит — Что же делать?
  20. А как это делать когда ничего непонятно? 90 Есть пару

    простых идей — Проставьте минимальное значение для requests, ниже которого сервис не будет работать совсем — Проставьте limits в 2-3 раза выше (в зависимости от ваших возможностей) — Дальше двигайтесь итерационно, либо с помощью нагрузочного тестирования, либо докидывая limits в процессе жизни (что более нервно) — Не забывайте мониторить throttling!
  21. Что будет, если неправильно сконфигурить 92 Ну кроме очевидного «пока,

    мой любимый кластер, мне так нравилось спать в 3 ночи» — Наш добрый дружок ООМ — CPU-«голодание» — «Выселение» подов — Трата лишних ресурсов
  22. Что можно было бы мониторить ещё 95 Но что мы

    пока не мониторим — Количество sent запросов — Количество received запросов — Время/продолжительность отправки — Время/продолжительность потребления — RPS
  23. Когда мы поняли, что дело в нём 100 А понять

    было ОЧЕНЬ непросто на самом деле (ведь корутины мы не мониторим) — Долго обсуждал — И в конце я вспомнил, что в asyncio есть Semaphore!
  24. Пару мыслей по корутинам 102 — Concurrency — штука коварная,

    имеет смысл ограничивать количество create_task — Semaphore и другие примитивы синхронизации вам бро! — Возможно, вам может быть полезен aiomonitor!
  25. Моя любимая панацея! 104 — Можно просто раз в сутки

    ребутать все контейнеры — Сделать очень просто: берёте gitlab scheduled ci и делаете с помощью kubectl rollout и/или helm — Не убегайте из зала с воплями ужаса, это правда экономит кучу нервных клеток — Не будем забывать о chaos engineering
  26. Пару слов о том, что не полечили 107 — retry.

    Тут стоило бы затащить circuit breaker! — healtcheck. В интернете ноль адекватных советов на эту тему, кстати — Не продумали стратегию backpressure когда retry не справляется (eviction/drop? delay? buffer?) — Пока не троттлили DLQ
  27. Некоторые ссылки 115 Redis py коммиты (но это не все)

    — https://github.com/redis/redis- py/blob/2732a8553e58d9e77f16566b9132fc7205614a53/redis/asyncio/connection.py#L976 — https://github.com/redis/redis- py/blob/2732a8553e58d9e77f16566b9132fc7205614a53/redis/asyncio/cluster.py#L232 — https://github.com/redis/redis- py/blob/2732a8553e58d9e77f16566b9132fc7205614a53/redis/connection.py#L952