×Закрыть

Как ловить утечки памяти на MySQL (Percona)? [решено, поймана]

Захотелось на проекте попробовать в действии движок TokuDB. Для этого поднял Percona, которая разумеется встала взамен предыдущего MySQL 5.6. От последнего я и так планировал избавляться за его прожорливость в плане оперативы, когда он жрёт памяти вдвое больше чем вся база весит.

На полигоне Percona 5.7.13 (последняя на данный момент) показала себя прекрасно. Но при поднятии на боевом серваке ждал «сюрпрайз» в виде утекания памяти ≈300-400Мб в сутки.
Что знаю:
— Таблица x$memory_global_by_current_bytes говорит что у меня 175Мб скушано всего.
— innodb_buffer_pool_size=10M (поскольку совсем от InnoDB не избавиться, 6 системных таблиц базы MySQL на нём)
— Кеш запросов отключён
— tokudb_cache_size=100M (100Мб отдал на кеш TokuDB)

Вопросы:
— Есть ли идеи, куда она может деваться, и как это ловить?
— Есть ли кто, кто стабильно работает на Percona и TokuDB? Какая версия? Или на других клонах Мускула у кого поднят TokuDB?

Предложения прыгнуть на другую SQL-базу — рассматриваются. Предпочтение — компактность в плане оперативы, которая поддаётся настройке. Ну и скорость будет не лишней. Рассказывайте у кого что. Фенечек вроде геолокации не требуется, данные примитивны.

Дефолтное решение вернуться на MySQL 5.6, и мне оно не нравится.

Понять на полигоне что именно жрёт память пока не получается. Такое впечатление, что это либо логирование, либо соединение, либо в каком-то компоненте установка по-умолчанию отжирать столько памяти, сколько система разрешает (включая уход в своп). Скорее всего последнее, поскольку на производительности никак не сказывается.

Либо же классическая утечка в неконтролируемой области — что меня удивляет, поскольку и база, и движок — достаточно старые, проверены годами. Так что оптимальное решение — найти версию где утечки нет. Или понять как можно хотя бы контролировать процесс, чтобы увидеть где течёт.

Отдельный вопрос — как правильно параллельно на Линухе поднимать несколько экземпляров MySQL, можно ли пользоваться инсталлятором и надеяться что ничего не убьёт из существующего? Может где-то это документировано?

UPD: Утечка поймана.Течёт prefetch buffer, очень вероятно не уничтожается при разрыве соединения.

Что было: один настырный демон (про которого давно забыли) пытался соединиться с базой, которой нет. Имя базы прописано в параметре соединения (на PHP). И с регулярностью несколько раз в секунду он это делал. После разруливания заметных утечек вроде нет, prefetch buffer вернул. Но у меня соединения используются повторно, если утечка на разрыве всё же существенна, замечу я это нескоро.

LinkedIn
Допустимые теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Допустимые теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter

Перевір, про всяк випадок, незакриті конекти.

Це перевірив в першу чергу, благо для цього є системні вьюшки. Проблема якраз таки закриті.

Тема закрыта, утекает bulk_prefetch.
Я так понимаю, на каждом селекте он пытается оптимистично выбрать ещё 128Кб данных «для моего удобства». И вот они где-то зависают. Короче, прищемил оптимизм — попустило!
tokudb_bulk_fetch=OFF

Спасибо за инфо, но лучше апдейтом в топ, чтоб если кто гуглить будет не надо будет перечитывать всю тему. Наверняка вы не первый и не последний кто с таким поведением столкнулся.

столкнутся практически все. это дефолтное поведение :) как понял начиная с 7.5

причем это просили у разработчиков не один год, судя по стековерфлов и блогам.

Может поведение и дефолтно, но факт что при неудачном соединении (и вероятно при разрыве удачного) буфер остаётся жить своей жизнью. В общем, ребята не в курсе что такое try-finally.

В общем, ребята не в курсе что такое try-finally.
код не смотрел. но уверен что в курсе :) продукту не один год, даже если бы не были в курсе написав первую версию.

странно что у вас, опытного программиста такая уверенность в такой глубочайшей некомпетентности других программистов. обычно это новичков такое самомнение :)

