PHP 엔진에서 생성된 PHP opcode는 코드 작성 방식에 큰 영향을 받습니다. 작업을 수행하기 위한 명령문의 수 측면에서만이 아닙니다. 분명히 그것은 매우 중요하며 여러분에게도 분명한 사실이라고 생각합니다.
덜 분명할 수 있는 점은 코드 구문조차도 생성된 opcode를 완전히 변경하여 시스템의 CPU가 정확히 동일한 코드를 실행하는 데 많은 오버헤드를 발생시킬 수 있다는 것입니다.
지난 몇 년 동안 내 SaaS 제품이 많이 성장했으며 이를 통해 워크로드를 최대한 효율적으로 실행하기 위한 최적화 기술을 점점 더 깊이 이해할 수 있는 기회를 얻었습니다.
제가 본 결과는 인상적이었으며 SaaS 여정을 계속 발전시키기 위해 무료 현금 흐름을 확보하는 데 많은 도움이 되었습니다.
이 시점에서 내 SaaS 제품 내부의 PHP 프로세스는 2vCPU 및 8GB 메모리를 갖춘 시스템에서 매일 12억 개 이상의 데이터 패킷(B 포함)을 처리하고 있습니다. 예측할 수 없는 급증 시 유연성을 높이기 위해 AWS AutoScaling 그룹을 사용하지만 두 번째 머신을 추가하는 경우는 거의 없습니다(일주일에 1~2회).
더 많은 기술 관련 기사를 보려면 Linkedin이나 X에서 저를 팔로우하세요.
최근에는 Inspector 서버를 ARM 인스턴스로 마이그레이션하는 방법에 대해서도 썼습니다: https://inspector.dev/inspector-adoption-of-graviton-arm-instances-and-what-results-weve-seen/
기사 주제로 들어가 보겠습니다. 매우 흥미로울 것 같습니다.
PHP opcode는 연산 코드(Operation Code)를 의미하며, 작성한 PHP 소스 코드가 컴파일된 후 PHP 엔진에서 실행되는 하위 수준 명령을 나타냅니다.
PHP에서 코드 컴파일은 런타임에 발생합니다. 기본적으로 PHP 엔진이 처음으로 코드를 가져오면 기계 친화적인 코드로 컴파일되고 캐시되므로 엔진이 동일한 코드를 다시 컴파일하지 않습니다. 그런 다음 실행됩니다.
이는 프로세스를 간단하게 표현한 것입니다.
PHP opcode를 캐싱하면 코드 실행 과정에서 원시 PHP 코드 구문 분석, 토큰화, 컴파일의 세 단계를 줄일 수 있습니다.
opcode가 처음 생성되면 이후 요청에서 재사용할 수 있도록 메모리에 저장됩니다. 이렇게 하면 PHP 엔진이 실행될 때마다 동일한 PHP 코드를 다시 컴파일할 필요성이 줄어들어 CPU 및 메모리 소비가 많이 절약됩니다.
PHP에서 가장 일반적으로 사용되는 opcode 캐시는 OPCache이며, PHP 5.5부터 최신 버전까지 기본적으로 포함되어 있습니다. 매우 효율적이며 광범위하게 지원됩니다.
미리 컴파일된 스크립트 바이트코드를 캐싱하려면 배포할 때마다 캐시를 무효화해야 합니다. 변경된 파일의 캐시에 바이트코드 버전이 있으면 PHP는 이전 버전의 코드를 계속 실행합니다. Opcode 캐시를 제거하여 새 코드가 다시 컴파일되어 새 캐시 항목을 생성할 때까지.
다른 구문이 스크립트의 opcode에 어떤 영향을 미칠 수 있는지 이해하려면 PHP 엔진에서 생성된 컴파일된 코드를 가져오는 방법이 필요합니다.
opcode를 얻는 방법에는 두 가지가 있습니다.
컴퓨터에 OPCache 확장 기능이 활성화되어 있으면 기본 기능을 사용하여 특정 PHP 파일의 opcode를 가져올 수 있습니다.
// Force compilation of a script opcache_compile_file(__DIR__.'/yourscript.php'); // Get OPcache status $status = opcache_get_status(); // Inspect the script's entry in the cache print_r($status['scripts'][__DIR__.'/yourscript.php']);
VLD는 컴파일된 PHP 코드를 분해하고 opcode를 출력하는 널리 사용되는 PHP 확장입니다. 이는 PHP가 코드를 해석하고 실행하는 방법을 이해하기 위한 강력한 도구입니다. 일단 설치되면 -d 옵션과 함께 php 명령을 사용하여 VLD가 활성화된 PHP 스크립트를 실행할 수 있습니다.
php -d vld.active=1 -d vld.execute=0 yourscript.php
출력에는 각 작업, 관련 코드 줄 등을 포함하여 컴파일된 opcode에 대한 자세한 정보가 포함됩니다.
3v4l은 편집기에 입력한 PHP 코드에 의해 생성된 opcode를 볼 수 있는 매우 유용한 온라인 도구입니다. 기본적으로 VLD가 설치된 PHP 서버이므로 VLD 출력을 가져와 브라우저에 opcode를 표시할 수 있습니다.
무료로 배포되므로 다음 분석에 이 온라인 도구를 사용하겠습니다.
3v4l은 우리가 사용하는 코드 구문이 결과 PHP opcode에 좋은 방식으로 또는 나쁜 방식으로 어떻게 영향을 미칠 수 있는지 이해하는 데 적합합니다. 아래 코드를 3v4l에 붙여넣어 보겠습니다. "지원되는 모든 버전" 구성을 유지하고 "평가"를 클릭하세요.
<?php namespace App; strlen('ciao');
코드를 실행하면 하단에 탭 메뉴가 나타납니다. 해당 OP코드를 시각화하려면 VLD 탭으로 이동하세요.
line #* E I O op fetch ext return operands ------------------------------------------------------------------------------------- 5 0 E > INIT_NS_FCALL_BY_NAME 'App%5CSpace%5Cstrlen' 1 SEND_VAL_EX 'ciao' 2 DO_FCALL 0 3 > RETURN 1
첫 번째 작업은 INIT_NS_FCALL_BY_NAME입니다. 인터프리터는 현재 파일의 네임스페이스를 사용하여 함수 이름을 구성합니다. 그런데 AppExample 네임스페이스에는 존재하지 않는데 어떻게 작동하나요?
통역사는 함수가 현재 네임스페이스에 존재하는지 확인합니다. 그렇지 않은 경우 해당 핵심 기능을 호출하려고 시도합니다.
여기서 통역사에게 이러한 이중 확인을 피하고 핵심 기능을 직접 실행하라고 지시할 수 있는 기회가 있습니다.
strlen 앞에 백슬래시()를 추가하고 "eval"을 클릭해 보세요.
<?php namespace App; \strlen('ciao');
이제 VLD 탭에서 단 하나의 명령문으로 opcode를 볼 수 있습니다.
line #* E I O op fetch ext return operands ------------------------------------------------------------------------------------- 5 0 E > > RETURN 1
기능의 정확한 위치를 전달했기 때문에 fallback을 고려할 필요는 없습니다.
백슬래시를 사용하고 싶지 않다면 루트 네임스페이스에서 다른 클래스처럼 함수를 가져올 수 있습니다.
// Force compilation of a script opcache_compile_file(__DIR__.'/yourscript.php'); // Get OPcache status $status = opcache_get_status(); // Inspect the script's entry in the cache print_r($status['scripts'][__DIR__.'/yourscript.php']);
정적 표현식을 미리 평가하는 최적화된 opcode를 생성하기 위한 PHP 엔진의 내부 자동화 기능도 많이 있습니다. 이것이 7.x 버전 이후 PHP의 성능이 크게 향상되는 가장 중요한 이유 중 하나였습니다
이러한 역학 관계를 인식하면 리소스 소비를 줄이고 비용을 절감하는 데 큰 도움이 될 수 있습니다. 이 조사를 마친 후 코드 전반에 걸쳐 이러한 트릭을 사용하기 시작했습니다.
PHP 상수를 사용한 예를 보여드리겠습니다. 이 스크립트를 3v4l로 실행하세요:
php -d vld.active=1 -d vld.execute=0 yourscript.php
PHP opcode의 처음 두 줄을 살펴보세요.
<?php namespace App; strlen('ciao');
FETCH_CONSTANT는 현재 네임스페이스에서 PHP_OS 값을 가져오려고 시도하며 여기에 존재하지 않는 전역 네임스페이스를 조사합니다. 그런 다음 IS_IDENTICAL 명령이 IF 문을 실행합니다.
이제 상수에 백슬래시를 추가해 보세요.
line #* E I O op fetch ext return operands ------------------------------------------------------------------------------------- 5 0 E > INIT_NS_FCALL_BY_NAME 'App%5CSpace%5Cstrlen' 1 SEND_VAL_EX 'ciao' 2 DO_FCALL 0 3 > RETURN 1
opcode에서 볼 수 있듯이 이제 상수의 위치가 명확하고 정적 값이므로 이미 메모리에 있으므로 엔진이 상수를 가져오려고 시도할 필요가 없습니다.
또한 IS_IDENTITCAL 문의 다른 쪽이 정적 문자열('Linux')이므로 IF 문이 사라졌습니다. 따라서 실행할 때마다 이를 해석하는 오버헤드 없이 IF를 "true"로 표시할 수 있습니다.
이것이 PHP 코드의 궁극적인 성능에 영향을 미칠 수 있는 많은 힘을 갖는 이유입니다.
글 시작 부분에서 언급한 것처럼 흥미로운 주제였기를 바랍니다. 이 전술을 사용하면 많은 이점을 얻을 수 있고 실제로 우리 패키지에도 사용됩니다.
성능을 최적화하기 위해 PHP 패키지에서 이 팁을 어떻게 사용했는지에 대한 예를 여기에서 볼 수 있습니다: https://github.com/inspector-apm/inspector-php/blob/master/src/Inspector.php# L302
더 많은 기술 관련 기사를 보려면 Linkedin이나 X에서 저를 팔로우하세요.
Inspector는 소프트웨어 개발자를 위해 특별히 설계된 코드 실행 모니터링 도구입니다. 서버 수준에서 아무것도 설치할 필요가 없습니다. Laravel 또는 Symfony 패키지만 설치하면 바로 사용할 수 있습니다.
HTTP 모니터링, 데이터베이스 쿼리 통찰력, 경고 및 알림을 선호하는 메시징 환경으로 전달하는 기능을 찾고 있다면 Inspector를 무료로 사용해 보세요. 계정을 등록하세요.
또는 웹사이트에서 자세한 내용을 알아보세요: https://inspector.dev
위 내용은 PHP opcode – 코드 변경 없이 애플리케이션 성능 향상의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!