| Summary: | MDB_TXN_FULL: Transaction has too many dirty pages при работе с большими группами в домене | ||||||
|---|---|---|---|---|---|---|---|
| Product: | Sisyphus | Reporter: | Дмитрий <supertuxxx> | ||||
| Component: | liblmdb | Assignee: | Evgeny Sinelnikov <sin> | ||||
| Status: | NEW --- | QA Contact: | qa-sisyphus | ||||
| Severity: | normal | ||||||
| Priority: | P5 | CC: | alimektor, shevchenkodyu, slev, supertuxxx | ||||
| Version: | unstable | ||||||
| Hardware: | x86_64 | ||||||
| OS: | Linux | ||||||
| Attachments: |
|
||||||
Версия
- samba-dc-4.21.9-alt1
Шаги Воспроизведения (показан простой способ воспроизведения)
Достаточно одного DC: неважно с storage-backend mdb или по умолчанию.
Тестировалось с RAM 10Gb.
1. Создать 130000 пользователей и добавить их в одну группу:
# samba-tool group list | grep '^group'
groupccaabdb
# samba-tool group listmembers $(samba-tool group list | grep '^group' | head -n 1 | xargs) | wc -l
130000
2. Удалить данную группу:
# samba-tool group delete $(samba-tool group list | grep '^group' | head -n 1 | xargs)
Ожидаемый результат: Успешное удаление группы.
Фактический результат: Ошибка
MDB_TXN_FULL: Transaction has too many dirty pages. Примерный вывод:
replmd_delete_internals: Failure to handle 'delete' of object CN=groupccaabdb\0ADEL:90164629-ef33-440d-a280-925f91b91264,CN=Deleted Objects,DC=samba,DC=testdomain after successful rename to CN=groupccaabdb,CN=Users,DC=samba,DC=testdomain. Error during tombstone modification was: Failed to remove backlink from CN=groupccaabdb\0ADEL:90164629-ef33-440d-a280-925f91b91264,CN=Deleted Objects,DC=samba,DC=testdomain to CN=userfdcbdcdawr,CN=Users,DC=samba,DC=testdomain - (-30788) - MDB_TXN_FULL: Transaction has too many dirty pages - transaction too big at ../../lib/ldb/ldb_mdb/ldb_mdb.c:203
ERROR(ldb): Failed to remove group "groupccaabdb" - replmd_delete: Failed to modify object CN=groupccaabdb,CN=Users,DC=samba,DC=testdomain in 'delete' - Failed to remove backlink from CN=groupccaabdb\0ADEL:90164629-ef33-440d-a280-925f91b91264,CN=Deleted Objects,DC=samba,DC=testdomain to CN=userfdcbdcdawr,CN=Users,DC=samba,DC=testdomain - (-30788) - MDB_TXN_FULL: Transaction has too many dirty pages - transaction too big at ../../lib/ldb/ldb_mdb/ldb_mdb.c:203
File "/usr/lib64/samba-dc/python3.12/samba/netcmd/group.py", line 394, in run
samdb.delete(group_dn)
Анализ проблемы. Ошибка `MDB_TXN_FULL` ("Transaction has too many dirty pages") вызвана архитектурным ограничением в реализации `liblmdb`.
Причина кроется в макросе `MDB_IDL_LOGN` (определен в `libraries/liblmdb/midl.h`), который по умолчанию равен 16.
Этот параметр определяет размер списка ID (dirty list/spill list) для транзакции как `1 << (MDB_IDL_LOGN + 1)`.
При дефолтном значении 16 лимит составляет `1 << 17` = 131 072 страниц.
В нашем случае при модификации группы размером ~128 571 пользователей количество изменяемых страниц (данные + индексы + метаданные) превышает этот порог, что приводит к откату транзакции.
Вариант решения.
Увеличить значение `MDB_IDL_LOGN` до **17** при сборке пакета.
Это поднимет лимит до `1 << 18` = 262 144 страниц, чего достаточно для обработки текущих объемов (группы по 150к+ пользователей).
Анализ рисков и совместимости.
1. ABI (Application Binary Interface):
Бинарная совместимость приложений сохраняется. Макрос используется только внутри библиотеки (internal header `midl.h`), публичный API (`lmdb.h`) и структуры данных, передаваемые наружу, не меняются. Пересборка зависимых пакетов (Samba, OpenLDAP и др.) не требуется.
2. Совместимость данных (On-disk format):
Здесь есть нюанс. Если модифицированная библиотека запишет в БД список свободных страниц (Freelist), превышающий стандартный лимит (131к), то стандартная версия liblmdb не сможет корректно работать с этим файлом БД.
Это означает потерю "обратной совместимости" базы данных: файл, созданный/измененный на patched-версии с большими транзакциями, может вызывать краш (assertion failure) при открытии "ванильной" библиотекой (например, при даунгрейде пакета или переносе файла на другую систему).
3. Потребление ресурсов (Stack usage).
Массивы `MDB_IDL` часто аллоцируются на стеке.
- При LOGN=16 размер массива ~1 МБ.
- При LOGN=17 размер вырастет до ~2 МБ.
Для стандартных лимитов стека (8 МБ) это безопасно, но при глубокой рекурсии в Samba теоретически возможен Stack Overflow.
План действий.
Готовим тестовое задание на сборку `liblmdb` с `MDB_IDL_LOGN=17`.
Проводим нагрузочное тестирование репликации и удаления крупных групп, а также мониторинг потребления стека процессом `samba`.
|
Created attachment 20515 [details] скриншоты ошибок Проверено на стендах с Р10 и Р11. Конфигурация: Альт Сервер (Р10 или Р11, обновлённый до актуального на 17.01.26 состояния) Samba-DC 4.19.9-alt7-x86_64 и Samba-DC 4.21.9-alt1-x86_64 В случае, когда в домене имеются группы пользователей в большим количеством членств (на практике более 128571 пользователя) при вводе нового контроллера в домен посредством samba-tool join с --backend-store=mdb в процессе репликации основной БД процесс останавливается с ошибкой: ERROR(runtime): uncaught exception - (8, 'WERR_NOT_ENOUGH_MEMORY') При этом расход физических ресурсов контроллера далёк даже от 1/4 имеющихся. Размер получившегося на момент сбоя файла БД тоже далёк до пределов MAP_SIZE БД. Повышение уровня дебага показывает, что в момент, когда в очередной транзакции пытается реплицироваться одна из таких больших групп происходит событие: DSDB Transaction [rollback]. И следом сообщение об ошибке, что указано выше. Если ввести контроллер в домен с параметром --domain-critical-only, то контроллер в домен вводится, но в дальнейшем DRS репликация корневого NC домена останавливается с тем же сообщением - 'WERR_NOT_ENOUGH_MEMORY'. Если на имеющемся контроллере попытаться удалить такую группу целиком, получаем ошибку вида: ../../source4/dsdb/samdb/ldb_modules/repl_meta_data.c:4909: Failed to rename object from 'CN=megagroup-14,CN=Users,DC=corp,DC=alt' to 'CN=megagroup-14\0ADEL:1a1f3db6-d666-47bc-80d6-78cb1d36c73f,CN=Deleted Objects,DC=corp,DC=alt' - Linked attribute member->memberOf between CN=megagroup-14,CN=Users,DC=corp,DC=alt and CN=____bkovalev1960574760,CN=Users,DC=corp,DC=alt - update failed - (-30788) - MDB_TXN_FULL: Transaction has too many dirty pages - transaction too big at ../../ldb_mdb/ldb_mdb.c:203 ERROR(ldb): Failed to remove group "megagroup-14" - Linked attribute member->memberOf between CN=megagroup-14,CN=Users,DC=corp,DC=alt and CN=____bkovalev1960574760,CN=Users,DC=corp,DC=alt - update failed - (-30788) - MDB_TXN_FULL: Transaction has too many dirty pages - transaction too big at ../../ldb_mdb/ldb_mdb.c:203 Добавление/удаление пользователей по одному при этом работает. Если же уменьшить количество членств в группе до 128571 (определено методом проб), то группа успешно удаляется, репликация такой группы тоже проходит. Была найдена информация, что библиотека liblmdb имеет ограничение на количество "грязных страниц" в одной транзакции в 131072 (2^17). Исходя из количества членств (а каждое из них - это линк атрибутов member (группы) -> memberOf (пользователя)), есть предположение, что с учётом прочих изменяемых атрибутов при репликации/удалении группы проблема именно в этом ограничении liblmdb. Проблема может возникнуть при использовании продукта Альт Домен в инфраструктурах, где имеется большой штат сотрудников и группы доступа/безопасности с большим количеством членов. Несколько скриншотов с ошибкой ввода и попытками удаления группы при разном количестве членств во вложении.