tempesta-tech / tempesta

All-in-one solution for high performance web content delivery and advanced protection against DDoS and web attacks
https://tempesta-tech.com/
GNU General Public License v2.0
613 stars 103 forks source link

Huge pages allocation issue and the crash on cache sizes >=2GB #1515

Open DagothDeer opened 3 years ago

DagothDeer commented 3 years ago

Т.к. в нашем распоряжении не было процессоров на микроархитектуре Broadwell, а были в наличие только Haswell (машины на основе 2-х процессоров Xeon E5-2697 v2 и E5-2673 v2), о чем уже кстати было оговорено во втором сообщении в Issue "Setting cache problems #1513", то мы сначала пробовали перенести изменения на release версию 0.6.7.

1) Изменения, внесенные в файл "db/core/main.c" дали положительные результаты. Для каждой ноды теперь создается отдельный файл: /opt/tempesta/db/cache0.tdb /opt/tempesta/db/cache1.tdb Эта проблема решена.

2) Патч ядра работает НЕ стабильно. Параметр kernel comand line "tempesta_dbmem" влияет на объем резервирования памяти, но отнюдь не обеспечивает надежность данного процесса. По большому счету, резервирование происходит удачно только в случае, если объем резервируемой памяти составляет менее 50% от объема ОЗУ. При значении, равном 50% - резервирование происходит не всегда. И при объеме более 64% - зарезервировать память не удается. Видимо сказывается попытка резервирования памяти через функцию kmalloc в виде непрерывного свободного участка, который при заполнении более 50% - видимо уже тяжело найти. Сам объем ОЗУ - НЕ сказывается. Ниже предоставили результаты тестов, в которых объем ОЗУ варьировался от 36 до 100 ГБ, а параметр "tempesta_dbmem" от 12 (2 блока по 8 ГБ) до 14 (2 блока по 32 ГБ).

Тестирование различных значений параметра "tempesta_dbmem" при различных значениях ОЗУ:

Системе выделено 36 ГБ ОЗУ tempesta_dbmem=12 (выделяется 2 блока по 8 ГБ) Попытка зарезервировать 44% от доступной памяти. Результат: успех изображение

Системе выделено 36 ГБ ОЗУ tempesta_dbmem=13 (выделяется 2 блока по 16 ГБ) Попытка зарезервировать 89% от доступной памяти. Результат: провал изображение изображение

Системе выделено 50 ГБ ОЗУ tempesta_dbmem=13 (выделяется 2 блока по 16 ГБ) Попытка зарезервировать 64% от доступной памяти. Результат: провал изображение изображение

Системе выделено 64 ГБ ОЗУ tempesta_dbmem=13 (выделяется 2 блока по 16 ГБ) Попытка зарезервировать 50% от доступной памяти. Результат: успех изображение

Запуск конфигурации с 50% от доступной памяти на третий раз выдал провал.

Системе выделено 100 ГБ ОЗУ tempesta_dbmem=13 (выделяется 2 блока по 16 ГБ) Попытка зарезервировать 32% от доступной памяти. Результат: успех изображение

Системе выделено 100 ГБ ОЗУ tempesta_dbmem=14 (выделяется 2 блока по 32 ГБ) Попытка зарезервировать 64% от доступной памяти. Результат: провал изображение изображение

Проблема с выделением "cache_size" НЕ решена

