Slide 1

Slide 1 text

/ Денис Аникин https://xfenix.ru Лимитируй это

Slide 2

Slide 2 text

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

Slide 3

Slide 3 text

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

Slide 4

Slide 4 text

No content

Slide 5

Slide 5 text

Пару слов о нашей системе

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

Пару слов о «НЕ ХАЙЛОАД» 7 — Порядок: сотни RPS от пользователей — Система постоянной доступности (непрерывный режим работы) — «Последняя» линия, к нам приходят когда уже что-то сломалось

Slide 8

Slide 8 text

И вот однажды мы упали 8

Slide 9

Slide 9 text

No content

Slide 10

Slide 10 text

Моя история — о том как это вышло 10

Slide 11

Slide 11 text

No content

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

4 золотых сигнала Latency, traffic, saturation, errors

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

Все совпадения с реальными людьми — выдуманы 15

Slide 16

Slide 16 text

Если вы беспокоетесь, что чего-то не знаете, посмотрите на меня и вам станет легче 16

Slide 17

Slide 17 text

Какой бывает event driven

Slide 18

Slide 18 text

По полям, по полям архитектор едет к нам! Так как в докладе будет много хороших решений и классных практик…

Slide 19

Slide 19 text

Итак, июнь 2022, пятница 19

Slide 20

Slide 20 text

No content

Slide 21

Slide 21 text

14 часов mob-debug в zoom

Slide 22

Slide 22 text

Наша система не упала, а просто перестала работать 22

Slide 23

Slide 23 text

No content

Slide 24

Slide 24 text

Если вы работаете с монолитом, то знакомо:

Slide 25

Slide 25 text

Микросервисы (вы ждали этой картинки):

Slide 26

Slide 26 text

Но на самом деле:

Slide 27

Slide 27 text

НАКОНЕЦ о наших делах 27

Slide 28

Slide 28 text

KeyDB (redis) мёртв 28

Slide 29

Slide 29 text

No content

Slide 30

Slide 30 text

Хвала failover! (заметили не сразу) 30

Slide 31

Slide 31 text

No content

Slide 32

Slide 32 text

Стоп. А что происходит? 32

Slide 33

Slide 33 text

Мы бъемся головой в лимит соединений! 33

Slide 34

Slide 34 text

Открытие: когда KeyDB упирается в соединения, ну… он падает! 34

Slide 35

Slide 35 text

Давайте вынесем на ретро 35

Slide 36

Slide 36 text

Ошибка номер 1 — мы не мониторим соединения с KeyDB 36

Slide 37

Slide 37 text

KeyDB 37 И мониторинг — Обычно все мониторят память — Количество операций — CPU

Slide 38

Slide 38 text

Сколько соединений по-умолчанию у KeyDB? 38 Давайте проголосуем — 1 000 — 10 000 — 30 000 — не ограничено ✅

Slide 39

Slide 39 text

Но зачем столько соединений-то? 39 Ну правда! — Корутины! — Распределенная система — Куча реплик — Несколько зон доступности — И секретный ингредиент!

Slide 40

Slide 40 text

Ошибка номер 2 — мы не мониторим topic lag 40

Slide 41

Slide 41 text

No content

Slide 42

Slide 42 text

Что такое topic lag и как он выглядит

Slide 43

Slide 43 text

Это был (почти) «добрый» topic lag 43

Slide 44

Slide 44 text

44 Злой выглядел бы вот как-то так:

Slide 45

Slide 45 text

Страшная ситуация: «перезагрузка не помогает» 45

Slide 46

Slide 46 text

No content

Slide 47

Slide 47 text

Ошибка номер 3 — плохо настроенный pooling & шутки от aioredis 47

Slide 48

Slide 48 text

48 4 вида сетапов redis/keydb

Slide 49

Slide 49 text

Немного о пулинге 49 Пулинг — прекрасно, но если вы его конфигурируете правильно — В документации Sentinel клиента ни слова о пулинге — Но самый сок нас ожидает под капотом…

Slide 50

Slide 50 text

50 Цитата из redis-py (aioredis туда вмержен) def __init__( … max_connections: Optional[int] = None, … ): max_connections = max_connections or 2 ** 31 # ß Добрый вечер! С sentinel сработает вот так

Slide 51

Slide 51 text

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)

Slide 52

Slide 52 text

Для high availability (HA), cluster в документации примеры указаны без max_connections! А умолчание вы видели… 52

Slide 53

Slide 53 text

Я пытаюсь сделать устойчивый кластер redis Документация к redis-py 2 ** 31

Slide 54

Slide 54 text

Ошибка номер 4 — мы очень полюбили concurrency с помощью create_task 54

Slide 55

Slide 55 text

Тут всё довольно скромно 55 — Наш consumer потребляет сообщение — Создает обработчик с помощью create_task — Идёт дальше

Slide 56

Slide 56 text

56 Если вспомнить topic lag…

Slide 57

Slide 57 text

Пулинг Очень много корутин Один знаменитый программист сказал: it’s get crashing, when I pull (pull из pool’а соединений имеется ввиду)

Slide 58

Slide 58 text

No content

Slide 59

Slide 59 text

Ошибка номер 5 — requests & limits 59

Slide 60

Slide 60 text

No content

Slide 61

Slide 61 text

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

Slide 62

Slide 62 text

No content

Slide 63

Slide 63 text

Ошибка номер 6 — мы очень очень любили resilience, а особенно реконнекты 63

Slide 64