Потому что экспериментально доказано, что ПОПЫТКА соединения с несуществующей базой, которая естественно отсекается — вызывает течь в движке TokuDB. Хотя какого пионерского перца движок вообще инициируется на этапе коннекта — вопрос хороший, при том что НА СИСТЕМНЫЕ таблицы действие этого движка не распространяется.

Так что сорри, но процедура хендшейка, не обёрнутая на каждом этапе во вложенные try-finally — это говнокод во все времена! Потому что если бы обёртка была — то и ресурсы бы освобождались.

Потому что экспериментально доказано, что ПОПЫТКА соединения с несуществующей базой, которая естественно отсекается — вызывает течь в движке TokuDB.
из того поведения что вы написали - этого не видно. видно потребление памяти, которое вы не ожидали. из описания технологии видно - а чудес не бывает, хошь перфоманса - пихай все в ОЗУ.

таким рассуждением можно объявить течью сохранение буферов, кеша а не их при полный сброс при любом некорректном обращении или завершение обращения к любому сервису.

Хотя какого пионерского перца движок вообще инициируется на этапе коннекта
ну наверное из предположения что раз движок подключен, то с ним будут работать.
так обычно работает то что названо prefetch
Открыл я одну страницу - а браузер тянет и остальные, ссылки на которые встретил. Минимум - DNS prefetching делает.
Запустил я виндовс, а она зыркнув в Prefetch грузит в память dllки которые мне не нужны. я ж открыл только чтобы файлик скопировать, и закрою. дура эта ваша виндовс, и программисты криворукие что ее писали.
не обёрнутая на каждом этапе во вложенные try-finally — это говнокод во все времена!
приведите код.
Потому что если бы обёртка была — то и ресурсы бы освобождались.
см. выше - некорректное соединение, или его завершение - НЕ причина инвалидации кеша.

но, всяко бывает - покажите баг реквест.

из официальной доки
tokudb_disable_prefetching
TokuDB attempts to aggressively prefetch additional blocks of rows, which is helpful for most range
queries but may create unnecessary IO for range queries with LIMIT clauses. Prefetching is on by default, with a value of 0, and can be disabled by setting this variable to 1.

aggressively - переводить?

там кстати с десяток настроек:
cachetable: prefetches
This is the total number of times that a block of memory has been prefetched into the database’s cache. Data is prefetched when the database’s algorithms determine that a block of memory is likely to be accessed by the application.
...
ft: basements fetched for prefetch (bytes)
Number of basement node bytes fetched from disk by a prefetch thread.
ft: basements fetched for prefetch (seconds)
Number of seconds waiting for IO when fetching basement nodes
from disk by a prefetch thread
...

вы с ними разобрались, пробовали поуменьшить aggressively ?

Утечка 400+ Мб в сутки - ну да, не видно...

просто у меня было уже такое - надежно выловил баг, написал баг-реквест в трекере разработчиков, с кейсом, все дела.
через пару дней в трекере ответ:
такое поведение при вашем кейсе может быть устранено настройками и тынц, тынц ссылки в доку. в случае дефолтного да, будет так.

сделал, как там написано, и баг исчез.

если гугль молчит на
TokuDB memory leak

то я бы вначале копал в доке, на форумах по поводу настроек, а не делал вывод об утечке памяти.
хотя, конечно не исключено что это баг, и именно такой как вы описываете - разработчики TokuDB полные невежды в программировании. вам оно конечно не заглядывая в код с этим багом - виднее.

просто меня "в детстве" учили - компилятор дурак в последнюю очередь.
хотя как-то я таки нарыл ошибку в компиляторе Турбо С, при включенной оптимизации, на завернутом коде. выключил такую-то оптимизацию - и усё в порядке. или код переписал.

так что вы бы им баг этот в трекер написали.

Согласен. Но я не ставил целью улучшить движок — я в этом мало понимаю, чтобы всерьёз лезть в его коррекцию. Наоборот, попросил помощи, и меня немножко на правильную мысль натолкнули.

