C, PHP, VB, .NET

Дневникът на Филип Петров


* PHP Opcache конфигурация

Публикувано на 24 юли 2017 в раздел ОСУП.

PHP е скриптов език, от което следва, че при всяко зареждане трябва да се извърши процес на компилация. Това, както може да се досетите, губи известно време, което може да се натрупа сериозно при по-натоварени сайтове. Още по-лошото е, че води и до дискови операции – файлът със сорс кода трябва да се прочете от диска, за да бъде компилиран. Тук на помощ идват кеширащите модули – OpCache, APC или Xcache. Идеята при всички е, че се заделя рам памет, в която се пазят готови компилирани скриптове. По този начин, ако някой желае да отвори даден скрипт, който вече е бил отварян и е кеширан, значително ще се ускори времето за изпълнение, защото напълно ще съкрати принципно бавния (от компютърна гледна точка) процес на компилиране. Най-популярният кеширащ механизъм за PHP е Zend Opcache и затова тук ще се спрем именно на неговата конфигурация.

Преди да започна, нека кажа две основни важни неща:

  1. НЕ използвайте Opcache с версии на PHP по-стари от 5.6.30 или между 7.0.0 и 7.0.13 на споделен хостинг (!!!). Причината за това е сериозен пропуск в сигурността, за който ще напишем по-надолу (CVE-2015-8994). Ако използвате сървър за един единствен сайт, тогава не е проблем и с по-стари версии. Естествено никой не стартира нов проект със стари версии на PHP софтуера, но opcache може да се използва като възможност за забързване на вече съществуваща конфигурация, която поради остарял код на софтуера не може да се ъпгрейдне лесно;
  2. Opcache НЕ работи със SuPHP. Причината за това е, че при SuPHP PHP процесите се затварят веднага след изпълнението им. При PHP-FPM, което е най-често използвания в днешно време вариант, винаги има един master процес, който в частност се грижи за кеша. Отчитайки, че SuPHP не се поддържа от няколко години, това няма да се разглежда като проблем. Повече за различните PHP handlers прочетете тук.
  3. Opcache е сравнително прост кеширащ механизъм, който не използва брояч за попадения върху конкретни файлове, т.е. не се стреми да поддържа най-често използваните скриптове кеширани. Ако кешът се запълни се освобождава пространство за нови скриптове като отпадат най-старите (тези, които са били отваряни най-отдавна). Това само по себе си също е добра приоритизация, защото ако един скрипт се отваря изключително често (както например index.php файла във WordPress или други CMS системи), той винаги ще се „рестартира“ като най-скоро отварян, т.е. няма да изпада от кеша;
  4. Както може сами да се досетите, Opcache е всъщност хеш таблица – използва ключ име на файл (за конкретика прочетете по-надолу) и стойност компилиран скрипт + метаданни (кога е влязъл в кеша и др.).

Интсталирането на Opcache е много лесно – просто се добавя като модул в php.ini файла подобно на всички останали модули. От там насетне е важно да добавите правилни настройки. Има значителна разлика между това дали ще използвате opcache за един единствен потребител (един сайт), или ще го използвате за споделен хостинг между много потребители. Второто изисква повишено внимание от гледна точка на сигурността, затова тук ще поставим специален акцент.

opcache.enable=1

Със стойност 0 казваме, че кеша не се използва, а с 1 го включваме

opcache.enable_cli=1

Да се използва ли кеша при стартиране на скриптове през конзолата (1) или не (0).

opcache.memory_consumption=256

Колко рам памет да бъде отделена за кеша. В общи линии няма смисъл от прекалено голям кеш – независимо от натовареността на сървъра, обеми от порядъка 128 до 256 са нормални. По-голям кеш обикновено е безсмислен, защото само хабите пространство и време за търсене в кеша за файлове, които се използват много рядко.

opcache.interned_strings_buffer=8

Това е специално място в кеша, което се използва за immutable текстови низове (константни текстове). Възможно е един и същи текст да се среща в различни скриптове. Вместо да се пази на множество места, opcache го съхранява веднъж и използва препратки от различните скриптове в споделеното пространство. Подобна технология се използва от Java и други езици с виртуална машина (обикновено се наричат „String pools“). Това е допълнителна оптимизация, която обикновено си заслужава при споделените хостинги, където много често потребителите използват едни и същи CMS платформи – WordPress, Joomla, PHPBB…

opcache.max_accelerated_files=10099

Променливата дефинира максимален брой скриптове, които могат да се съхранят в кеша. Тук обикновено няма смисъл от огромни числа, защото тъй или иначе сме ограничени от memory_consumption променливата (даденото обикновено е предостатъчно за 256 MB).