Slide 64 text

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

Slide 65

Slide 65 text

Цитируя известного художника: «вечеринка движется к каннибализму» 65

Slide 66

Slide 66 text

No content

Slide 67

Slide 67 text

И добиваем лоу-киком 67 Чтобы KeyDB не имел шанса подняться и всем было веселее, мы сверху полируем реконнектами… …в каждой корутине

Slide 68

Slide 68 text

Ты обронил, держи продакшн!

Slide 69

Slide 69 text

Мои архитектурные навыки Моё умение программировать

Slide 70

Slide 70 text

Крепкого здоровья погибшим, остальным либа backoff 70

Slide 71

Slide 71 text

Ошибка номер 7 — 71

Slide 72

Slide 72 text

Я — терминатор от мира архитектуры

Slide 73

Slide 73 text

Ошибка номер 7 — великолепные healtcheck’и 73

Slide 74

Slide 74 text

Как не стоить делать хелсчеки консьюмеров 74 — Берем асинхронный консьюмер — Рядом в треде запускаем асинхронный фреймворк с одной ручкой — Вешаем пробу на эту ручку

Slide 75

Slide 75 text

75 Что же может пойти не так?

Slide 76

Slide 76 text

76 Что же может пойти не так? Мой продакшн

Slide 77

Slide 77 text

77 Что же может пойти не так? Я, пытающийся понять почему topiclag 10055000, консьюмеры мертвее моей архитектурной карьеры, а хелсчеки говорят Мой продакшн

Slide 78

Slide 78 text

Ошибка номер 8 — dead letter queue 78

Slide 79

Slide 79 text

No content

Slide 80

Slide 80 text

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

Slide 81

Slide 81 text

81 Делаем DLQ (dead letter queue) УПС Попыток 10 на сообщение

Slide 82

Slide 82 text

Как вы догадались: мы поддавали жару ещё и здесь 82

Slide 83

Slide 83 text

Подведем итог: у нашей системы не было и шанса! 83

Slide 84

Slide 84 text

Это явно я Ф — надежность

Slide 85

Slide 85 text

Как же мы всё это вылечили?

Slide 86

Slide 86 text

No content

Slide 87

Slide 87 text

/ Денис Аникин https://xfenix.ru https://github.com/xfenix/ Спасибо!

Slide 88

Slide 88 text

No content

Slide 89

Slide 89 text

Проставили requests & limits 89

Slide 90

Slide 90 text

А как это делать когда ничего непонятно? 90 Есть пару простых идей — Проставьте минимальное значение для requests, ниже которого сервис не будет работать совсем — Проставьте limits в 2-3 раза выше (в зависимости от ваших возможностей) — Дальше двигайтесь итерационно, либо с помощью нагрузочного тестирования, либо докидывая limits в процессе жизни (что более нервно) — Не забывайте мониторить throttling!

Slide 91

Slide 91 text

No content

Slide 92

Slide 92 text

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

Slide 93

Slide 93 text

Сделали мониторинг topic lag и количества консьюмеров 93

Slide 94

Slide 94 text

No content

Slide 95

Slide 95 text

Что можно было бы мониторить ещё 95 Но что мы пока не мониторим — Количество sent запросов — Количество received запросов — Время/продолжительность отправки — Время/продолжительность потребления — RPS

Slide 96

Slide 96 text

Сделали мониторинг количества соединений KeyDB 96

Slide 97

Slide 97 text

Проставили max_connections для пулинга! (у Sentinel тоже можно) 97

Slide 98

Slide 98 text

Самое интересное было с concurrency! 98

Slide 99

Slide 99 text

КО Порождаем 100_000 корутин Берем здесь соединение из пулинга УПС В чём сложность

Slide 100

Slide 100 text

Когда мы поняли, что дело в нём 100 А понять было ОЧЕНЬ непросто на самом деле (ведь корутины мы не мониторим) — Долго обсуждал — И в конце я вспомнил, что в asyncio есть Semaphore!

Slide 101

Slide 101 text

… Какой-то шаренный ресурс (типа коннекта к базе/базы) Корутины Семафор со значением 3 Корутины

Slide 102

Slide 102 text

Пару мыслей по корутинам 102 — Concurrency — штука коварная, имеет смысл ограничивать количество create_task — Semaphore и другие примитивы синхронизации вам бро! — Возможно, вам может быть полезен aiomonitor!

Slide 103

Slide 103 text

Enterprise архитектор Solution архитектор Я, делающий вот это всё

Slide 104

Slide 104 text

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

Slide 105

Slide 105 text

Сделал ребуты и делаю вид, что это chaos engineering

Slide 106

Slide 106 text

Эксперты, слушающие доклад

Slide 107

Slide 107 text

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

Slide 108

Slide 108 text

Самое главное, что я хочу сказать: «лимитируй это»… 108

Slide 109

Slide 109 text

…пожалуйста! 109

Slide 110

Slide 110 text

…не будь как я 110

Slide 111

Slide 111 text

Как тебя архитектурить? Не надо меня архитектурить Откуда ты это сказал?

Slide 112

Slide 112 text

No content

Slide 113

Slide 113 text

Веселый был бы доклад на хайлоад…

Slide 114

Slide 114 text

Веселый был бы доклад на хайлоад… если бы хайлоад писали на питоне

Slide 115

Slide 115 text

Некоторые ссылки 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

Slide 116

Slide 116 text

Денис Аникин https://xfenix.ru https://github.com/xfenix/ Спасибо!