Но считать что программисты не ошибаются... я мог в 10-м классе. Когда я сам программист, и львиная доля коллег моложе меня — я уж как-то могу оценить СКОЛЬКО ошибаюсь я. И вижу сколько они.

Однако процедура сетевого коннекта — вещь настолько старая и изъезженная, что пора бы высечь в граните: КАЖДЫЙ слой нужно оборачивать в try-finally. Чтобы в код не падали чужие исключения, а обрабатывались исключительно в своём, и если ты ресурс выдал — будь добр его освободить.

PS. Да, я из того поколения, когда деструкторы писались руками. И я знаю, что это нужно делать по сей день. Настолько же принципиально, как развязывать шнурки прежде чем лечь на кровать — хотя это и неочевидное правило для кровати, но если оно не обработано на своём уровне интерфейса — потом возникает казус. А компьютер штука тупая, ему плевать на последствия своих действий.

Да, согласен, вы уже на первом курсе, а не в 10ом курсе, когда пришло понимание что ошибаются все, да пока далеко до понимания — а как же сотворенное этими ошибающимися может работать вообще.
В общем ваши обвинения несерьезеы, и наивны, до тех пор пока вы не показали ошибку в коде, или не написали баг-реквест.
За то что поделились фингалом от граблей — спасибо. Я узнал новое о TokuDB. Попутно с примером что опыт сам по себе — не делает мудрым.

Это первое что я проверил :)
Утекающая память в этих объектах не отображается, значит утечка более низкоуровневая.

коннект с неправильными параметрами это не исключение. Поэтому не вижу смысла там в try ... catch. Это часть бизнес логики

И утечка 400+ Мб в сутки тоже? Не в Майкрософте ль работаете?

с TokuDB не работал (не иметь foreign keys — смертельный недостаток), но тем не менее...

Для начала, думаю, выложи my.cnf (позатирай сенситивную инфу, если она там есть), или как вариант, результаты запроса «show variables like ’toku%’;» - возможно там что-то интересное затесалось.
Список переменных тут — www.percona.com/...udb/tokudb_variables.html

Ну и помониторить память с помощью «free» и «top -u mysql» — какие параметры растут, особенно, свопится ли система. Если свопится — Хьюстон, у вас проблемы.

Если переходить на что-то другое — попробуй на mariadb 10 или postgres 9.x

Ну что же вы как маленький, Valgrind прогоните и найдите конкретное место где память течет и зарепортьте в Percona.

p.s. Хотя, нет, Percona — российская компания, ничего не репортьте и переходите на другой движок/базу.

Хотя, нет, Percona — российская компания
С чего вы взяли?

Основатели — россияне. Разработка в Москве.

Основатели — россияне
Один из, Ткаченко — украинец, если я не ошибаюсь. Это какбы не делает компанию российской.
Разработка в Москве.
Не знаю с чего вы взяли, но на линкедине у них больше разработчиков из Украины, чем из России.

Ну и что. Этот проект переживёт и Xyйло™ и его рускей мир.

Это международный проект, а место рождения создателей не имеет значения для такого серьёзного зверя. И потом, если Рашка на них наедет некошерным способом, думаю просто переедут ребята и всё. Таких спецов везде заберут, тем более готовой фирмой. Тот же Оракл может позвать и скрестить обратно с Мускулем (не в пользу последнего).

К тому же ОПЕНСОРС.

Если бы проблема ловилась на полигоне, вопросов бы не было. Поставить в продакшене на Valgrind — низя, производительность сдохнет.

Перкона обрастает мифами. :)
Нет, Перкона не российская компания и никогда ею не была, она зарегистрирована в США.
Основана Петром Зайцевым (выходец из россии) и Вадимом Ткаченко (выходец из Украины). Оба живут в США уже много лет.

До 2013 года штаб-квартира была в калифорнии, сейчас — в северной каролине. Основная масса сотрудников работает удаленно, в том числе и из россии.

И я там проработал почти шесть лет, из-под Киева :-)

Отдельный вопрос — как правильно параллельно на Линухе поднимать несколько экземпляров MySQL
dev.mysql.com/.../5.7/en/mysqld-multi.html
dev.mysql.com/...-multiple-mysql-instances

