profile

이 세상에 하나는 남기고 가자

세상에 필요한 소스코드 한줄 남기고 가자

PHP Composer Autoloader 최적화

유영재

Composer Autoloader 최적화

Composer Autoloader는 상대적으로 빠르게 실행되나 PSR-4 및 PSR-0 autoload 규칙이 설정되는 방식으로 인해 클래스 이름을 확인하기 전에 파일 시스템을 검사해야 한다. 이 경우 성능이 떨어지지만 개발 환경에서는 새로운 Class를 추가할 때 autoload 구성을 다시 작성하지 않고도 즉시 사용할 수 있으므로 편리하다. 그러나 production 환경에서는 클래스의 추가가 발생하지 않기 때문에 성능을 위해서 파일 시스템을 검사하지 않고 클래스를 로드하는 것이 좋다.

Composer는 이러한 문제를 개선하기 위해 autoload 최적화 옵션을 제공한다.

최적화 레벨 1 : 클래스 맵 생성

autoload 최적화를 위한 클래스 맵을 생성하는 방법은 다음과 같은 몇가지가 존재한다.

  • composer.jsonoptimize-autoloader을 추가

install 또는 update 시 별도의 옵션을 주지 않아도 자동적으로 최적화를 수행하므로 편리하다.

{
  "name": "project",
  ...
  "config": {
    "optimize-autoloader": true
  }
}
  • composer install / update-o 또는 --optimize-autoloader 옵션을 추가

install 또는 update 시 별도의 옵션을 주어야 하지만 필요시에만 최적화를 하려는 경우 유용하다.

$ composer install -o
$ composer update --optimize-autoloader
  • composer dump-autoload-o 또는 --optimize 옵션과 함께 실행

패키지들이 이미 설치된 이후에 최적화면 수행하고자 할 경우 사용 가능하다.

$ composer dump-autoload --optimize

클래스 맵 생성은 기본적으로 PSR-4 / PSR-0 규칙을 클래스 맵 규칙으로 변환한다. 클래스 맵이 클래스의 존재와 위치를 보장하므로 Composer는 파일 시스템을 검사하지 않고 빠르게 클래스를 로드할 수 있다.

특히 PHP 5.6 이상에서는 opcache가 활성화되어 있는 경우 클래스 맵이 opcache에도 캐시될 수 있으므로 초기화 시간을 크게 향상된다.

Trade-offs

최적화 레벨 1의 경우 특별한 Trade-offs가 없으므로 production 환경에서는 항상 활성화하는 것이 좋다.

단, 클래스 맵에 누락된 클래스를 호출하는 경우 PSR-4 규칙이 대체되어 파일 시스템 검사가 발생할 수 있다. 하지만 모든 클래스를 검사하는 것보다는 당연히 성능이 뛰어나므로 사용하지 않을 이유가 없다.

누락된 클래스에 의한 성능 저하를 해결하기 위해서 두가지의 레벨 2 최적화 옵션이 존재한다. 이 옵션들은 프로젝트에 존재하지 않는 클래스에 대한 class_exists 검사가 많은 경우 사용할 수 있다.

최적화 레벨 2/A : 신뢰할 수 있는 클래스 맵

autoload 최적화를 위한 신뢰할 수 있는 클래스 맵을 생성하는 방법은 다음과 같은 몇가지가 존재한다.

  • composer.jsonclassmap-authoritative을 추가

install 또는 update 시 별도의 옵션을 주지 않아도 자동적으로 최적화를 수행하므로 편리하다.

{
  "name": "project",
  ...
  "config": {
    "classmap-authoritative": true
  }
}
  • composer install / update-a 또는 --classmap-authoritative 옵션을 추가

install 또는 update 시 별도의 옵션을 주어야 하지만 필요시에만 최적화를 하려는 경우 유용하다.

$ composer install -a
$ composer update --classmap-authoritative
  • composer dump-autoload-a 또는 --classmap-authoritative 옵션과 함께 실행

