Комментарии 10
нужно было сразу делать профилирование (perf(1), CPU Flame Graphs для наглядности) чтобы увидеть кто ест большими ломтями.
+4
Там не умеют Overhead'ы мерить в принципе…
Даже банальный встраиваемый ehcache с offheap'ом был бы быстрее Redis.
Вот в Terracotta / Hazelcast было пару багов с RMI так что их пока не стоит рассматривать.
Не знаю, мне, лично, после DPDK/SPDK видеть 1.5K RPS довольно прискорбно, так как даже на PHP7 можно в ~10К+ RPS.
+1
Самое смешное, что redis при старте в логи орет, мол, выключите THP, если включено.
Столько работы провели, а можно было просто в лог глянуть :)
Столько работы провели, а можно было просто в лог глянуть :)
+11
Спасибо, это полезная инфа.
Хочу отметить, что по проблеме не очевидно, в чьём логе ошибки искать. Тем более, сообщение появляется там не в момент высокой нагрузки, а при ребуте.
Тем и отличается хороший инженер по производительности, что и в отсутствии очевидного сообщения о ошибке он отыщет корень бед.
0
Лучше сделать:
Чтобы дать приложениям возможность использовать фичу явно, если она им нужна.
echo madvise > /sys/kernel/mm/transparent_hugepage/enabled
Чтобы дать приложениям возможность использовать фичу явно, если она им нужна.
+2
Давно уже у RedHat и Oracle есть документы, где явно предлагается выключать THP при использовании на серверах. Лучше бы наверно эта «фича» для серверных инсталляций была выключена по умолчанию.
0
А при моем профиле нагрузки на mariadb 10.3 наоборот включение улучшает ситуацию(сейчас стоит always)
Очень неочевидная фича.
Очень неочевидная фича.
+1
запуск задач по расписанию и другие системные задачи.
Что за глупости? Какое отношение все это имеет к ядру?
Выделение и освобождение памяти происходит с помощью вызовов malloc и free соответственно
Нет. В линуксе(да и везде) маллок/free не занимаются памятью, а работают только с виртуальным адресным пространством.
которые в итоге будут обработаны системными вызовами ядра, а значит отобразятся в утилизации CPU как системное время.
Не всегда, очень даже не всегда.
В большинстве современных операционных систем
К операционным системам это не имеет никакого отношения. Они лишь использует механизмы предоставленные железом.
виртуальная память организуется с помощью страничной адресации
Не виртуальная, как минимум не только виртуальная.
при таком подходе вся область памяти делится на страницы фиксированной длины
Память.
и при выделении, например, 2 Гб памяти, менеджеру памяти придётся оперировать более чем 500000 страниц
Нет. Менеджер памяти тут вообще не при делах и работает он, как я уже сказал, с адресным пространством. Т.е. он выделит просто диапазон и повесит на него права.
Отображением занимаются совершенно другие подсистемы. Причём занимаются только только созданием этих отображений — далее процессор всё делает сам.
В таком подходе появляются большие накладные расходы на управление и для их уменьшения были придуманы технологии Huge pages
Не для этого.
с их помощью можно увеличить размер страницы
Это аппаратная фича.
например до 2МБ, что существенно сократит количество страниц в куче памяти.
Не для этого.
В некоторых случаях THP вызывает ничем не мотивированное увеличение потребления CPU в систем.
Не в некоторых, а вполне в конкретных. И всё там мотивировано.
В заключение хотелось бы дать несколько советов, для успешного поиска проблем с производительностью:
Ничего из этого сделано не было. Да и советы достаточно глупые. Абстрактная нагрузка на процессор — ничего не показывает. Нужно использовать нормальный профайлер и собирать адекватный трейс, а уже далее смотреть.
Дак для чего же нужны эти большие страницы? Всё очень просто. Абсолютно неважно — сколько там страниц, пока они влезают в кэш. Есть специальный кэш — называется tlb. Когда происходит промах(т.е. отображения нету в кэше) — процессор вынужден пойти(автономно — ЭТО НЕ СИСТЕМНОЕ ВРЕМЯ) — найти и прочитать это отображение из памяти(если не нашел — тогда уже триггерится пейджфолт и уже тогда включается ядро).
Если отображение уже существует в памяти, то это на трупут почти не влияет. Процессор умеет в префетч и заранее подготавливает все отображения. Да, это съедает чуть-чуть трупута памяти(т.к. отображения читать из памяти нужно), но это крохи.
Но проблемы возникают именно на random access, когда никакой префетч не работает и трупут упирается в летенси(помноженной на блок) памяти. Поиск отображения — очень дорогая по летенси операция и от того задержки памяти возрастаю в разы.
Для предотвращения подобного поведения и нужны большие страницы. Их нужно меньше и в кэш влезают уже не мегабайты, а сотни, тысячи мегабайт памяти.
У этого подхода существует только одна проблема — это разряженная память. Дело в том, что по-умолчанию ядро попросту разрешает r/w в какой диапазон вадресспейса. Памяти в «памяти» выделяемой маллоком нет. Вообще(если это большие блоки(100к и больше по умолчанию, насколько я помню)).
Далее, когда мы начнём читать/писать в память — процессор не найдёт отображения и сгнерирует пейджфолт. Далее ядро пойдёт и в специальную таблицу(дерево) запишем отображение. Далее процессор всегда будет читать его или из памяти или из кэша(тлб).
Если мы будем читать/писать память байт за байтом, то первое чтение затригеррит пейджфолт и ядро свяжет первую(нулевую) страницу нашего отображения с реальной страницей(физической памяти). Для последующих 4096 байт(включая текущие чтение/запись) память будет. После — её не будет и опять будет пейджфол.
Тут уже можно понять — в чём проблема. Если мы выделим 2 мегабайта памяти и запишем половину — в ситуации с 4к страницами — выделится 1 мегабайт физической памяти. В ситуации с 2м страница — 2 мегабайта. Подобная ситуация сплошь и рядом в том же С++.
Тоже самое с разряженными массивами. Если у нас есть гигантский массив и мы сделаем туда 10 записей — мы затриггерем в среднем 10 пейджфолтом и свяжем 10 страница по 4к. Если тоже самое мы сделаем с 2м страницами — будет 10 по 2м.
Откуда может взяться высокий systime? Всё очень просто. Пейджфолты сами по себе дорогие, но разницы между типа страниц почти нет. Но.
Дело в том, что ядро при связывании страницы ОБЯЗАНО её забить нулями, т.е. пройтись мемсетом. Очевидно, что если мы в С++ запишем в строку 1гб + 1 байт, то ядро сделает мемсет на 1гб + 4к в случае с 4к страницами и 1гб + 2м в случае с 2м. И 1гб + 1гб в случае с 1гб страницами. Этим же обусловлено и возросшее потребление памяти.
И если в софте очень много разряженной памяти, то очевидно — ему повсеместные 2м+ страницы будут вредны, а в современном железе там 1гб и более страницы.
+12
Зарегистрируйтесь на Хабре , чтобы оставить комментарий
Влияние Transparent Huge Pages на производительность системы