Еще вариант — под докером поднять несколько инстансов.

Отдельный вопрос — как правильно параллельно на Линухе поднимать несколько экземпляров MySQL, можно ли пользоваться инсталлятором и надеяться что ничего не убьёт из существующего? Может где-то это документировано?

Запускать разные бинарники mysqld с разными —basedir и/или конфигами
mariadb.com/...n/mariadb/mysqld-options
И с разными uid’ами без прав записи в чужие datadir-ы, тогда точно ничего не убъёт.

Поставить один пакет на другой не получится, вытащить mysqld из пакета и пользовать отдельно скорее всего получится.

Ну и с такими вопросами: а что именно «утекает» и как это меряется?

Тоже пришло на ум что течет что-то другое. Уж очень сильно течет, чтобы быть багом. Он бы давно у тьмы людей проявился б
Но с TokuDB не работал, может там ключик какой есть — что-типа держать снапшотодампы в памяти в количестве стопицот штук.

Вот меня и удивляет, что во-первых слишком нормально работает для текущей.
Во-вторых, течёт сериями. То есть в какой-то момент отжирает метров 20, и точно так же может отдать. Может пару часов не утекать вообще. В общем, хер пойми что, такое впечатление что движок мою память с /dev/nul перепутал.

Например, эти сутки база отожрала свои 400Мб, притом львиную долю утром, сейчас вообще скромничает. ИЧСХ, это мало зависит от типовой нагрузки.

Вот я и хочу знать, есть ли способы изловить зверя, может возможности какие плохо-документированные.

Что меня удивляет больше, что всё это «из коробки». Я поставил базу, и уже потом накатил дамп.

мало ли какое дефолтное поведение.

я все никак не доберусь пощупать HandlerSocket и InnoDB memcached plugin, хотя проблемы массированной записи, как в TokuDB они не решают.

кстати, а может если не перкону, а марию взять, проблема рассосется?
о перконе негативное, слышал и в других кейсах

з такими питаннями краще на форум sql.ru

Запусти под valgrind и посмотри что и где течет.

TokuDB — отличный, интересный движок, никаких утечек памяти не было, ставился на обычный мускуль с дефолтными настройками.

Версия мускуля, версия TokuDB, как ставился (инсталлятор или простое копирование с ручными настройками?, как пакет из репозитория или руцями?)

Давно было дело, 3 года назад. Вроде версия мускуля была 5.5 или 5.4. TokuDB ставился руками. Система Линуха — Debian.

От последнего я и так планировал избавляться за его прожорливость в плане оперативы, когда он жрёт памяти вдвое больше чем вся база весит.
Сколько же у вас база весит ?
Захотелось на проекте попробовать в действии движок TokuDB.
Техническое любопытство или насущная необходимость ?

TokuDB без констрейнів/зовн, ключів як?

Нема такого. Взагалі некористуюся на даний момент констрейнами бази. В майбутньому звичайно підніматиму, але поки багато чого змінюється, мені набагато легше підтримувати стабільність лише на рівні коду. Бо в базі виправити щось криво збережене можна, але коли база відмовилась зберігати взагалі — це таки проблема.

На текущий момент можно обойтись, но в будущем (≈3-6 мес.) — необходимость. Я решил переходить на ранней стадии. Ловить такие траблы на раскрученном проекте — мне ссыкотно считать убытки.

База на текущий момент весит 130Мб основная, около 300Мб это вся папка на диске (включая системные таблицы, страничные буферы и прочее счастье). Конечно, я её ещё оптимизирую. Но факт что у неё рост 8-10% в месяц, и мне нужен вменяемый движок.

Это я ещё проект в активную фазу раскрутки не переводил, пока только прямые продажи.

База на текущий момент весит 130Мб основная, около 300Мб это вся папка на диске
как говорится — нам бы ваши проблемы :-)

Ну так это SQL-база, не всё ж в ней хранить, а только то что хорошо структурируется.

TokuDB концептуально интересный, но — сыроватый еще движек, по моему. А на базу 130Мб ....... ну серьезно — возьмите InnoDB и поставьте innodb_buffer_pool_size=4G.