3) Эта проблема затрагивает не только модуль парсинга конфига, но так же модули выделения памяти и управления файлами кэша на диске. Судя по всему этот функционал, с внесенными в него изменениями 1514 из ветки ak-1513 НИКТО не тестировал при объемах более 2 ГБ. Как Вы писали: "Запускал я на KVM с 4 hardware CPU и виртуальной двухнодовой NUMA и 4GB RAM, полная конфигурация VM": qemu-system-x86_64 -s -machine dump-guest-core=on -enable-kvm -m 4096 -numa node,nodeid=0 -numa node,nodeid=1 -cpu host -smp cpus=2 -no-hpet -name tfw-test -drive file=debian.img,format=raw -netdev tap,ifname=tap0,id=n1,vhost=on,queues=1,script=no -device virtio-net-pci,netdev=n1,mq=on,vectors=3 -boot order=cd,menu=on -serial file:serial-deb.txt. Т.е. у Вас всего было 4 ГБ ОЗУ. Из них, как минимум 500 МБ уходят на сам debian, а оставшиеся 3.5 Вы поделили между двумя numa-блоками => размер кэша не выставлялся больше, чем 1.7, а резервируемая память вряд ли превышала 50% от ОЗУ, а => при таких параметрах Вы НЕ МОГЛИ заметить ошибки. Подробнее о проблеме с выделением "cache_size" написали в самом конце.

Мысли по поводу самой организации хранения кэша. Сама идея, использования файлов для свапанья в них кэша из памяти, не терпит никакой критики... Вы сами во всех конференциях рассказываете о том, что хранение каких-либо кэшей в файлах - это пережиток прошлого. Вы видимо тестируете на очень маленьких объемах кэша. Судя по всему, до недавних правок по нашей просьбе - он не превышал 470 МБ. Теперь, после Ваших исправлений можно выставить 2 ГБ и вот тут начинает вырисовываться проблема. Как мы понимаем, Вы используете эти файлы для хранения содержимого кэша между перезапусками Tempesta. При старте Вы из них вычитываете, а при выключении - в них записываете. Две пары файлов по 2 ГБ - это уже 4 ГБ и даже при использовании SSD, скажем со скоростью записи 400 МБ/с - это уже занимает 10 секунд. При объеме памяти в 128 ГБ - 2 файла будут весить уже 256 ГБ, а значит писаться они будут уже в 64 дольше, т.е. 640 секунд, а это уже почти 11 минут. Вот Ваш комментарий из патча, который Вы накладываете на ядро: "+/ Modern processors support up to 1.5TB of RAM, be ready for 2TB. /". Такой объем еще в 16 раз больше и займет уже почти 3 часа. И обращаем Ваше внимание, что 3 часа при старте и 3 часа при выключении. Как Вы думаете, пользователи сервиса поймут, почему они ДОЛЖНЫ ждать целых 6 часов пока сервис не возобновит свою работу, если админ захочет просто перезагрузить машину? Как нам кажется, данная функция, сохранения копии кэша в файл, должна настраиваться в конфиге и в некоторых случаях лучше ее отключить и просто заново постепенно загрузить весь контент с бакендов, чем ждать 6 часов перезапуска. Кстати, чем обусловлено выбранное ограничение показателя степени двойки, равного 16 в Вашем патче ядра? #define MAX_PGORDER 16 /* 128GB per one table */ Выглядит, как костыль в будущем, а, пожалуй, даже в настоящем.

Была надежда, что возможно данные изменения не работали лишь на версии 0.6.7 (куда мы их перенесли вручную). Поэтому решили собрать ветку ak-1513 на основе master-ветки с будущей версией 0.7.

Как мы писали, с Линуксом мы работаем совсем недавно, поэтому для нас многое в новинку, в т.ч. компиляция ядра с дополнительными патчами.

