...

PHP OPcache wyjaśnione dogłębnie: jak maksymalnie wykorzystać pamięć podręczną

PHP OPcache przyspiesza działanie moich skryptów, ponieważ PHP kompiluje kod bajtowy w pamięci, oszczędzając w ten sposób ponowne parsowanie. W tym przewodniku pokażę, jak używam OPcache. konfiguracja, monitoruję i precyzyjnie dostosowuję, aby Twoja aplikacja reagowała znacznie szybciej i spokojnie radziła sobie ze szczytami obciążenia.

Punkty centralne

  • Pamięć podręczna kodu bajtowego zmniejsza obciążenie procesora i operacje wejścia/wyjścia
  • Parametry Jak celowo wybierać memory_consumption i max_accelerated_files
  • Środowiska Ustawienia zróżnicowane: Dev, Staging, Produkcja
  • Monitoring Wykorzystaj dla współczynnika trafień, obłożenia, eksmisji
  • Wdrożenie i czyszczenie pamięci podręcznej

Tak działa OPcache: kod bajtowy zamiast ponownej kompilacji

Przy każdym zapytaniu PHP zazwyczaj odczytuje pliki, analizuje kod i tworzy kod bajtowy, który wykonuje silnik Zend. OPcache działa właśnie w tym miejscu i zapisuje ten kod bajtowy w pamięci współdzielonej, aby kolejne zapytania były uruchamiane bezpośrednio z pamięci. Dzięki temu zmniejsza się liczba cykli procesora i dostępów do plików, co zauważalnie skraca czas odpowiedzi. W typowych konfiguracjach osiągam dzięki temu wzrost wydajności od 30 do 70 procent, w zależności od bazy kodu i profilu ruchu. Decydujące znaczenie ma to, aby pamięć podręczna pozostała wystarczająco duża, a najważniejsze skrypty były trwale przechowywane w Pamięć pozostać.

Sprawdź i aktywuj OPcache w systemach Linux, Windows i na serwerach współdzielonych

Zawsze zaczynam od zajrzenia do phpinfo() i wyszukania „Zend”. OPcache“ oraz klucze, takie jak opcache.enable lub opcache.memory_consumption. W systemie Linux aktywuję moduł za pomocą pakietu php-opcache i pliku opcache.ini w katalogu conf.d. W systemie Windows wystarczy wpis zend_extension=opcache w pliku php.ini i ponowne uruchomienie serwera WWW. W przypadku hostingu współdzielonego często włączam OPcache za pomocą niestandardowego pliku php.ini lub menu klienta. W przypadku wąskich gardeł sprawdzam również Zwiększenie limitu pamięci PHP, aby OPcache i PHP-FPM miały wystarczającą ilość Zasoby odebrany.

Najważniejsze przełączniki wyjaśnione w zrozumiały sposób

Za pomocą opcache.enable aktywuję pamięć podręczną dla zapytań internetowych, natomiast opcache.enable_cli kontroluje wykorzystanie dla zadań CLI, co jest przydatne w przypadku kolejek zadań. Podstawą jest opcache.memory_consumption, które określa dostępną pamięć współdzieloną w megabajtach; zbyt mała wartość prowadzi do ewakuacji i ponownego Kompilacje. opcache.max_accelerated_files określa, ile plików może trafić do pamięci podręcznej; wartość ta powinna znacznie przewyższać liczbę plików w projekcie. Za pomocą opcache.validate_timestamps i opcache.revalidate_freq określam, jak rygorystycznie OPcache sprawdza zmiany w plikach, od bardzo dynamicznego (rozwój) do bardzo oszczędnego (produkcja z ręcznym opróżnianiem). Komentarze zabezpieczam za pomocą opcache.save_comments=1, ponieważ wiele narzędzi korzysta z DocBlocks są uzależnieni.

Porównanie wartości początkowych i profili

Aby zapewnić płynne rozpoczęcie pracy, stawiam na jasne profile rozwoju, stagingu i produkcji. Dzięki temu zyskuję z jednej strony szybkie cykle informacji zwrotnych podczas kodowania, a z drugiej strony niezawodną wydajność podczas pracy na żywo. Ważne jest, aby regularnie sprawdzać te wartości początkowe w odniesieniu do rzeczywistych wskaźników i je udoskonalać. W przypadku większych instalacji WordPress planuję dużą ilość pamięci i wpisów, ponieważ wtyczki i motywy zajmują dużo miejsca. Pliki . Poniższa tabela zawiera zestawienie sensownych wartości wyjściowych, które następnie dostosowuję na podstawie współczynnika trafień i ewakuacji.