Ну я бы не сказал что движок «сыроват», очень даже грамотный. Что течёт — ну факт, думаю вылечат или как минимум документируют если это надо устранять в настройках.

Ситуация не критическая. Я не спорю что можно взять InnoDB, но он показал своих коней: после транзакции INSERT или UPDATЕ, последних у меня просто таки до чёртиков, он считает своим долгом выжрать под 100% CPU секунд на 5-10. Что он делает — знает лишь мудрец лохматый. Притом на MySQL 5.6 он и стоял, и таких проблем не было.

Учитывая планируемый рост, я просто решил пойти на TokuDB именно за его грамотную работу с добавлением -удалением записей, особенно там где много индексов.

Если бы 130Мб было её пределом — вопрос бы не стоял в принципе. Но проект ещё в стадии беты, то есть на свою аудиторию ещё даже не выходил. А задача у него мерзостная, связанная с системой качества, и потому сам проект должен работать с качеством превышающим те в которые он интегрируется. Иначе говоря, 130Мб — результат оптимизации, до того был 5Gb. И все шансы что снова будет и весьма скоро.

Да кстати утекать может из-за того что вы не установили нужные параметры linux kernel

Вот такие:
echo never > /sys/kernel/mm/transparent_hugepage/enabled
echo never > /sys/kernel/mm/transparent_hugepage/defrag

Описано вот тут — для перконы в принципе это тоже справедливо: mariadb.com/...hugepage-support-on-linux

Ставил инсталлятор, он установил. Я проверил.

Ну и кстати — какую проблему InnoDB вы пытаетесь решить с TokuDB?
TokuDB позиционирует себя как optimal solution на read\write curve
www.percona.com/...on-clarifications-part-2

То есть грубо — запись «почти» как MyRocks при чтении «почти» как InnoDB.
Но при базе 130 Мб и росте 10-15% (15-20Мб) в МЕСЯЦ — я сомневаюсь что у вас есть какие либо заметные проблемы с записью.

То есть теоретически Toku универсальней — но сильно менее распостранена и более сырая.

Именно запись. Пока проблем нет, но они будут. Потому и я готовлюсь заранее, разбирая где узкие места.
При базе 130Мб львиная нагрузка ложится на пару табличек, которые имеют все шансы уходить во взаимный deadlock, и не обязательно двумя процессами.

Toku не просто универсальнее, он даёт шустрые операции там где раньше утекали десятки милисекунд. Я не спорю, что может быть что-то пошустрее, но поднимать не-универсальный движок означает заиметь проблем с транзакциями.

В общем, я не факт что прав. Просто рассматриваю варианты. InnoDB как последний вариант, его тяжело балансировать — сотни настроек, без внятного объяснения что и как балансировать. А эксперименты на боевой базе штука дорогая, вероятность ошибки никто не отменял.

Диагноз
по телефону не поставить.
Но насчет «без внятного объяснения» не соглашусь. Другое дело что оно в книгах, а не статьях, где первые главы посвящены архитектуре MySQL, без понимания которой будут непонятны дальнейшие главы, и самое важное — в нестандартных ситуациях выводы будут делаться неверные. Типа классического — а вот я сейчас под запросом выберу грубо, а потом уже точно. Зато ж первая выборка сильно уменьшит размер для фулскана во второй. Вроде логично, правда?

Я думаю вам надо дибиэйщика найти, в консультанты, которому вы в подробностях расскажете потребности, а не кажущиеся вам очевидными рецепты.

— пациент, рассказывайте симптомы, а не прописанный себе курс лечения

А я не ставлю диагноз. Диагноз будет ставиться потом, когда база уже наберёт обороты. Сейчас я планирую что мне подойдёт, предсказываю ситуацию. И зная, что проект вырастает из детских штанишек MySQL я не собираюсь выделять 2 ядра и 8 гектар под классическое поведение, там где на 300Мб и база выдержала тестовую нагрузку не прогрузив даже 1 ядро на 10%.