opcache.validate_timestamps=1

Тази променлива е основната, която дефинира дали кеша ще се обновява при промяна на файл (променяте нещо в кода на скрипта) или не. Ако стойността е 1, при наличие на съвпадение в кеша, opcache ще направи (в зависимост от opcache.revalidate_freq – виж по-долу) лека, но все пак дискова операция, с която ще провери дали истинския файл е променен – ако не е, ще върне резултата от кеша, а ако е – ще изхвърли текущия скрипт от кеша и ще компилира файла наново. Тази променлива може да се държи със стойност 0 ако вие сами си управлявате сайтовете, които се хостват – просто трябва да помните, че при обновяване на сайт, трябва да изчиствате кеша. При споделен хостинг тази стойност се държи на 1, защото в противен случай потребителите ще са крайно объркани (сменят файл, а поради съвпадение в кеша, на сайта не се виждат никакви промени).

opcache.revalidate_freq=60

Тази променлива е тясно свързана с validate_timestamps. Ако validate_timestamps е 0, стойността на revalidate_freq няма значение – пропуска се. Ако validate_timestamps е 1, то revalidate_freq указва брой секунди (на престой на скрипта в кеша), в които няма да се прави проверка за обновяване на файла. Казано по друг начин, ако един потребител си обнови файл и тази променлива е със стойност 60, то в интервал от 0 до максимум 1 минута обновяването няма да се вижда на сайта му. Това разбира се може да се окаже объркващо за много потребители, затова често на споделените хостинги revalidate_freq се слага със стойност 0 въпреки, че реално носи голяма полза откъм производителност при натоварени сайтове. Не трябва да се пропуска и още едно важно нещо, което е свързано със сигурността – потенциално е възможно някой потребител да обнови два скрипта в своя хостинг, като един от тях е кеширан, а другия не е. При подобен сценарий може да се получи непредвидена ситуация – за кратък период от време неговият сайт ще е обновен само частично – нещо, което може да доведе включително до риск със сигурността.

opcache.validate_permission=1

В първите версии на opcache не са се правили никакви проверки на права за достъп. Тоест достатъчно е било един потребител да укаже, че иска да прочете даден файл и той да е наличен в кеша, и opcache ще му върне резултата от кеша независимо, че потребителя няма права за достъп до реално записания на диска файл (това е възможно, защото opcache се изпълнява в master процеса – било то apache при mod_php или основния процес при php-fpm, – а той е права на потребител root). Сами може да се досетите, че това е напълно неприемливо при споделен хостинг – един потребител ще може да напише скрипт, с който потенциално да прави include на ресурси от други потребители в системата, до които той не би трябвало да има достъп. Интересното е, че за този бъг се е знаело в период от две години, но е оправен чак за PHP 7.0.14 и по-нови версии, като тогава е добавена и за 5.6.30 и по-нови от 5.6.х клона. По-стари версии на PHP нямат това обновление, защото са извън срокове за поддръжка. Използвайте тази променлива със стойност 0, само и единствено ако работите с един единствен потребител (той тъй или иначе има пълен достъп до своите собствени файлове) – така ще се спести допълнителна проверка, с което би могло да се очаква някакво съвсем минимално забързване.

opcache.validate_root=1

Свързан с предишния бъг, това е много важна проверка за споделени хостинги, когато се използва chroot среда, т.е. това е php-fpm или mod_php+mod_ruid2. С тази опция се предотвратява хак, с който файлове с едно и също име се прехвърлят неправомерно от един потребител на друг.

opcache.use_cwd=1

Тази променлива указва да се използва абсолютния, а не релативен път до файла, когато се използва за ключ в хеш таблицата. Тази опция е задължителна ако имаме повече от един хостнат сайт – с нея се предотвратяват колизии на имена на файлове. Само и единствено при инсталация, която хоства един единствен сайт, можем да си позволим стойност 0 – това ще направи ключовете малко по-къси, с което може да се очаква някакво минимално подобрение в скоростта на търсене.

opcache.revalidate_path=1

Тази опция се използва тогава, когато се използват symlinks. В PHP много често в едни скриптове се прави include(…) или require(…) на други, като се посочва релативен път. Да, но при use_cwd=1 за ключ се пазят абсолютните пътища до файловете. Това обикновено не е проблем, освен ако А. в хостинга се използват symlinks и Б. symlink се промени, а файловете са кеширани. Променливата revalidate_path помага, но за съжаление не покрива всички възможни сценарии в такива ситуации. Поради тази причина трябва да сте доста внимателни ако използвате symlinks в комбинация с opcache. По-добре недейте или ако ги има, не местете symlinks без да сте спрели кеширането.