Ustawienie Rozwój Staging/Test Produkcja
opcache.enable 1 1 1
opcache.enable_cli 0 0–1 1 (w przypadku zadań CLI)
opcache.memory_consumption 128–256 MB 256–512 MB 256–512+ MB
opcache.interned_strings_buffer 16–32 MB 32–64 MB 16–64 MB
opcache.max_accelerated_files 8 000–10 000 10 000–20 000 10 000–20 000+
opcache.validate_timestamps 1 1 0–1 (w zależności od wdrożenia)
opcache.revalidate_freq 0–2 s 60–300 s 300+ s lub 0 (z ręczną kontrolą)
opcache.save_comments 1 1 1
opcache.fast_shutdown 1 1 1

Ta macierz jest celowo pragmatyczna, ponieważ rzeczywiste projekty rozwijają się w bardzo różny sposób. Zaczynam od tych wartości, a następnie obserwuję współczynnik trafień, zajęty udział w pamięci współdzielonej i występowanie ewakuacji. W przypadku oznak obciążenia najpierw zwiększam opcache.memory_consumption w umiarkowanych krokach. Następnie dostosowuję opcache.max_accelerated_files, aż liczba plików będzie pasować. W ten sposób pozostaje Schowek skuteczne, a zapytania pozostają na stałym poziomie.

Ustawienia według środowiska: rozwój, staging, produkcja

W procesie rozwoju ważne jest szybkie reagowanie na zmiany w kodzie, dlatego ustawiam validate_timestamps=1 i revalidate_freq na bardzo niskie wartości lub nawet 0. Na etapie stagingu sprawdzam realistyczne obciążenie i ustawiam dużą pamięć, aby wyniki były zbliżone do późniejszej pracy na żywo. W środowisku produkcyjnym zwiększam częstotliwość sprawdzania lub całkowicie wyłączam znaczniki czasu, jeśli moje wdrożenie celowo opróżnia pamięć podręczną po ich sprawdzeniu. W przypadku pracowników opartych na CLI aktywuję enable_cli=1, aby powtarzające się zadania były również wykonywane przez Pamięć podręczna kodu bajtowego Korzystaj z tego. W ten sposób każde środowisko generuje dokładnie takie zachowanie, jakiego potrzebuję, bez niespodzianek związanych z czasem reakcji.

Zaawansowane ustawienia, które często mają znaczenie

Oprócz podstawowych parametrów dostępne są przełączniki, które pozwalają zwiększyć stabilność i bezpieczeństwo oraz zminimalizować skutki uboczne:

  • opcache.max_wasted_percentage: Określa, od jakiego stopnia fragmentacji OPcache uruchamia wewnętrzną przebudowę pamięci. W przypadku silnie zmiennych baz kodu nieznacznie zmniejszam tę wartość, aby mieć mniej „przeciętej“ pamięci.
  • opcache.force_restart_timeout: czas w sekundach, po upływie którego OPcache wymusza ponowne uruchomienie, jeśli konieczne jest ponowne uruchomienie, ale procesy są nadal aktywne. Zapobiega to bardzo długim stanom zawieszenia.
  • opcache.file_update_protection: okno ochronne w sekundach, w którym świeżo zmodyfikowane pliki nie są od razu buforowane. Pomaga to zapobiegać tworzeniu się niekompletnych plików podczas wdrażania lub na dyskach sieciowych.
  • opcache.restrict_api: Ogranicza, które skrypty mogą wywoływać opcache_reset() i funkcje statusowe. W środowisku produkcyjnym ustawiam to ściśle, aby dostęp miały tylko punkty końcowe administracji.
  • opcache.blacklist_filename: plik, w którym przechowuję wzorce wykluczone z pamięci podręcznej (np. wysoce dynamiczne generatory). Pozwala to zaoszczędzić miejsce dla bardziej krytycznych skryptów.
  • opcache.validate_permission i opcache.validate_root: aktywne, gdy w grę wchodzi wielu użytkowników/chrootów. W ten sposób PHP zapobiega nieuprawnionemu wykorzystaniu kodu z pamięci podręcznej z jednego kontekstu w innym.
  • opcache.use_cwd i opcache.revalidate_path: kontrola sposobu identyfikacji skryptów OPcache w przypadku włączenia ścieżek poprzez różne katalogi robocze/dowiązania symboliczne. W przypadku dowiązań symbolicznych typu release testuję te wartości w sposób ukierunkowany, aby uniknąć podwójnych pamięci podręcznych.
  • opcache.cache_id: Jeśli kilka wirtualnych hostów współdzieli ten sam SHM (rzadko), rozdzielam pamięci podręczne za pomocą unikalnego identyfikatora.
  • opcache.optimization_level: Zazwyczaj pozostawiam ustawienie domyślne. Tylko w skrajnych przypadkach podczas debugowania tymczasowo zmniejszam liczbę przejść optymalizacyjnych.

