PHP에서 세션(session)에 대한 주의할 점과 성능 개선 방법

최근에 잘 모르고 있었던 레거시 코드 부분에서 심각한 성능 저하가 있는 것을 발견했다.
Request 마다 사용자 인증을 확인하는 함수가 호출 되는데 20 라인도 안되는 그 함수에서 전체 비중에 50% 이상이 오버헤드가 발생하고 있었다. 라인수가 짧다고 심플하고 가볍다고는 볼 수 없지만, 사용한 변수나 호출하는 자식 함수명만 봤을때는 전혀 예상하지 못했던 부분이였다. 하지만 이름에서 풍기는 가벼움과 다르게 자식 함수들은 생각보다 무거운 작업을 하고 있었다.

  1. $_SESSION 에 접속한 사용자 정보가 있는지 확인
  2. (1)에서 확인한 사용자 ID로 추가 정보를 DB 에서 조회 후 전역변수에 저장
  3. (2) 와 비슷하게 기타 설정값을 DB 에서 조회 후 같은 전역변수에 저장

일단 (2), (3) 을 제거하고 싶은 마음에 관련된 의존성 코드를 찾기 시작했다.
그리고 포기했다. 저 전역변수는 너무나 많은 곳에서 사용되고 있었다. (이래서 전역변수를 사용하지 말라는 것이다!)
결국 나름 꼼수로 생각한 대안은 같은 사용자가 최초 수행한 (2), (3) 작업을 $_SESSION 에 캐시 하도록 했다.
하지만 이 또한 그렇게 나이스한 해결책은 아니였다는 것을 깨닫게 되는데는 오랜 시간이 걸리지 않았다.

위와 같이 처리해도 큰 성능 개선은 없었다. 왜일까?
xhprof 로 프로파일링한 결과를 통해서 본 결과는 더욱 충격적이였는데 그 이유는 아직도 저 함수가 계속 느린 것이다.
그렇게 아직도 느렸던 녀석은 바로 session_start(); 였다.
처음에는 xhprof 를 의심했다. 아니 그래도 페이스북에서 만들었다던 xphrof 가 나에게 거짓 정보를 줬을리가 없다는 생각이 다시 들었다!
그래서 나는 PHP 의 session 이 어떻게 동작하는지 찾아보게 되었고, 뜻밖에 결과에 또 놀라게 되었다.

PHP는 기본적으로 세션을 파일로 다룬다. 그리고 session_start() 가 호출되면, 해당 파일에 동시 쓰기를 막기위해 LOCK을 잡게 된다.
따라서 Request 마다 사용자 정보를 가져오기만 위해 호출된 session_start() 가 성능 저하에 큰 부분을 차지했던 것이다. (만약 php.ini 설정에 session.auto_start 까지 1 로 되어 있었다면 Request 마다 자동으로 session_start()를 하는 꼴이 된다.)

이 부분에 대한 해결책으로는 session_start() 이후에 session_write_close() 를 호출해서 세션에 쓰기 LOCK을 해제하는 것이다.
이렇게 한 이후에도 $_SESSION 전역변수에는 접근이 가능하기 때문에 세션에 저장된 값을 가져오는데 시간을 절약할 수 있게 된다.
추가로 더 좋은 성능을 내기 위해 세션이 저장되는 스토리지를 파일이 아닌 Sqlite 나 Memcached, Redis 를 사용하는 것도 좋다고 한다.

PHP 처음 배울때 누구나 세션에 대해서 배우지만 이런 내용은 어디서도 알려주는 곳이 없던것 같다. 휴..


comments powered by Disqus
TAGS
On this page