패키지들이 이미 설치된 이후에 최적화면 수행하고자 할 경우 사용 가능하다.

$ composer dump-autoload --classmap-authoritative

이 옵션이 활성화될 경우 클래스맵에 찾는 클래스가 없더라도 PSR-4 규칙에 따른 파일 시스템 조사를 하지 않도록 하는 것이다. 또한 이 옵션을 사용하면 레벨 1 최적화는 자동적으로 활성화 된다.

이 옵션의 추가 전후의 autoload_real.php 파일 변화를 보면 차이가 명확히 보인다.

public static function getLoader()
{
    ...
    } else {
        $map = require __DIR__ . '/autoload_namespaces.php';
        foreach ($map as $namespace => $path) {
            $loader->set($namespace, $path);
        }

        $map = require __DIR__ . '/autoload_psr4.php';
        foreach ($map as $namespace => $path) {
            $loader->setPsr4($namespace, $path);
        }

        $classMap = require __DIR__ . '/autoload_classmap.php';
        if ($classMap) {
            $loader->addClassMap($classMap);
        }
    }
    ...
}
public static function getLoader()
{
    ...
    } else {
        $classMap = require __DIR__ . '/autoload_classmap.php';
        if ($classMap) {
            $loader->addClassMap($classMap);
        }
    }
    ...
}

Trade-offs

이 욥션을 사용하면 PSR-4 규칙을 통한 파일 시스템 검사를하지 않으므로 autoloader가 항상 빠르게 동작한다. 하지만 이로 인해 런타임 상에서 클래스가 생성되는 경우 클래스를 찾을 수 없으므로 "class not found" 오류가 날 수 있으므로 주의해서 사용해야 한다. 특히 개발 환경에서는 클래스의 추가가 자주 일어날 수 있으므로 불편하다(클래스 추가시마다 클래스 맵을 재생성 해야 함).

또한 이 최적화 옵션은 최적화 레벨 2/B와 동시에 사용할 수 없다.

최적화 수준 2 / B : APCu 캐시

autoload 최적화를 위한 APCu 캐시를 사용하는 방법은 다음과 같은 몇가지가 존재한다.

  • composer.jsonapcu-autoloader을 추가

install 또는 update 시 별도의 옵션을 주지 않아도 자동적으로 최적화를 수행하므로 편리하다.

{
  "name": "project",
  ...
  "config": {
    "apcu-autoloader": true
  }
}
  • composer install / update--apcu-autoloader 옵션을 추가

install 또는 update 시 별도의 옵션을 주어야 하지만 필요시에만 최적화를 하려는 경우 유용하다.

$ composer install --apcu-autoloader
$ composer update --apcu-autoloader
  • composer dump-autoload--apcu 옵션과 함께 실행

패키지들이 이미 설치된 이후에 최적화면 수행하고자 할 경우 사용 가능하다.

$ composer dump-autoload --apcu

이 옵션은 APCu 캐시를 클래스 맵의 fallback으로 추가한다. 발견된 class는 APCu에 캐시되므로 다음 요청시에는 빠르게 반환한다. 최적화 레벨 2/A와 달리 레벨 1 최적화를 자동적으로 활성화하지 않으므로 필요시 수동으로 활성화 해야 한다.

Trade-offs

APCu가 사용 가능해야 하는 제약이 있으며 APCu 메모리를 사용해 autoload를 수행하지만 신뢰할 수 있는 클래스 맵에서와 같이 클래스를 찾지 못하는 오류가 발생할 수 있다.

또한 이 최적화 옵션은 최적화 레벨 2/A와 동시에 사용할 수 없다.

결론

위에서 소개한 바와 같이 클래스 맵을 생성하는 최적화 레벨 1은 기본적으로 항상하는 것이 좋다. 최적화 레벨 2의 경우는 성능 상의 이점이 있으나 프로그램의 상황에 따라 오류 발생 가능성이 있으니 production 환경에서 상황에 맞게 선택적으로 사용하는 것이 좋다.


참고 : PHP Composer Autoloader Optimization

comments powered by Disqus