Preloading: utrzymywanie części kodu na stałe w pamięci

W PHP 7.4+ mogę za pomocą opcache.preload i opcache.preload_user ładować i łączyć centralne pliki frameworka lub projektu podczas uruchamiania serwera. Zaleta: klasy są dostępne bez autoload-hitów, a hot paths są dostępne od razu. Kilka praktycznych zasad:

  • Preloading jest szczególnie przydatny w przypadku dużych, stabilnych baz kodu (np. Symfony, własne biblioteki podstawowe). W przypadku WordPressa używam go z umiarem, ponieważ rdzeń/wtyczki są częściej aktualizowane.
  • Plik preload zawiera ukierunkowane wywołania opcache_compile_file() lub integruje autoloader, który definiuje klasy. z góry ładuje.
  • Każda zmiana kodu w plikach związanych z preload wymaga ponownego uruchomienia PHP-FPM, aby preload został ponownie zbudowany. Włączam to na stałe do wdrożeń.
  • Mierzę efekt osobno: nie każdy kod na tym korzysta; wstępne ładowanie zużywa dodatkowo pamięć współdzieloną.

JIT i OPcache: zalety, ograniczenia, wymagania dotyczące pamięci

Od wersji PHP 8 istnieje kompilator Just-In-Time (JIT), który jest sterowany przez OPcache (opcache.jit, opcache.jit_buffer_size). W przypadku typowych obciążeń sieciowych związanych z operacjami wejścia/wyjścia i bazami danych kompilator JIT często nie przynosi większych korzyści. Jednak w przypadku kodu obciążającego procesor (np. przetwarzanie obrazów/danych) może on być bardzo pomocny. Postępuję w następujący sposób:

  • Aktywuję JIT konserwatywnie i mierzę rzeczywiste wskaźniki użytkowników oraz profile procesora. Ślepa aktywacja zwiększa zapotrzebowanie na pamięć i może powodować sytuacje graniczne.
  • Rozmiar bufora JIT dostosowuję w zależności od obciążenia procesora. Zbyt małe bufory nie wnoszą żadnej wartości dodanej, a zbyt duże wypierają kod bajtowy.
  • Jeśli spada współczynnik trafień lub wykorzystanie SHM, przedkładam OPcache nad JIT. Pamięć podręczna bajtów jest ważniejszym czynnikiem dla większości stron internetowych.

Ścieżki plików, dowiązania symboliczne i bezpieczne strategie wdrażania

OPcache jest oparty na ścieżkach. Dlatego skupiam się na strategii wdrażania:

  • Atomic Releases poprzez symlink (np. /releases/123 -> /current): Czyste, ale należy zwrócić uwagę na opcache.use_cwd i zachowanie realpath. Unikam podwójnych pamięci podręcznych, ponieważ wszystkie procesy robocze widzą tę samą rzeczywistą ścieżkę.
  • W przypadku validate_timestamps=0 pamięć podręczna musi wszędzie opróżniane: po przełączeniu celowo flushuję OPcache na wszystkich hostach/podach i ponownie uruchamiam PHP-FPM w kontrolowany sposób.
  • realpath_cache_size i realpath_cache_ttl dostosowuję do OPcache, aby wyszukiwanie plików pozostało szybkie i stabilne.
  • Na dyskach sieciowych (NFS/SMB) zwiększam wartość file_update_protection i konfiguruję wdrożenia tak, aby pliki były zastępowane atomowo.