opcache.file_update_protection=2

Предотвратява кеширането на файлове, които са били съвсем наскоро обновени (в примера е от последните 2 секунди). Това се използва за защита от кеширане на частично обновени файлове.

opcache.max_wasted_percentage=5

Кешът може да се фрагментира с течение на времето. Това води до заета памет, която не може да се използва. В случая ако се засече, че тя е повече от 5%, opcache ще се саморестартира (с което реално ще извърши нещо като дефрагментация и ще освободи ненужно заетата памет).

opcache.fast_shutdown=1

Променливата се използва за ускоряване на рестартирането на сървъра – свързано е с почистването на паметта. Вместо да я нулира, opcache оставя тази задача на Zend Engine (който ще го прави тъй или иначе)

opcache.enable_file_override=1

Прави се проверка за наличие на файл в кеша при извикване на функциите file_exists(), is_file() и is_readable(), което води до подобрение. В документацията се указва, че тази опция трябва да е включена само при validate_timestamps=1!

opcache.error_log=

Ако няма стойност, ще се използва основния error log на PHP hanldler. В противен случай посочвате път до файл.

opcache.log_verbosity_level=1

Какво да се логва – критични проблеми (1, errors), критични проблеми и предупреждения (2, warnings), предишните две + информационни съобщения (3) или всичко, включително дебъг информация (4).

opcache.consistency_checks=0

Указва след колко опита да се прави проверка дали файла е валиден (чрез повторно компилиране и сравняване на checksum). При стойност 0 не се правят проверки. При число N>0 се прави проверка на всеки N заявки. Трябва да се има предвид, че това значително намалява производителността, затова обикновено не се ползва. Променливата е нещо като „да направим проверка за всеки случай“.

opcache.file_cache=/backuppartition/.opcache

Указва път до директория на твърдия диск, която да се използва за кеш ако споделената оперативна памет свърши. Познато е като „кеширане на второ ниво“. Помага при рестартиране на сървъра, когато кеша се губи и трябва да се регенерира наново – вместо да се започва от нулата, паметта се „затопля“ (warm-up) от файл на диска. Препоръчително е да се сложи не на основния дисков масив, който е натоварен, а на друг – например този за резервни копия.

opcache.file_cache_consistency_checks=1

Същото е като opcache.consistency_checks, но за кеш от второ ниво.

opcache.file_cache_only=0

Указва да се използва само и единствено кеширане на второ ниво – споделената оперативна памет не се ползва.

opcache.force_restart_timeout=180

Ако кешът не се използва (няма заявки) за определено време (в примера 180 секунди), то opcache предполага, че има евентуален проблем и се саморестартира.

opcache.save_comments=1

Да се кешират ли коментарите в кода или да се пропуснат за да се спести място? Препоръчително е да се кешират (1), защото някои frameworks ги използват.

opcache.huge_code_pages=1

Възможност за opcache да се възползва от hude code pages в linux kernel. По подразбиране е 0. Проверете дали операционната система го поддържа преди да го включвате.

opcache.inherited_hack=1

Поправя бъг във версии на PHP по-стари от 5.3. При по-новите тази опция се пропуска.

opcache.max_file_size=0

Да има ли ограничение за максимален размер на файла, над което той да не бъде кеширан (да не се хаби кеша за много големи файлове)? По подразбиране няма ограничение (0).

opcache.opt_debug_level=0

Ниво на debug – използва се само за разработчици. На реален сайт трябва да е винаги 0.

opcache.preferred_memory_model=

При празна стойност, opcache само ще подбере най-подходящия режим на работа с паметта спрямо системата, на която работи. Възможни други стойности са mmap, shm, posix и win32.

opcache.optimization_level=0xffffffff

Битова маска за вътрешно ползване – указва кои оптимизации са включени и кои не. Обикновено тази променлива не се променя ръчно, а се оставя на системата да подбере най-подходящата стойност.

opcache.protect_memory=0

Използва се само при debug.

opcache.restrict_api=

Позволява извикването на Opcache само за скриптове, чийто път започва с указания стринг. При празна стойност (по подразбиране) се работи с всички стриптове.

opcache.blacklist_filename=

Файл или файлове (поддържа маски), които са забранени за кеширане. Може например да се укаже директория – така всичко в нея и нейни поддиректории няма да се кешира. По подразбиране е празен низ, т.е. всичко се кешира.

opcache.dups_fix=0

Включва се само ако в логовете се появят грешки от типа „Cannot redeclare class“.

 



Добави коментар

Адресът на електронната поща няма да се публикува


*