Lock in $30 Savings on PRO—Offer Ends Soon! ⏳

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

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

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

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

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

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

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