Aby zapewnić bardzo szybkie ponowne uruchomienie, często stosuję dwuetapową procedurę: najpierw rozgrzewka w tle, a następnie krótkie, skoordynowane ponowne załadowanie wszystkich modułów roboczych, aby pierwszy ruch na żywo trafił już na rozgrzaną pamięć podręczną.

Pamięć podręczna plików, rozgrzewanie i przygotowywanie

Oprócz pamięci współdzielonej OPcache może opcjonalnie zapisywać kod bajtowy na dysku (opcache.file_cache). Jest to pomocne w szczególnych sytuacjach:

  • W środowiskach kontenerowych można użyć pamięci podręcznej plików. pomiędzy Ponowne uruchomienia FPM Skrócenie czasu ponownej kompilacji, o ile pamięć masowa jest szybka.
  • Korzystam z opcache.file_cache ostrożnie: na wolnych lub rozproszonych systemach plików nie przynosi to większych korzyści, a zwiększa złożoność.
  • opcache.file_cache_only jest specjalnym przypadkiem dla środowisk bez SHM – nie jest stosowany w konfiguracjach wydajnościowych.

Do rozgrzewki tworzę sobie małe „podkłady“:

  • Skrypt CLI wywołuje opcache_compile_file() dla gorących plików, np. autoloader, centralne klasy frameworka, duże pomocniki.
  • Robot indeksujący odwiedza najważniejsze ścieżki (strona główna, logowanie, realizacja transakcji), aby kod bajtowy i dalsze pamięci podręczne były odpowiednio rozgrzane.
  • Planuję rozgrzewki tak, aby zakończyły się tuż przed zmianą wersji.

OPcache w stosie: PHP-FPM, pamięć podręczna obiektów i pamięć podręczna stron

OPcache wykazuje swoją siłę przede wszystkim w połączeniu z PHP-FPM, czystą konfiguracją procesów i dodatkowymi warstwami pamięci podręcznej. W przypadku WordPressa łączę go z pamięcią podręczną obiektów (np. Redis) i pamięcią podręczną stron, aby odciążyć bazę danych i renderowanie. W tym celu zwracam uwagę na Wydajność pojedynczego wątku, ponieważ zapytania PHP w dużym stopniu zależą od poszczególnych rdzeni procesora. Jeśli jednak pojawia się obciążenie, rozdzielam je między procesy PHP-FPM, nie wybierając zbyt małej pamięci współdzielonej OPcache. W ten sposób wykorzystuję Stos kompletnie, zamiast tylko przekręcać śrubę regulacyjną.

Częste błędy i szybkie kontrole

Zbyt mała pamięć podręczna powoduje wyrzucanie danych, co mogę sprawdzić w statusie OPcache lub phpinfo(). Jeśli tak się dzieje, stopniowo zwiększam opcache.memory_consumption i sprawdzam efekt poprzez współczynnik trafień. Jeśli pliki pozostają bez przyspieszenia, ustawiam opcache.max_accelerated_files na wartość wyższą niż rzeczywista ilość plików w projekcie. W przypadku problemów z wdrażaniem sprawdzam validate_timestamps: przy wartości 0 stary kod bajtowy pozostaje aktywny, dopóki nie wyczyszczę pamięci podręcznej. Narzędzia takie jak Doctrine wymagają DocBlocks, dlatego pozostawiam save_comments=1, aby Błąd poprzez brak adnotacji.

Monitorowanie i interpretacja OPcache

Mierzę współczynnik trafień i dążę do osiągnięcia wartości bliskich 100 procent, aby zapytania prawie zawsze były uruchamiane z pamięci podręcznej. Dodatkowo obserwuję wykorzystanie pamięci i liczbę ewakuacji, aby wcześnie wykrywać wąskie gardła. Za pomocą opcache_get_status() tworzę małe pulpity nawigacyjne lub zasilam istniejące rozwiązania monitorujące. Dzięki temu od razu widzę zmiany po wydaniu nowych wersji lub aktualizacji wtyczek. Dzięki tym wskaźnikom podejmuję świadome decyzje. Decyzje i dostosowuję tylko to, co jest naprawdę konieczne.

