Created attachment 15874 [details] Настройки nginx, Apache, тестовый PHP скрипт Для i586 есть только sysv. Без вариантов, ибо пакетов systemd для этой платформы нет в принципе. Я пользовался образом alt-p10-jeos-sysv-20240309-i586.iso. Для x86_64 пользовался образом alt-p10-jeos-systemd-20240309-x86_64.iso После установки вы получите локальную сеть на dhcp. Если нужен доступ извне, то потребуется настройка сети. Она сводится к созданию трех файлов в папке интерфейса (ищите в /etc/net/ifaces). Также, для работы DNS нужен /etc/resolv.conf Я забил туда серверы имен Яндекс. Увы, здесь поможет только vim. Опционально, можно настроить и hostname. Делается это редактированием /etc/sysconfig/network и последующей перезагрузкой. Для systemd ничего редактировать не надо, есть команда hostnamectl set-hostname example.com После, при необходимости, можно настроить sshd для доступа по паролям, ключам и т.п. А до этого момента все делается, если на хостинге, по VNC и подобному. Для настройки sshd предстоит лезть в файл /etc/openssh/sshd_config. Там есть параметр PermitRootLogin. Временно ему надо поставить значение yes. После копирования ключей и их добавления в authorized_keys параметр нужно вернуть в исходное значение. Если привыкли пользоваться mc, то очень полезно установить пакет glibc-locales. Локали там уже настроены, не хватает их описаний. В варианте с systemd это не требуется (все уже есть). Для последующей настройки WEB потребуются пакеты nginx apache2-httpd-event apache2-mod_fcgid php8.2-cgi Необходимые зависимости подтянуться. Далее уже мои персональные заморочки. Я использую именно этот MPM: alternatives-manual /usr/sbin/httpd2 /usr/sbin/httpd2.event alternatives-update Сделав это, вы увидите: # httpd2 -l Compiled in modules: core.c mod_so.c http_core.c event.c mod_unixd.c Определенно, на главный вопрос по PHP это не влияет. Но суеверия ... Этот шаг можно и пропустить. Далее рассовываете предзаготовленные настроечные файлы nginx, Apache и wrapper. Все это, и описанное выше есть в архиве. Там нужно поменять на свои IP и домены. Команды, которые могут оказаться полезны (папка WEB содержит распакованный архив, приложенный к этому тикету): $ cd WEB/etc/httpd2 $ scp -r conf/ root@vds.example.com:/etc/httpd2 $ cd WEB/etc/nginx $ scp -r sites-available.d/ root@vds.example.com:/etc/nginx $ cd WEB/var $ scp -r www/ root@vds.example.com:/var При настройке Apache у вас должно получиться: # a2chkconfig_list ports http no ports http-localhost-8088 yes extra httpd-addon.d no extra httpd-autoindex yes extra httpd-default yes extra httpd-icons yes extra httpd-languages yes extra httpd-mime yes extra httpd-mpm yes extra httpd-multilang-errordoc yes sites default no sites php yes sites ports_all no sites vhosts no mods access_compat yes mods alias yes mods authz_core yes mods authz_host yes mods autoindex yes mods dir yes mods fcgid yes mods include yes mods log_config yes mods logio yes mods mime yes mods negotiation yes mods systemd no Применение настроек делается командой a2chkconfig. nginx поставляется без таких удобств. Ссылку на /etc/nginx/sites-available.d/php.conf придется сделать самому. Далее запускаете службы: service httpd2 start service nginx start Для образа systemd, можно и без оберток: # systemctl start httpd2 # systemctl start nginx А далее то, для чего все затевалось: http://vds.example.com/mem.php?max=64 128M total 64M requested SUCCESS А хотим мы увидеть на http://vds.example.com/mem.php?max=128 вместо статуса 500 128M total 128M requested SUCCESS PS: если страница недоступна, то требуется открыть порт. Я делал это командой alterator-net-iptables write -s +www Для ее работы нужно установить пакет alterator-net-iptables (он потянет за собой и iptables) Я не вполне уверен, что это требуется (может порты и открыты), просто так делаю всегда. PS2: проблема легко обнаруживается и в "фирменном" образе docker php:8.1-apache (просто для моей задачи нужен именно он) А там уже модуль Apache. Почему я столкнулся с проблемой только сейчас - вопрос.
Добрый день, Анатолий! Не могли бы предоставить дополнительную информацию о вашей системе, приложив вывод следующих команд: uname -a cat /etc/os-release apt-repo rpm -qa | grep php И детальнее описать последовательность действий, приводящих к воспроизведению ошибки (можно только команды, которые используете именно вы, чтобы не возникало путаницы). Хотелось ещё уточнить, что выводит phpinfo() при ваших настройках? Соответствует ли его вывод ожидаемому?
(Ответ для Osmolovskaya Anastasia на комментарий #1) > Не могли бы предоставить дополнительную информацию о вашей системе, приложив > вывод следующих команд: > uname -a > cat /etc/os-release > apt-repo > rpm -qa | grep php Площадку для x86 я уже удалил. Осталась только 64-х битная (та, что из образа alt-p10-jeos-systemd-20240309-x86_64.iso). # uname -a Linux vds.example.com 6.1.79-un-def-alt1 #1 SMP PREEMPT_DYNAMIC Fri Feb 23 18:56:17 UTC 2024 x86_64 GNU/Linux # cat /etc/os-release NAME="starter kit" VERSION="10" ID=altlinux VERSION_ID=10 PRETTY_NAME="ALT Starterkit 10 (Hypericum)" ANSI_COLOR="1;33" CPE_NAME="cpe:/o:alt:starterkit:10" BUILD_ID="starter kit 10" ALT_BRANCH_ID="p10" HOME_URL="http://en.altlinux.org/starterkits" BUG_REPORT_URL="https://bugs.altlinux.org/" LOGO=altlinux # apt-repo -bash: apt-repo: команда не найдена # rpm -qa | grep php php8.2-libs-8.2.17-alt1.x86_64 php-base-2.7-alt3.x86_64 php8.2-8.2.17-alt1.x86_64 php8.2-cgi-8.2.17-alt1.x86_64 > И детальнее описать последовательность действий, приводящих к > воспроизведению ошибки (можно только команды, которые используете именно вы, > чтобы не возникало путаницы). Не вполне понял что еще требуется. Я описал, как из двух образов стартер китов (x86 и x86_64) сделать тестовую площадку. Выложил архив с необходимыми настройками. И предложил набрать в браузере определенный адрес (тестовый скрипт тоже в архиве есть). Написал что получилось и что надо. > Хотелось ещё уточнить, что выводит phpinfo() при ваших настройках? > Соответствует ли его вывод ожидаемому? Там установлена memory_limit на 128 МБ. Это стандартные значения для пакета. Ничего не менял. apt-repo, как видите, не установлена в образе. # apt-get update Получено: 1 http://ftp.altlinux.org p10/branch/x86_64 release [4223B] Получено: 2 http://ftp.altlinux.org p10/branch/x86_64-i586 release [1665B] Получено: 3 http://ftp.altlinux.org p10/branch/noarch release [2844B] Получено 8732B за 0s (43,6kB/s). Получено: 1 http://ftp.altlinux.org p10/branch/x86_64/classic pkglist [23,9MB] Получено: 2 http://ftp.altlinux.org p10/branch/x86_64/classic release [137B] Получено: 3 http://ftp.altlinux.org p10/branch/x86_64-i586/classic pkglist [17,5MB] Получено: 4 http://ftp.altlinux.org p10/branch/x86_64-i586/classic release [142B] Получено: 5 http://ftp.altlinux.org p10/branch/noarch/classic pkglist [7223kB] Получено: 6 http://ftp.altlinux.org p10/branch/noarch/classic release [137B] Получено 48,7MB за 9s (5078kB/s). Чтение списков пакетов... Завершено Построение дерева зависимостей... Завершено
Created attachment 15882 [details] Настроки PHP по лимиту памяти
Версия пакета: php8.2-fpm-fcgi-8.2.18-alt1.x86_64 Дополнительно: в sisyphus на данный момент нет возможности проверить Удалось воспроизвести ошибку по следующим шагам: 1. # systemctl stop httpd2 2. # apt-get install nginx php8.2-fpm-fcgi webserver-common 3. # cat > /etc/nginx/sites-enabled.d/default.conf <<EOF #load_module modules/ngx_http_geoip_module.so; #load_module modules/ngx_http_perl_module.so; #load_module modules/ngx_mail_module.so; #load_module modules/ngx_stream_module.so; server { listen localhost:80; server_name localhost localhost.localdomain; location / { root /var/www/html; } location ~* ^.+\.(ogv|iso|html)\$ { root /var/www/html; } location ~ \.php\$ { root /var/www/html; try_files \$uri =404; include /etc/nginx/fastcgi_params; fastcgi_pass unix:/var/run/php8.2-fpm/php8.2-fpm.sock; fastcgi_param SCRIPT_FILENAME /var/www/html/\$fastcgi_script_name; } location ~ /\.ht { deny all; } access_log /var/log/nginx/access.log; } EOF 4. # cat > /var/www/html/index.php <<EOF <?php header('Content-Type: text/plain'); print ini_get('memory_limit') . ' total' . PHP_EOL; $max=intval($_GET['max']); if (!$max) $max = 127; print $max . 'M requested' . PHP_EOL; for($i=1;$i<=$max;$i++) $a[]=str_repeat(chr($i),1024*1024); // 1 Mb die("SUCCESS"); ?> EOF 5. # systemctl restart nginx php8.2-fpm 6. Проверить вывод: # curl -s 'http://localhost/index.php?max=64' # curl -s 'http://localhost/index.php?max=128' Ожидаемый результат: успешный вывод команд 128M total 64M requested SUCCESS 128M total 128M requested SUCCESS Реальный результат: При выполнении # curl -s 'http://localhost/index.php?max=64' успешный вывод При выполнении # curl -s 'http://localhost/index.php?max=128' вывод отсутствует. В логах /var/log/nginx/error.log будет ошибка: FastCGI sent in stderr: "PHP message: PHP Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 1052672 bytes) in /var/www/html/index.php on line 12" while reading response header from upstream, client: 127.0.0.1, server: localhost, request: "GET /index.php?max=128 HTTP/1.1", upstream: "fastcgi://unix:/var/run/php8.2-fpm/php8.2-fpm.sock:", host: "localhost"
Воспроизводится в sisyphus
Позволю себе ворваться, но здесь нет ошибки. Все правильно, этот скрипт поедает заведомо больше. Достаточно добавить в цикле, где заполняется строка вывод реально выделяемой памяти: print(memory_get_usage() / 1048576 . "Mb /". memory_get_usage(true) / 1048576 . " Mb Real\n"); Будет видно, что когда автор ожидает, что у него 64, на самом деле он уже скушал 128. 64.624717712402Mb / 128Mb Real PHP Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 1052672 bytes)
(Ответ для keleth на комментарий #6) > Позволю себе ворваться, но здесь нет ошибки. > Все правильно, этот скрипт поедает заведомо больше. > Достаточно добавить в цикле, где заполняется строка вывод реально выделяемой > памяти: > print(memory_get_usage() / 1048576 . "Mb /". memory_get_usage(true) / > 1048576 . " Mb Real\n"); > > Будет видно, что когда автор ожидает, что у него 64, на самом деле он уже > скушал 128. > 64.624717712402Mb / 128Mb Real > PHP Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to > allocate 1052672 bytes) На этом скрипте так быть не должно. Там в цикле запрашивается 1МБ за один проход. Если PHP при этом занимает не один, а два мегабайта - в этом и проблема. Для интересующихся - этот скрипт основан на стандартном тесте Битрикс. Мои дополнения там незначительны и имеют другой отступ. Если выяснится, каким-то чудом, что тест написан неверно, будет повод обратиться в поддержку Битрикс. А пока ситуаций так себе ...
Ну как не должно? это суровая действительность. Проверно на доступных мне: Debian c php 8.2/8.3, Альте 10 и Сизиф.
(Ответ для keleth на комментарий #8) > Ну как не должно? это суровая действительность. > Проверно на доступных мне: Debian c php 8.2/8.3, Альте 10 и Сизиф. Да причем тут это? Я проверял скриптом, который в Битрикс используется для проверки РЕКАЛЬНО ДОСТУПНОГО
млин, что-то не то нажал. И не исправить ничего ... Это тест реально доступного объема памяти. И реально доступный объем меньше в два раза выделенного по настройке memory_limit. Какая разница, что это везде так? Да я и знаю, что это так. О чем написал в самом первом сообщении. Даже в фирменном docker конетейнере эта болячка есть. А там другой SAPI. Я проверял сам в FCGI. Команда убедилась в реальности проблемы на FPM. А docker сделан на mod_apache.
Так ошибка в тесте, вот пришлось пойти и вспоминать основы PHP: "PHP активно использует механизм copy-on-write. Это означает, что при попытке внутри функции что-то записать в переданные ей параметры, вначале будет сделана копия этой переменной, а уж затем в неё что-то запишется. " Таким образом, когда мы добираемся в цикле до 64 итерации, то, чтобы добавить еще 1 мегабайт в массив, нам нужно уже 128 - все, финал. Вопросы к авторам теста.
(Ответ для keleth на комментарий #11) > Так ошибка в тесте, вот пришлось пойти и вспоминать основы PHP: > "PHP активно использует механизм copy-on-write. Это означает, что при > попытке внутри функции что-то записать в переданные ей параметры, вначале > будет сделана копия этой переменной, а уж затем в неё что-то запишется. " > > Таким образом, когда мы добираемся в цикле до 64 итерации, то, чтобы > добавить еще 1 мегабайт в массив, нам нужно уже 128 - все, финал. > Вопросы к авторам теста. Тогда логично было бы при запросе 64 МБ получить 65 использованных. Разве нет? Вот оригинальный тест: elseif (@$_GET['memory_test']) { $max=intval($_GET['max']); if (!$max) $max = 255; for($i=1;$i<=$max;$i++) $a[]=str_repeat(chr($i),1024*1024); // 1 Mb die("SUCCESS"); } Там, как раз, учтен этот пресловутый мегабайт.
Я честно не совсем понял какой мегабайт был учтен, здесь просто создается строка размером примеррно с мегабайт и добавляется как новый элемент в массив $a. Ранее я тоже не совсем был прав, но топтался около. Когда существующий массив достигает пределов выделенной под него памяти, создается новый массив с бОльшим объемом зарезервированной под него памяти, в новый массив копируется содержимого старого, добавляется новый элемент и подменяется в переменной, по указателю или как там оно (здесь нам не важно), вот пока весь процесс переноса данных не быдет завершен - нельзя освободить старые данные, отсюда и удвоение размера памяти в пиковых случаях. Поэтому и говорю, что тест не совсем корректный. (Ответ для Анатолий Кирсанов на комментарий #12) > (Ответ для keleth на комментарий #11) > > Так ошибка в тесте, вот пришлось пойти и вспоминать основы PHP: > > "PHP активно использует механизм copy-on-write. Это означает, что при > > попытке внутри функции что-то записать в переданные ей параметры, вначале > > будет сделана копия этой переменной, а уж затем в неё что-то запишется. " > > > > Таким образом, когда мы добираемся в цикле до 64 итерации, то, чтобы > > добавить еще 1 мегабайт в массив, нам нужно уже 128 - все, финал. > > Вопросы к авторам теста. > > Тогда логично было бы при запросе 64 МБ получить 65 использованных. Разве > нет? > > Вот оригинальный тест: > > elseif (@$_GET['memory_test']) > { > $max=intval($_GET['max']); > if (!$max) $max = 255; > for($i=1;$i<=$max;$i++) > $a[]=str_repeat(chr($i),1024*1024); // 1 Mb > die("SUCCESS"); > } > > Там, как раз, учтен этот пресловутый мегабайт.
(Ответ для keleth на комментарий #13) > Я честно не совсем понял какой мегабайт был учтен Лимитом в цикле. Стандартный тест Битрикс доволен хостингом, если найдет 256 МБ ОЗУ. > Когда существующий массив достигает пределов выделенной под него памяти, > создается новый массив с бОльшим объемом зарезервированной под него памяти, > в новый массив копируется содержимого старого, добавляется новый элемент и > подменяется в переменной, по указателю или как там оно (здесь нам не важно), > вот пока весь процесс переноса данных не будет завершен - нельзя освободить > старые данные, отсюда и удвоение размера памяти в пиковых случаях. Выглядит занимательно, но так не должно быть. Таких экстремальных ситуаций в реальных скриптах полно. > Поэтому и говорю, что тест не совсем корректный. Чтобы долго не ходить по кругу (я не такой гуру в таких тонких вопросах), я обратился с вопросом в Битрикс (обращение 3501810). Посмотрим, что они скажут. Что касается самого тикета в Багзилле, то он появился не просто так. Я не припомню за 15 лет работы с Битрикс такой ситуации. Толи я был слеп все это время и детально не проверял это ограничение (я начинал с PHP 4), толи что-то изменилось повсеместно во всех сборках PHP. Я пока открыт для любого варианта.