Ваша Wiki по установке из исходников явно требует к себе внимание: 1. Неплохо бы в apt-get install добавить fakeroot. 2. В разделе "Configure Kernel" неплохо было бы в начале привести сами команды подготовки файлов для сборки, создания копий конфига и запуска программ его редактирования, а уже ПОСЛЕ этого писать какие параметры нужно изменить, а не наоборот, т.к. это вводит в тупик (пытаешься понять, где же я должен это изменить эти параметры, если ничего еще не открыли на редактирование...). 3. Первый запуск с функцией "make oldconfig" из WiKi привел к анкетированию (как оказалось, около 4 тыс. вопросов, на многие из которых без захода в мануалы и в Google по 20 минут - не ответишь). Выставление всех параметров, которые небыли выставлены или отсутствовали в старом ядре - это явно работа программистов, занимающихся отладкой ядра, под какую-то узкую конфигурацию оборудования и доведение ее до "блеска", а не человека, который просто хочет протестить, как работает утилита на новой версии ядра. Даже на сайте "Kernel.org" было сказано, что настройка параметров ядра через "oldconfig" займет очень и очень много времени и поэтому благоразумнее было бы использовать функцию "olddefconfig", для выставления всех параметров в значение по умолчанию с ответом "да" или "oldnoconfig" - с ответом "нет". Как нам кажется, "olddefconfig" - был бы идеален в Вашей инструкции, особенно для новичков и опытных пользователей, у которых нет лишних 48-и часов на прохождение анкеты из 4 тыс. вопросов (почти 40% конфиг-файла в режиме is not set, а конфиг под новое ядро отличается от stretch версии более, чем на 2 тыс. строк). 4. Псевдографические утилиты menuconfig, nconfig, xconfig, gconfig кроме предоставления удобства требуют еще и знания в каком разделе, подразделе, под подразделе и т.д. искать нужный параметр. Но к сожалению, у Вас просто приведены сами наименования параметров => найти их в этих утилитах крайне НЕпросто и после того, как удалось найти не больше 3-х параметров, было решено "плюнуть" на эту затею и открыв файл .config в обычном mc - просто поиском найти эти параметры и изменить. Наш опыт говорит о том, что-либо нужно указать, в каких разделах искать данные параметры в этих псевдографических утилитах, либо указать способ прямого редактирования конфиг-файла без всяких утилит. 5. Скриншот из menuconfig как-то не соответствует данным версиям (возможно стоит заменить).

Когда мы все-таки скомпилировали ядро, то были сильно разочарованы в том, что релиз 0.7 в отличие от 0.6.7 стал иметь повышенные требования к процессору. Наличие инструкций bmi2 и adx, согласно make файлу, стали обязательными. Вопрос: Стоило ли увеличение производительности TLS модуля на 40% полного устранения линейки Haswell из поддерживаемых процессоров? Серверные системы стоят дорого (более одного млн. рублей). Поэтому даже крупные компании, содержащие дата центры массово избавляются от оборудования не ранее, чем через 7-10 лет. Это же является и благоприятным временем для сбора относительно-дешевых серверных систем компаниям по меньше. Ваша программа является Open Source проектом, но для ее использования Вы постоянно стараетесь увеличить требование к оборудованию. На Вашей весенней конференции в HighLoad 2021 Вы уже даже начали присматриваться к функциям avx-512 из Ice Lake, которым только пару лет. По нашему мнению, требования к оборудованию растут слишком быстро:

Тревожная тенденция. Начинает напоминать оборудование Cisco, в котором для получения новых функций нужно купить новую "железяку" за много-много тыс. $, но ведь это Open Source программа и было бы странно ради БЕСПЛАТНОЙ программы, раз в 2 года обновлять серверное оборудование на несколько миллионов рублей. В этом случае функция update в скрипте смотрится, как издевка, потому что перед тем, как ее запустить по Вашей логике нужно выкинуть старое оборудование и купить новое, а заодно и развернуть все остальные подсистемы на новом железе. Мы понимаем, что Вы стремитесь увеличить производительность своей программы и это хорошо и правильно, но такой подход к будущим пользователям / клиентам явно несовершенен. Потеря производительности на Haswell по сравнению с Broadwell согласно Вашим графикам с одной из конференций была не более, чем в 2 - 3 раза (возможно в 4), но Вы тестируете на малоядерных, однопроцессорных системах (не более 4-х ядер), в то время, как даже на 10 летних серверах Haswell может быть от 48 до 64 ядер, что как минимум в 12 раз больше чем у Вашей системы, а значит даже при снижении производительности в 4 раза - она все равно будет в 3 раза быстрее + доп. выигрыш от объемов серверной памяти, когда на обычных десктопах она не превышает 64-128 ГБ, а на серверах спокойно может достигать величин более 6 ТБ на 4 процессорных системах. Поэтому, новый десктопный Broadwell будет сильно проигрывать серверному Haswell. К чему мы клоним... Процессоры, с новыми все более быстрыми и удобными в использовании инструкциями будут выходить каждый год, но это не значит, что уже сделанные наработки под старые процессоры нужно полностью выкидывать из кода, куда более благоразумно просто ветвить код. Если процессор старый, то используем эту инструкцию. Если новее - то другую и т.д. В этом случае программа будет продолжать работать и на старом железе, а когда пользователь его обновит, то он получит прирост производительности. При этом он уже будет до этого спокойно пользоваться программой несколько лет. У него будут рабочие конфиги и опыт настройки. Главное, что для этого не нужно писать новый код, а нужно просто НЕ ВЫБРАСЫВАТЬ старый. Тем более, мест в коде, где используются инструкции - не так много. Для того же TLS можно было оставить дополнительно его реализацию в ядре Линукс (просто в дополнение к вашему усовершенствованному варианту). Как правило, инструкции не дают нам новые функции, которые мы не могли бы реализовать с использованием старых инструкций или вообще без инструкций, а лишь дают увеличение скорости. Это будет накладывать дополнительные расходы времени на поддержание старого кода, но они вряд ли столь значительны. Тем более у Вас есть команда. Да и подумайте над тем, что многие утилиты под Debian, особенно WAF, firewall, IPS и т.п. очень часто ставят и на слабые "железки" тоже, те же роутеры на основе RouterOS и т.п. И там явно не будет Ваших инструкций. При этом сам Debian без проблем на них встанет. По нашему мнению, сам Linux - это и есть пример хорошего ПО, которое имеет широкий функционал и работает практически на любом железе.

Было бы очень неплохо, если бы Вы не выпиливали полностью старые рабочие функции, а оставляли их и добавляли свои, более скоростные их версии, НО в качестве альтернативы.

Таким образом, из-за ужесточения требования к процессору на своем парке машин скомпилировать ветку ak-1513 не получилось. Как мы и писали выше, пришлось искать помощи со стороны. Для этого мы специально начали искать машину с установленным Broadwell. К сожалению, в своем доступном парке мы ее не нашли, что вызвало большую задержку. К счастью, у одного из знакомых такой процессор был найден. И спасибо ему большое, за то, что он согласился потратить своих 4 часа на то, чтобы мы все протестировали.

В конечном итоге, код из данной ветки скомпилировался с незначительными warning: изображение изображение

Но программа вела себя точно также, как и при переносе этих изменений на версию 0.6.7. Максимальное значение, при котором Tempesta запускается - 2 ГБ минус 2 МБ, что как бы наталкивает на мысль, что мы уперлись в ограничение типа данных у переменных, которые оперируют данными значениями.

Выставляем cache_size 2046 МБ (2 145 386 496) - это максимально возможное кратное, что можно выставить изображение Примечание: На версии 0.6.7 2 ГБ без 2 МБ выставить не удается. Нужно уменьшить на 42 МБ вместо 2 МБ.

Выставляем cache_size 2 ГБ ровно (2 147 483 648) - провал изображение

Выставляем cache_size 4 ГБ минус 48 МБ (3 таблицы по 16 МБ) (4 244 635 648) - провал изображение

Нас лимитирует число 2 147 483 648, которое является ПРЕДЕЛОМ для типа данных long (хоть для unsigned long значение и должно было быть в 2 раза больше) "https://docs.microsoft.com/ru-ru/cpp/c-language/cpp-integer-limits?view=msvc-160" "https://ru.wikipedia.org/wiki/Система_типов_Си"

