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을 고려할 필요는 없습니다.
If don't like to use the the backslash, you can import the function like any other class from the root namespace:
<?php namespace App; use function strlen; strlen('ciao');
There are also a lot of internal automatisms of the PHP engine to generate an optimized opcode evaluating static expressions in advance. This was one of the most important reasons of the great performance improvement of PHP since the version 7.x
Being aware of these dynamics can really help you reduce resource consumption and cut costs. Once I made this research, I started using these tricks throughout the code.
Let me show you an example using PHP constants. Run this script into 3v4l:
<?php namespace App; if (PHP_OS === 'Linux') { echo "Linux"; }
Take a look at the first two lines of the PHP opcode:
line #* E I O op fetch ext return operands ------------------------------------------------------------------------------------- 5 0 E > FETCH_CONSTANT ~0 'App%5CPHP_OS' 1 IS_IDENTICAL ~0, 'Linux' 2 > JMPZ ~1, ->4 6 3 > ECHO 'Linux' 7 4 > > RETURN 1
FETCH_CONSTANT try to get the value of PHP_OS from the current namespace and it will look into the global namespace as it doesn’t exist here. Then the IS_IDENTICAL instruction executes the IF statement.
Now try adding the backslash to constant:
<?php namespace App; if (\PHP_OS === 'Linux') { echo "Linux"; }
As you can see in the opcode the engine doesn't need to try to fetch the constant because now it's clear where it is, and since it's a static value it already has it in memory.
Also the IF statement disappeared because the other side of the IS_IDENTITCAL statement is a static string ('Linux') so the IF can be marked as "true" without the overhead of interpreting it on every execution.
This is why you have a lot of power to influence the ultimate performance of your PHP code.
I hope it was an interesting topic, as I mentioned at the beginning of the article I'm getting a lot of benefits from using this tactic and in fact they are also used in our packages.
You can see here an example of how I used this tips in our PHP package to optimize its performance: https://github.com/inspector-apm/inspector-php/blob/master/src/Inspector.php#L302
For more technical articles you can follow me on Linkedin or X.
Inspector is a Code Execution Monitoring tool specifically designed for software developers. You don't need to install anything at the server level, just install the Laravel or Symfony package and you are ready to go.
If you are looking for HTTP monitoring, database query insights, and the ability to forward alerts and notifications into your preferred messaging environment, try Inspector for free. Register your account.
Or learn more on the website: https://inspector.dev
위 내용은 PHP opcode – 코드 변경 없이 애플리케이션 성능 향상의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!