Меряю потолки потоков для серии, которую пишу. Думал, упрусь в константу ядра, а уперся в systemd. В статью эта развилка не влезет, утянет главу в тюнинг ядра, а здесь ей самое место.
Тест примитивный:
pthread_create в бесконечном цикле, каждый поток сразу засыпает навсегда. Смотрю, на каком номере ядро скажет хватит.Обычный терминал.
поток #75275 не создался: Resource temporarily unavailable (errno 11)
В
/proc/sys/kernel/threads-max при этом лежит 501995, в ulimit -u 250997, но до них дело не дошло. Обрубил не ядро, а systemd: DefaultTasksMax выдает моему scope 75299 задач, ровно 15% от threads-max.А теперь то, ради чего я вообще это писал. Потолок не константа, он едет за лимитами:
ulimit -u 30000 # обрыв на потоке #29276
ulimit -u 60000 # обрыв на потоке #59276
Снимаю потолок systemd и поднимаю
ulimit:systemd-run --user --scope -q -p TasksMax=infinity bash -c 'ulimit -u 150000; /tmp/pthread_limit'
поток #149273 не создался: Resource temporarily unavailable (errno 11)
Каждый раз тот же
errno, и каждый раз обрыв в другом месте. До круглого числа ulimit не дотягивает, потому что RLIMIT_NPROC считает все задачи пользователя, а не только мои. И ни разу это не ядро: threads-max так и остался нетронутым на полумиллионе. На маке, где я мерил до этого, лестницы нет вовсе: потолок прибит константой sysctl kern.num_taskthreads, прогон обрывался на потоке #4096.Есть и еще один потолок, до которого я не добрался.
ulimit -s равен 8192 КБ, то есть каждый поток резервирует под стек 8 МБ. Отдельным замером: десять тысяч потоков забрали 80 ГБ виртуального адресного пространства и 81 МБ физической. Системе все равно, страницы никто не трогает.Оба теста лежат в репозитории, каталоги pthread_limit и pthread_cost: собираются одним gcc, порт под macOS рядом.
Вывод у меня скорее эксплуатационный. Если сервис уперся в потолок потоков, смотреть надо не в характеристики машины, а в
pids.max того cgroup, где он живет. Ядро готово дать полмиллиона, а обычный терминал получил 75 тысяч. В кубере поверх этого ляжет еще и podPidsLimit :-)