Иначе говоря, я попробовал, мне подошло, но ложка дёгтя оказалась бочкой. Сейчас у меня варианты — закронтабить перезагрузку, вернуться на старый Мускуль 5.6, или прыгнуть на другую архитерктуру. Я выбрал вариант задать вопрос на DOU, может у кого-то есть опыт пользования, и соответственно можно просто поставить более стабильную версию, или взять какие-то специфические настройки.

Чего я пока НЕ понимаю:
— можно ли Мускулю задавать внешнюю настройку, лимитить память? Потому как он чувствует себя хозяином жизни и берёт сколько ему надо, потом часто возвращает.

Пока что ликвидировал буферезированный вывод, прищемил размер кеша (а придётся поднять с ростом базы), и получил примерно утечку 100-150 метров в сутки. Я не могу даже утверждать утечка ли это, потому дам базе с недельку поработать. Вероятно утечка либо в буферизации вывода (не очень-то верится), либо же в оптимизации потоков — такое впечатление, что после закрытия соединения его prefetch-буфер оставался выделенным. А поскольку потоки используются повторно, выловить ситуацию не так и просто.

И с этого поста — тоже ну ничего не понятно о вашей задаче. Может для нее вообще касанлру нужно. Критерий — попробовал, мне подошло — не критерий, если неизвестна задача и технические требования.

Насчет самого вопроса, то вы как первый раз замужем. Как можно ответить на вопрос не видя конфигов, логов,и т.д. только если кто-то сходу нарвался на ту же проблему.

Но если такая проблема из коробки сразу, типична — то ее бы пофиксили давно.
Ну и, как сказал, раз не хватает квалификации, то нужно пробовать, а не пытаться рассуждать. Смените линух, смените перкону на марию, смените версию бд на предыдущую, и т.п.

Убрал prefetch и течь перестало. Если не совсем, но уж крайне незаметно если где и течёт.
tokudb_bulk_fetch=OFF

понятно. я про такое и догадывался:

может там ключик какой есть — что-типа держать снапшотодампы в памяти в количестве стопицот штук.
погуглил — рекомендуют наоборот Increased Usage of Bulk Fetch — Bringing the same performance enhancement to more complex SELECT statements as well as DELETE statements, this new capability is much faster than retrieving a row at a time.

variable tokudb_bulk_fetch
This session variable determines if our bulk fetch algorithm is used for SELECT and DELETE statements.
By default, tokudb_bulk_fetch is enabled.

TokuDB 7.5 has been released!
New Features
...
Added bulk fetch algorithm to improve performance of select and delete statements
...

у кого версия меньше, тот такого поведения и не видел :)

то бишь, наспех вывод — все оно правильно работало, ничего никуда не текло, TokuDB просто прикидывается in-memory DB ради скорости работы.

интересно, насколько в вашем реальном кейсе будет просад по скорости работы.

The TokuDB bulk fetch algorithm speeds up fractal tree scans by returning multiple rows per tree search rather than a single row. This amortizes the cost of a fractal tree search over several rows. We have observed a speedup of between 2x and 5x when using bulk fetch compared to not using it. TokuDB 7.1.7 (and prior versions) only use bulk fetch for simple selects. As a result, only simple selects run fast. Other operations, such as create select, run slow. We describe when bulk fetch can be used, how its use is triggered, and why it can be used to speed up operations such as create select.
github.com/...db-engine/wiki/Bulk-Fetch

Так я нашёл что вызывает эту течь (разрыв коннекта), и вернул буфер. Жрёт конечно некисло 100-150Мб оперативы вынь да полож. Но это терпимо если хочу скорости. Теоретически можно прищучить дефолтный размер буфера выдаваемый каждому коннекту. Практически так и поступлю когда мне будет не хватать оперативы.

В чём смысл таких танцев с бубном на базе в 300Мб?

Это не зрелый проект, база будет больше. Мне нужно откатать механизм. Откатывать его при боевых задачах уже не получится, слишком уж time critical задачи.

юзайте постгрес и не парьтесь

Версия, что он требует, какие траблы, в чём его ограничения, сколько процессора жрёт?
TokuDB выбран за экономичность по отношению к процу. Фрактальные индексы ну очень лояльны процессу добавления данных.

Подписаться на комментарии