Konkretne wytyczne, które sprawdziły się w praktyce:

  • Wskaźnik trafień > 99 % przy normalnym i szczytowym obciążeniu; poniżej tej wartości sprawdzam dystrybucję plików i rozgrzewkę.
  • Wolna część SHM stała > 5–10 %; w przeciwnym razie skaluję pamięć.
  • Wykorzystanie pamięci w czasie: jednorazowe skoki po wdrożeniu są dopuszczalne; ciągłe wykorzystanie pamięci wskazuje na niedostateczną wielkość lub silną fragmentację.
  • Obserwuj marnowaną pamięć: jeśli osiągnie limit, planuję kontrolowane ponowne utworzenie OPcache (np. w oknach konserwacyjnych).

Przykład: konfiguracja WordPressa przy dużym natężeniu ruchu

W przypadku dużych witryn WordPress wybieram opcache.enable=1 i opcache.enable_cli=1, aby również CLI-Worker mógł z tego skorzystać. Pamięć współdzieloną ustawiam na 384 MB lub więcej, jeśli w grę wchodzi wiele wtyczek i bogaty w funkcje motyw. Zwiększam opcache.interned_strings_buffer do 64 MB, ponieważ wiele nazw klas i funkcji powtarza się we wszystkich żądaniach. W przypadku środowisk o ekstremalnej wydajności ustawiam validate_timestamps=0 i revalidate_freq=0, ale opróżniam pamięć podręczną bezpośrednio po każdym wydaniu. Ważne jest, aby wdrożenia były zaprojektowane w taki sposób, aby nie pozostawały stare kod bajtowy pozostaje w obiegu.

Praktyczny przepływ pracy w zakresie dostosowywania i wdrażania

Pracuję w stałych cyklach: mierzę, zmieniam, kontroluję. Najpierw zapisuję wartości statusu, takie jak współczynnik trafień, obłożenie i ewakuacje, a następnie dostosowuję parametr i ponownie dokonuję pomiaru. Przed wydaniem usuwam celowo OPcache przy wyłączonych znacznikach czasu, albo poprzez ponowne uruchomienie PHP-FPM, albo za pomocą małego skryptu. Następnie kontroluję szczyty obciążenia za pomocą rzeczywistego ruchu lub reprezentatywnych benchmarków. Jeśli pojawia się podejrzane zachowanie, sprawdzam również Fragmentacja pamięci, ponieważ wykorzystują Współdzielony Pamięć się pogarsza.

Kilka dodatkowych procedur, które sprawdziły się w zespołach:

  • Wersjonowanie zmian parametrów: opcache.ini w repozytorium, zmiany poprzez pull request i changelog.
  • Canary-Deploys: Najpierw część pracowników/podów ładuje nowe wersje i tworzy pamięć podręczną, a następnie następuje wdrożenie na wszystkich instancjach.
  • Przełącznik awaryjny: wewnętrzny punkt końcowy administratora z bezpiecznym dostępem, który umożliwia wywołania opcache_reset() i ukierunkowane wywołania opcache_invalidate() — w połączeniu z opcache.restrict_api.
  • Oszacowanie wielkości: jako przybliżoną zasadę ogólną przyjmuję początkowo 1–2 MB OPcache na 100–200 plików PHP, a następnie dostosowuję tę wartość na podstawie rzeczywistych danych. W przypadku WordPressa z wieloma wtyczkami dodaję bufor.

Krótkie podsumowanie

OPcache przyspiesza działanie aplikacji PHP poprzez kompilację kod bajtowy w pamięci RAM. Dzięki odpowiednim ustawieniom pamięci, liczby plików i strategii znaczników czasu można osiągnąć stałe krótkie czasy odpowiedzi. Należy zwrócić uwagę na koordynację z PHP-FPM i innymi warstwami pamięci podręcznej, aby cały stos działał sprawnie. Należy monitorować współczynnik trafień, zajętość i ewakuacje, aby móc dokonywać ukierunkowanych dostosowań. W ten sposób można zapewnić wydajną i niezawodną Platforma do dużych obciążeń i wzrostu.

Artykuły bieżące