Рассказ инженера Big Data
Мы решили ускорить NameNode.
Сначала увеличили количество потоков.
Сервер посмотрел на нас и сказал: “Спасибо, теперь мне плохо быстрее”.
Потому что очередь — это не когда мало людей у окошка.
Очередь — это когда окошко одно, а люди уже начали жить в очереди.
И вот стоит запрос getFileInfo.
Он ничего не хочет.
Он просто спросить.
Но таких “просто спросить” — девять тысяч.
И каждый с выражением лица: “я на секундочку”.
А система в этот момент думает:
“Если все на секундочку, почему у меня уже среда?”
И тут приходит администратор.
Не человек — профессия.
У него в глазах не усталость.
У него в глазах jstack.
Он говорит:
“Сейчас мы посмотрим, кто держит lock”.
Это очень сильная фраза.
В обычной жизни так не говорят.
В обычной жизни говорят: “Кто последний?”
А тут: “Кто держит lock?”
И сразу понятно — люди давно не отдыхают.
Сделали jstack -l.
И NameNode завис.
То есть мы хотели узнать, почему он зависает.
И для этого дали ему команду зависнуть окончательно.
Это называется диагностика.
В медицине так нельзя, а в IT — пожалуйста.
Потом решили:
“Больше -l не делать”.
Это тоже важный этап зрелости инженера.
Когда ты не знаешь, что делать, но уже знаешь, чего делать нельзя.
На этом держится половина промышленной эксплуатации.
Потоки стоят.
Очередь RPC растёт.
CallQueueLength смотрит на тебя как очередь в поликлинике в понедельник утром.
Там уже не запросы.
Там судьбы.
Один запрос пришёл открыть файл.
Второй — узнать информацию о файле.
Третий — удалить файл.
Четвёртый — просто посмотреть список.
И каждый считает, что он главный.
open говорит:
“Без меня вообще ничего не начнётся”.
getFileInfo говорит:
“Я маленький, я быстро”.
delete говорит:
“Я сейчас освобожу место”.
А NameNode говорит:
“Вы все говорите одновременно. Я один”.
И где-то рядом DataNode.
У него вообще своя жизнь.
Он пишет:
“Block token verification failed”.
Что это значит?
Это значит: “Я помню блок, но не помню пароль от воспоминаний”.
Блок есть.
Токен есть.
Ключа нет.
Как в жизни: человек есть, пропуск есть, база сказала — не знаю такого.
Потом появляется Hive Metastore.
Это уже не сервис.
Это посредник между болью и базой данных.
Цепочка красивая:
Trino идёт в Metastore.
Metastore идёт в HAProxy.
HAProxy идёт в PgBouncer.
PgBouncer идёт в PostgreSQL.
PostgreSQL смотрит на Patroni.
Patroni смотрит в вечность.
И где-то посередине возникает timeout.
Все говорят:
“Это не у меня”.
Trino говорит:
“Я просто спросил”.
Hive говорит:
“Я передал”.
HAProxy говорит:
“Я балансировал”.
PgBouncer говорит:
“Я пулил”.
PostgreSQL говорит:
“Я вообще живой благодаря Patroni”.
Patroni говорит:
“Я лидер, но не крайний”.
И вот в логе появляется прекрасное:
Connection is not available.
Очень человеческая фраза.
Не “ошибка”.
Не “сбой”.
А именно — “соединение недоступно”.
Как хороший специалист в отпуске.
Он есть.
Он где-то числится.
Но сейчас недоступен.
Тогда мы увеличиваем pool.
Потому что если не хватает соединений, надо дать больше соединений.
Это логично до первой тысячи.
Потом выясняется, что больше соединений — это не решение, а способ быстрее узнать, где следующая проблема.
Сначала не хватало соединений.
Потом не хватает потоков.
Потом не хватает памяти.
Потом не хватает терпения.
Потом не хватает людей, которые помнят, зачем это всё было построено.
А Trino тем временем живёт отдельно.
У него 185 нод.
Потом уже 275.
Два координатора.
Большой кластер.
Очень большой.
Такой большой, что когда запрос не выполняется, это уже не ошибка, а коллективное мероприятие.
И он пишет:
No nodes available to run query.
Вот это особенно красиво.
Двести семьдесят пять нод.
И ни одной свободной.
Как парковка у торгового центра перед Новым годом.
Ты смотришь на кластер и говоришь:
“Но вот же они. Стоят”.
А Trino отвечает:
“Физически — да. Духовно — нет”.
Потом Trino находит утечку памяти.
Он пишет:
“Memory leak detected”.
И перечисляет query id.
Длинные такие, солидные.
Как номера уголовных дел.
Запрос уже завершился.
Но память держит.
Он ушёл, но вещи оставил.
Как родственник после праздников:
“Я только куртку заберу потом”.
И память ждёт.
День ждёт.
Ночь ждёт.
ZGC ходит рядом, тихий, интеллигентный.
Говорит:
“Я бы убрал, но оно формально занято”.
ZGC вообще похож на хорошего уборщика в музее.
Всё видит, всё понимает, но экспонаты трогать нельзя.
Потом начинается Kafka.
Kafka — это когда ты решил, что логов много, но всё равно хочешь их сохранить.
Потому что вдруг пригодятся.
Что именно пригодится — неизвестно.
Но удалять нельзя.
Вдруг потом спросят: “А кто удалил?”
И вот HDFS audit летит в Kafka.
Ranger audit летит в Kafka.
Spark читает Kafka.
Пишет ORC.
Trino читает ORC.
Человек читает Trino.
И в конце человек всё равно делает grep.
Потому что сколько бы мы ни строили платформу данных, настоящий BI начинается с:
cat log | grep ERROR
А потом awk.
awk — это такой маленький Hadoop для одного человека.
Если человек злой и выспался — он заменяет половину enterprise-стека.
Потом Spark Streaming.
Он должен читать поток, парсить, складывать.
Очень просто.
Пока не появляется offset.
Offset — это память о том, где ты остановился.
В жизни этого очень не хватает.
Spark говорит:
“Я помню”.
Kafka говорит:
“А я помню, что ты помнишь”.
YARN говорит:
“Подожди, у меня ресурсов нет”.
И всё стоит, потому что кто-то где-то попросил executor, а YARN отвечает:
“Ваш запрос очень важен для нас. Оставайтесь на линии”.
Executor ждёт.
Driver ждёт.
Kafka ждёт.
Пользователь ждёт.
Только данные не ждут.
Данные приходят.
И это главная особенность Big Data.
Маленькие данные можно отложить.
Большие — нельзя.
Они идут.
Как отопительный сезон.
Как отчётность.
Как родственники на дачу.
Потом мы смотрим Grafana.
Grafana — это когда всё плохо, но красиво.
Линии бегут.
CPU прыгает.
Network падает.
Heatmap светится.
И ты уже не решаешь проблему, а любуешься её динамикой.
Особенно приятно, когда график показывает, что проблема была ночью.
В три часа.
Когда ты спал.
То есть теоретически спал.
Потому что в 03:17 пришло сообщение:
“NameNode опять залип”.
И ты смотришь на телефон.
На мир.
На потолок.
И думаешь:
“Когда я был маленький, я хотел заниматься компьютерами”.
Вот оно.
Занимаешься.
Потом появляется PostgreSQL.
Мы смотрим самые тяжёлые таблицы.
SDS.
DBS.
SEQ_SCAN большой.
Очень обидно, когда таблица называется из трёх букв, а проблем создаёт на весь день.
Делаем ANALYZE.
И сразу вопрос:
“А он не заблокирует?”
Потому что в промышленной базе любая команда звучит как угроза.
Даже ANALYZE.
Хотя по названию вроде культурная вещь.
А всё равно страшно.
Потом индексы.
Индексы — это как полки в гараже.
Пока их нет, всё лежит на полу, но все знают, где что.
Потом ставишь полки — и сначала становится хуже.
Потому что теперь надо понять, на какую полку ты положил то, что раньше просто пинал ногой.
Но без индексов нельзя.
С индексами тоже нельзя просто так.
В этом и состоит архитектура.
А ещё есть HAProxy.
У него параметры.
Много параметров.
maxconn, timeout, backlog, nbthread.
Ты смотришь на них и понимаешь:
люди не настраивают HAProxy.
Люди ведут с ним переговоры.
“Сколько соединений ты выдержишь?”
“Смотря как попросите”.
“А если увеличить?”
“А если я упаду?”
И ты такой:
“Давай аккуратно”.
В Big Data слово “аккуратно” означает:
сначала на одной ноде, потом на всех, потом откат, потом опять на всех, но уже с другим значением.
Потом Ansible.
Ansible — это способ ошибиться сразу на 185 серверах, но с чувством порядка.
Одна команда — и везде одинаково.
Если правильно — праздник.
Если неправильно — тоже везде одинаково.
Красота стандартизации.
Особенно хорош site.retry.
Это файл, где записаны те, кто не смог.
У людей тоже должен быть life.retry.
Список задач, на которых мы отвалились, но потом вернёмся.
А пока возвращаемся к NameNode.
NameNode сидит.
У него 500 гигабайт heap.
ZGC.
Метрики.
JMX.
Очереди.
Потоки.
Handlers.
И всё равно он иногда смотрит в одну точку.
Потому что размер памяти не отменяет смысла происходящего.
Можно дать человеку большой кабинет.
Можно дать ему три секретаря.
Можно дать ему кофемашину.
Но если к нему каждую секунду забегают тысячи людей с вопросом:
“А этот файл есть?”
— рано или поздно он начнёт отвечать глазами.
И вот мы сидим ночью.
Смотрим на логи.
Там Java.
Thrift.
SocketTimeoutException.
Read timed out.
Очень честная ошибка:
“Я читал, читал — и устал”.
И в этот момент приходит мысль:
Big Data — это не про большие данные.
Это про большую ответственность за маленькие настройки.
Один timeout.
Один pool.
Один индекс.
Один handler count.
Одна очередь.
Один jstack -l.
И всё.
У тебя уже не кластер.
У тебя роман.
Роман о человеке, который хотел просто хранить файлы.
Потом просто читать таблицы.
Потом просто ускорить запросы.
Потом просто понять, почему оно висит.
Потом просто дожить до утра.
И самое смешное — утром оно заработает.
Само.
Ты придёшь, а графики ровные.
Очередь ноль.
CPU нормальный.
Metastore отвечает.
Trino выполняет.
Kafka пишет.
Spark читает.
И все скажут:
“Ну вот, видишь, прошло”.
А ты знаешь:
оно не прошло.
Оно просто ждёт следующего релиза.