В файле "fw/cfg.c" Вы применили для вот этих функций tfw_cfg_set_long() tfw_cfg_parse_long() в качестве параметров выходного значения переменные типа unsigned long. Вопрос: Как в данном типе переменной может храниться байтовое значение до 128 ГБ (137 438 953 472)? Не подходит ли для этого лучше тип данных unsigned long long (18 446 744 073 709 551 615) - почти 16 эксабайт. Вот это точно запас на будущее. На наш взгляд, эта проблема касается не только подсистемы парсинга кэша, но и подсистем выделения памяти и управления файлами подкачки (хранение кэша), например, в фале "db/core/file.c" при определении массива MArea, элемент массива start по сути являющийся байтовым значением, с которого начинается отсчет выбираемого интервала так же определен переменной unsigned long, а значит не способна указывать на большие адреса. Тоже самое касается переменной len, используемой для передачи запрашиваемого объема памяти в функциях ma_get_best_fit(), ma_split(), tempesta_map_file(), tempesta_unmap_file(). Тоже самое касается переменных addr и size в этом же файле и в файле file.h. Даже сама ядерная функция парсинга значения из конфига kstrtoul(), используемая в функции tfw_cfg_parse_long() в файле "fw/cfg.c" НЕ МОЖЕТ вернуть результат, размерностью более unsigned long. Вот ее написание в файле "/include/linux/kernel.h": `static inline int __must_check kstrtoul(const char s, unsigned int base, unsigned long res) { /*

В данном случае не совсем понятно, как из первого return значение типа unsigned long long возвращается в переменную res, размерностью unsigned long (хоть эти два типа и занимают оба по 8 байт). При этом сама функция kstrtoull() - регламентируется в этом файле, как для внутреннего использования, но в том же Android версии Lolipop есть функция `static int _kstrtoull(const char s, unsigned int base, unsigned long long *res)` для полноценного парсинга значений unsigned long long. "https://android.googlesource.com/kernel/msm/+/android-msm-shamu-3.10-lollipop-mr1/lib/kstrtox.c"

Единственное, что в новых Линуксах эту функцию перенесли с kernel.h в kstrtox.c для разгрузки первого.

Так же нам удалось захватить краш ядра с помощью режима netconsole, который Вы посоветовали:

Системе выделено 64 ГБ ОЗУ tempesta_dbmem=13 (выделяется 2 блока по 16 ГБ) Зарезервировано 50% от доступной памяти. Настройка кэша на 3 ГБ Результат: ПАДЕНИЕ ЯДРА изображение изображение изображение изображение изображение изображение

Небольшое заключение: 1) Нам пока тяжеловато в незнакомой среде тестить чужой софт и потом самим пытаться искать в нем ошибки. Было бы замечательно, если бы Вы САМИ, СВОЕЙ КОМАНДОЙ ПОЛНОСТЬЮ проверяли внесенные Вами изменения, как то, например, поддержка до 128 ГБ памяти под кэш, т.к. на системе с выделенными 136 ГБ памяти не смогли отработать ни патч ядра, с захватом 2 по 64, ни парсинг конфига, ни скорее всего аллокация памяти. Полученные результаты Вам дали бы гораздо больше сведений о работе Ваших подсистем в реальных условиях, чем нам. 2) Еще раз подумайте над оставлением поддержки хотя бы процессоров Haswell, пусть и с пониженной производительностью. 3) Небольшой вопрос. При настройке конфига ядра, когда мы выбираем SLUB аллокатор, его нужно включать в дополнение к SLAB аллокатору, или при его включении SLAB аллакатор нужно отключить? В интернете четкого ответа не нашлось, чаще всего их рассматривают как альтернативные версии, но судя по коду SLUB аллокатор вызывается из файла slab.h. Так как правильно настроить?

P.S. Сливание тестовых веток, в которых не было подтверждено устранение issue со стороны пользователей и при этом НЕ БЫЛО проведено полноценное тестирование внесенных изменений (выставление cache_size=128 ГБ с последующим удачным запуском), с основной master веткой - нежелательная практика, т.к. приводит к накоплению ошибок в основном коде.

voodam commented 3 years ago

Ваша Wiki по установке из исходников явно требует к себе внимание:

Спасибо за замечания, обновил вики.

DagothDeer commented 3 years ago

@voodam Надеемся, что это не весь Ваш ответ. Нас интересуют ответы, на все описанные выше проблемы.

voodam commented 3 years ago

@DagothDeer

Надеемся, что это не весь Ваш ответ.

Да, конечно.

Когда мы все-таки скомпилировали ядро, то были сильно разочарованы в том, что релиз 0.7 в отличие от 0.6.7 стал иметь повышенные требования к процессору. Наличие инструкций bmi2 и adx, согласно make файлу, стали обязательными. Вопрос: Стоило ли увеличение производительности TLS модуля на 40% полного устранения линейки Haswell из поддерживаемых процессоров?

Это починю.

По остальному @krizhanovsky, думаю, ответит через некоторое время.

krizhanovsky commented 3 years ago

@DagothDeer больше спасибо за столь подробный баг репорт! Мы очень благодарны Вам за время, которое вы уделили Tempesta FW и этому репорту. Могу я узнать Ваш use case для Tempesta FW? Если не трудно, напишите, пожалуйста, на ak@tempesta-tech.com.

Прежде всего, Tempesta FW еще находится в альфе, в основном как раз из-за незавершенного функционала кэша. Поэтому, не судите, пожалуйста, нас слишком строго :)

Тестирование различных значений параметра "tempesta_dbmem" при различных значениях ОЗУ

Алокация huge pages происходят на этапе загрузки системы, в функции tempesta_reserve_pages() - она работает с buddy аллоктором, который нахлдится под kmalloc.

Я воспроизвел проблему на VM с 24GB RAM и tempesta_dbmem=13. При этом hugepagesz=2MB hugepages=8200 (даже немного больший объем памяти) выделяют страницы. Думаю, нам нужно пользоватья тем же механизмом.

Системе выделено 36 ГБ ОЗУ....Попытка зарезервировать 89% от доступной памяти.

В Linux huge pages не могут быть переиспользованы (если их, конечно сам пользователь не возвращает в систему). 4GB для сетевого ввода вывода и сами HTTP сообщения - это заведомо очень мало. Я бы советовал оставлять системе 10-16GB или 20% RAM. Но нам нужно будет лучше оценить эти значения.

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

Да, обсолютно верно: файловый кэш - не эффективно. Tempesta DB - это in-memory database, у которой есть требование persistency, поэтому есть файлы. Проблема файловых кэшей в том, что каждая запись (web cache entry) - это отдельный файл, который нужно открывать и закрывать, пусть даже с кэшом открытых файловых дескрипторов. Индекс - это структура файловой системы, а dentry lookup в файловой системе - очень медлено.

Основная задача, которая должна быть сделана для выхода беты - это как рах большой объем доделок веб кэша https://github.com/tempesta-tech/tempesta/issues/515 .

Как Вы думаете, пользователи сервиса поймут, почему они ДОЛЖНЫ ждать целых 6 часов пока сервис не возобновит свою работу, если админ захочет просто перезагрузить машину?

Нет, Tempesta DB должна в бэкграунде сбратывать грязные страницы, например, как это делает InnoDB: вам же не надо ждать часами прогревки buffer pool для большой СУБД. Хотя, по-моему у Percona был патч принудительного разогрева кэша - старт медленный, но дает высокую скорость в run time.

Иметь возможность сконфигурировать кэш без персистентности - это хорошая мысль. Я обновил #515. Спасибо.

Кстати, чем обусловлено выбранное ограничение показателя степени двойки, равного 16 в Вашем патче ядра?

Структурой индекса Tempesta DB. На это тоже есть отдельный пункт в #515.

Ваша Wiki по установке из исходников явно требует к себе внимание:

Сборка ядра - это не то, чем мы хотим, чтобы наши пользователи занимались :) Еще раз спасибо за ваше время со сборкой и патчами Tempesta. Нормальный пользовательский workflow - это инсталляция из пакетов https://github.com/tempesta-tech/tempesta/wiki/Install-from-packages .

К сожалению, в данный момент нам не хватает ресурсов на разработку и до беты usability не в первом приоритете.

Стоило ли увеличение производительности TLS модуля на 40% полного устранения линейки Haswell из поддерживаемых процессоров?

Да. Мы сейчас в альфе и фокусируемся на платформах, актуальных к планируюшейся бете.

Вы тестируете на малоядерных, однопроцессорных системах (не более 4-х ядер),

Нет, на таких системах мы ведем разработку. А для тесирования мы aрендуем Skylake сервера (например, https://github.com/tempesta-tech/tempesta/wiki/HTTP-cache-performance или https://github.com/tempesta-tech/tempesta/wiki/HTTPS-performance ). Мы арендуем и более серьезное железо, но для генераторов трафика. Если мы запустим Tempesta на десятках ядер, то нам потребуется уже несколько серверов и 100Gbps каналы с свитчи, чтобы ее загрузить.

Главное, что для этого не нужно писать новый код, а нужно просто НЕ ВЫБРАСЫВАТЬ старый.

Требование Broadwell появилось из-за математики в Tempesta TLS. Крипто-алгоритмы у нас написаны снуля (мы все же заимствуем GPLv2 код, не не так много, как хотелось бы). При выборе написать более быстрый код для более быстрого процессора, который на рынке уже 5 лет, или написать legacy, будучи еще в альфе, конечно, мы выбрали первое. То, что у нас было до этого, это C код от mbed TLS, который более, чем в 10 раз медленее любой хорошей ассемблерной реализации. @voodam сейчас работает над портированием кода на Haswell. На этой неделе мы можно ли заимствовать код и, по всей видимости, нет. Сейчас мы не сможем выделить достаточно много времени на эту задачу и будем надеятся, что ее получится сделать быстро.

Нас лимитирует число 2 147 483 648, которое является ПРЕДЕЛОМ для типа данных long (хоть для unsigned long значение и должно было быть в 2 раза больше)

unsigned long на x86-64 имеер размер 8 байт и эквивалентен unsigned long long (эти типы различаются на 32х битной x32). Но проблема все равно есть, как есть и крэш.

Еще отдельное спасибо за call trace падения - по нему мы сможем поймать баг.

К сожалению, мы сможем исправить эту проблему только в milestone 0.8: в #515 кэш будет очень сильно меняться. Кроме описанных Вами багов, есть еще ряд проблем, которые должны быть исправлены в 0.8 https://github.com/tempesta-tech/tempesta/issues?q=is%3Aopen+label%3Abug+label%3Acache . В частности tdb_entry_walk(), на которой случился крэш, будет переписываться.

Мы можем брать задачи в более ранний релиз только в случае запросов от наших клиентов. Если у вашего бизнеса есть потребность в Tempesta FW и оперативном фиксе проблемы, пожалуйста, напишите мне на ak@tempesta-tech.com . И/или рассмотрите возможность спонсирования проекта https://github.com/sponsors/tempesta-tech . При оформлении поддержки мы можем быстро настроить Tempesta FW на вашем железе.

Также у нас есть Slack канал https://join.slack.com/share/zt-vcf0ram8-yWqaPNL1aVN9moCejvFjtA?skip_onboarding=1 , в котором Вы можете задавать любые вопросы нашей команде по Tempesta FW.

Небольшой вопрос. При настройке конфига ядра, когда мы выбираем SLUB аллокатор, его нужно включать в дополнение к SLAB аллокатору, или при его включении SLAB аллакатор нужно отключить? В интернете четкого ответа не нашлось, чаще всего их рассматривают как альтернативные версии, но судя по коду SLUB аллокатор вызывается из файла slab.h. Так как правильно настроить?

Да, это альтернативные реализации. На stackoverflow есть хороший ответ https://stackoverflow.com/questions/15470560/what-to-choose-between-slab-and-slub-allocator-in-linux-kernel . Так же в init/Kconfig:

choice
    prompt "Choose SLAB allocator"
    default SLUB
    help
       This option allows to select a slab allocator.

config SLAB
    bool "SLAB"
    select HAVE_HARDENED_USERCOPY_ALLOCATOR
    help
      The regular slab allocator that is established and known to work
      well in all environments. It organizes cache hot objects in
      per cpu and per node queues.

config SLUB
    bool "SLUB (Unqueued Allocator)"
    select HAVE_HARDENED_USERCOPY_ALLOCATOR
    help
       SLUB is a slab allocator that minimizes cache line usage
       instead of managing queues of cached objects (SLAB approach).
       Per cpu caching is realized using slabs of objects instead
       of queues of objects. SLUB can use memory efficiently
       and has enhanced diagnostics. SLUB is the default choice for
       a slab allocator.

config SLOB
    depends on EXPERT
    bool "SLOB (Simple Allocator)"
    help
       SLOB replaces the stock allocator with a drastically simpler
       allocator. SLOB is generally more space efficient but
       does not perform as well on large systems.

Summary

  1. It seems we need to use the Linux native hugetlb mechanism to reserve huge pages in more reliable way (see Documentation/vm/hugetlbfs_reserv.rst and mm/hugetlb.c).
  2. The huge pages are mapped to physical pages, which can not be reused, so need to update Wiki with some guidance which percentage of RAM is good to pass to Tempesta DB. Probably a simple script examining the system and printing the suggested setting would be beneficial.
  3. ~We'll try to reimplement several Tempesta TLS math routines for compatibility with Haswell~. Out of the scope - we don't have resources to develop the backward compatibility.
  4. Need to fix the crash on tdb_entry_walk()
  5. 515 adds requirement to test the new web cache on 4GB and larger sizes

krizhanovsky commented 3 years ago

Я переименовал задачу по итогу разбора проблем, описанных в ней.

krizhanovsky commented 1 year ago

let's fix the tdb_entry_walk() crash and leave the rest for the next version of TDB

const-t commented 9 months ago

I suggest consider memblock API mm/memblock.c for reserving memory.

krizhanovsky commented 9 months ago

I confirm that there is a problem at least with the web cache database mapping. I have a VM with 16GB RAM, tempesta_dbmem=12. If I configure Tempesta FW as

cache 1;
cache_size 4294967296;

I get

[  173.635749] [tdb] ERROR: Cannot read 4294967296 bytes to addr 00000000ae2f281c, ret = 2147479552
[  173.636600] [tdb] ERROR: Cannot map file
[  173.637012] [tdb] ERROR: Cannot open db for /opt/tempesta/db/cache.tdb

The same for 2GB cache_size:

[  375.784707] [tdb] ERROR: Cannot read 2147483648 bytes to addr 00000000344abccb, ret = 2147479552
[  375.785644] [tdb] ERROR: Cannot map file
[  375.786202] [tdb] ERROR: Cannot open db for /opt/tempesta/db/cache.tdb

And only 1GB cache configuration succeeded.

Also we need to fix the design problem with the powers of 2. Having a machine of 16GB RAM I have to, I can specify tempesta_dbmem=12 (8GB) the maximum to leave some memory for the rest of OS. This might be reasonable for 16GB RAM, but will be inadequate for say 128GB and more RAM.

Need to

krizhanovsky commented 1 month ago

From time to time we see:

root@tempesta-1:~# systemctl restart tempesta-fw.service 
Job for tempesta-fw.service failed because the control process exited with error code.
See "systemctl status tempesta-fw.service" and "journalctl -xeu tempesta-fw.service" for details.
root@tempesta-1:~# dmesg|tail
[   29.348480] Huh? What family is it: 0x19?!
[   29.548325] Huh? What family is it: 0x19?!
[   29.768662] Huh? What family is it: 0x19?!
[   29.937552] Huh? What family is it: 0x19?!
[   30.097914] Huh? What family is it: 0x19?!
[   30.207769] Huh? What family is it: 0x19?!
[686522.920763] [tdb] Start Tempesta DB
[686522.921614] [tdb] ERROR: Cannot get mapping for node 0
[686544.519878] [tdb] Start Tempesta DB
[686544.520638] [tdb] ERROR: Cannot get mapping for node 0

On Tempesta restart and VM reboot helps.