mysql_pconnect()에 대한 고찰
php는 mysql_connect 함수를 사용하여 mysql(mariadb)과 연결하고 통신을 합니다.
매번 php가 요청을 처리할 때마다 커넥션을 맺고 끊고를 반복합니다.
여기서 php5는 mysql_pconnect라는 함수를 제공하여 지속연결을 제공해준다고 합니다.
(PHP 4, PHP 5)
mysql_pconnect — Open a persistent connection to a MySQL server
커넥션을 맺고 끊고를 반복하지 않고 한번 맺은 커넥션으로 여러번의 요청을 처리할 수 있다고 하고 있습니다.
그러나 php는 스크립트형 언어로써 요청이 들어올때마다 실행되므로 여러번의 요청은 완전히 독립적입니다.
서로 독립적인 요청들이 하나의 커넥션 리소스를 어떻게 공유하는 것일까요?
또한 mysql_pconnect에 대한 평판도 그렇게 좋지 않은 것 같습니다.
php.net의 mysql_pconnect함수 소개페이지에 들어가보면 사용을 추천하지 않는다는 건의가 많으며 심지어 php7에서는 삭제를 당합니다.
Warning
This extension was deprecated in PHP 5.5.0, and it was removed in PHP 7.0.0. Instead, the MySQLi or PDO_MySQL extension should be used. See also MySQL: choosing an API guide and related FAQ for more information. Alternatives to this function include:
- mysqli_connect() with p: host prefix
- PDO::__construct() with
PDO::ATTR_PERSISTENT
as a driver option
LAMP방식으로 돌아가는 php에게 지속연결은 얼마나 큰 이점을 가져다 주는걸까요? 또한 결점은 무엇일까요?
1. mysql_pconnect가 커넥션 리소스를 유지하는 방법
Note:
Note, that these kind of links only work if you are using a module version of PHP. See the Persistent Database Connections section for more information.
mysql_pconnect는 PHP가 Apache의 모듈방식으로 작동할때만 사용할 수 있다고 합니다. 왜일까요?
이것은 모듈방식으로 돌아갈때 php는 Apache의 프로세스 내부에서 돌아가기 때문입니다.
그리고 Apache프로세스는 요청을 한번만 처리하는게 아니고 여러번 처리하게 됩니다. 몇번 처리할지는 Apache설정의 MaxRequestPerChild값을 따라갑니다.
결국 php가 관리한다고 하기보다 Apache에서 커넥션 리소스를 관리하고 있다고 보면 됩니다.
Warning
Using persistent connections can require a bit of tuning of your Apache and MySQL configurations to ensure that you do not exceed the number of connections allowed by MySQL.
또한 지속연결으로 인해 mysql 커넥션 최대치 설정과 apache 프로세스 최대치 설정의 튜닝이 필요합니다.
왜냐하면 아파치 프로세스의 최대치는 100인데 mysql 커넥션의 최대치는 90이라면 91번째 요청부터는 two many connections 오류가 날 수 있기 때문입니다. mysql_pconnect는 php에서 수동으로 커넥션을 끊을 수 없으며 mysql에서 waittime_out을 통해 일정시간 활동이 없는 리소스를 자동으로 kill하는 방식으로만 끊을 수 있습니다.
2. php내부 mysql_pconnect의 구현상세
mysql_pconnect의 파라미터를 보면 다음과 같습니다.
mysql_pconnect ([ string
$server
= ini_get(“mysql.default_host”) [, string$username
= ini_get(“mysql.default_user”) [, string$password
= ini_get(“mysql.default_password”) [, int$client_flags
= 0 ]]]] ) : resource
순서대로 호스트, 사용자 아이디, 사용자 비밀번호, 설정 플래그 입니다.
이것만 가지고 어떻게 지속 연결 리소스를 공유할 수 있을까요?
Apache와 php의 연동 동작방식에 대한 이해가 먼저 필요합니다.
LAMP구조의 서버는 Centos, Apache, PHP, MariaDB을 이용하여 웹 서비스를 진행하고 있습니다.
먼저 Apache와 php가 어떻게 연동하여 동작하는지 간단하게 알아봅시다.
Apache는 prefork라는 모드로 돌아가고 있으며 Apache를 시작하면 설정파일에서 설정해놓은 숫자만큼의 프로세스를 미리 생성해놓습니다.
해당 프로세스들은 생성할때부터 php를 Load하며 MINIT단계의 초기화까지 진행하고 사용자의 요청이 올때까지 기다립니다.
(php는 MINIT, RINIT, RSHUTDOWN, MSHUTDOWN의 실행단계를 거칩니다.)
여기서 알아야 할 점은 모든 Apache 프로세스에서 돌아가는 PHP는 독립적이며 서로 어떠한 간섭도 없다는 것입니다.
httpd-mpm.conf 파일
StartServers 5 MinSpareServers 5 MaxSpareServers 10 MaxClients 150 MaxRequestsPerChild 10
HTTP 요청이 들어오고 특정 Apache프로세스가 요청을 처리하기 시작합니다. php는 모든 처리를 마친다음 결과를 리턴해주며 최종적으로 Apache가 결과를 요청자한테 돌려보냅니다. 여기서 주의해야 할점, Apache 프로세스는 처리를 끝마쳤지만 종료하지 않고 다음 요청을 기다립니다. 즉 하나의 Apache프로세스는 하나의 요청만 처리하는게 아니고 여러번의 프로세스를 처리합니다. 따라서 Apache내부의 PHP도 여러번의 요청을 처리하게 되죠. 몇번의 요청을 처리하는가에 대한 설정값은 MaxRequestsPerChild의 값을 따라갑니다. mysql_pconnect를 통해 생성된 db커넥션은 바로 해당 프로세스에서 상주하게 되는 것입니다. 프로세스가 MaxRequestsPerChild번 만큼의 요청을 처리하고 종료될까지는. mysql_pconnect함수는 매번 실행될 때 먼저 db커넥션이 이미 존재하는지 체크하며 존재하면 가져와서 쓰고 존재안하면 db커넥션을 생성하고 메모리에 상주시킵니다. mysql에서는 그러면 이러한 커넥션을 어떻게 처리할까요? 답은 wait_timeout입니다. mysql은 주동적으로 해당 커넥션을 끊지 않고 wait_timeout에 설정한 값에 따라 특정 커넥션이 지정된 시간동안 활동이 없으면 종료시킵니다. 만약 Apache의 프로세스가 MaxRequestsPerChild만큼의 요청을 처리하고 종료되더라도 커넥션은 wait_timeout이 되야 종료됩니다.
3. mysql_pconnect의 문제점
여기까지만 보았을때 큰 문제가 없어보이는게 사실입니다.
mysql_pconnect에 대해 사람들이 언급하고 있는 주의점에 대해 알아보면
- Apache의 child process의 합은 mysql server의 커넥션 허용갯수보다 많으면 안된다는 것입니다. too many connections오류를 방지하기 위해서입니다.
- 특정 Apache의 child process에서 mysql table에 lock을 걸고 커리를 수행하는 도중 예기치 못한 종료가 발생하면 pconnect때문에 커넥션을 유지하기 때문에 해당 테이블은 커넥션이 kill되기 전에는 lock상태를 유지하게 되며 서비스 장애로 이어지게 됩니다.
- 서비스의 방문자가 지속적으로 많지 않고 특정시간때에만 몰린다고 가정할때 Apache는 많은 child process를 생성하게 되고 커넥션을 많이 생성하게 되지만 방문자가 갑자기 사라질때 추가로 생성한 커넥션들은 kill당하기만 기다리는 리소스가 되어버리므로 위험부담이 있습니다.
4. 총결
그렇다면 mysql_pconnect을 사용하지 않는게 좋을가요?
해당 함수를 사용하는데 대해 php.net에는 이렇게 소개하는 코멘트가 있습니다.
This function is designed for environments which have a high overhead to connecting to the database.
high overhead, DB에 연결하기 위해 많은 리소스와 시간이 필요될 때 사용하라고 권장합니다.
운영중인 웹 서버와 php5는 DB에 연결을 시도할 때 얼마만큼의 소모가 발생할까요?
또한 pconnect의 사용여부에 따라 얼마만큼의 위험부담과 반응속도의 문제가 있을지?
mysql_connect와 mysql_pconnect중 어떤걸 사용할지에 대해서는 전반적인 성능측정과 튜닝이 필요하다고 생각됩니다.
- mysql_connect함수가 소모하는 CPUtime, TCP connection을 맺는데 사용하는 시간
- mysql_pconnect의 리스크 범위
- Apache설정과 mysql server의 설정값 튜닝