Apache / PHP 기반 웹 앱에서 명백한 메모리 누수의 원인을 어떻게 확인할 수 있습니까?


18

일주일에 한 번, 며칠 동안 정상적으로 실행 한 후 하루에 몇 번이라도 EC2 인스턴스가 응답하지 않게됩니다. Munin의 메모리 그래프는 매우 간단한 이야기를 보여줍니다. "앱"에 할당 된 메모리가 커지기 시작하고 스왑이 완전히 사용되고 인스턴스가 효과적으로 무릎을 꿇을 때까지 멈추지 않습니다. 또 다른 사용자 정의 그래프는 지속적으로 성장하는 프로세스가 아파치 2임을 보여줍니다.

mod_php와 몇 가지 PHP 스크립트를 사용하여 표준 prefork Apache 설정을 실행합니다. 아래 그래프에서 볼 수 있듯이 apache2 프로세스가 더 많은 메모리를 사용하기 시작하는 트리거가 발생합니다. 첫 번째 녹색 스파이크가 제 시간에 걸려 아파치가 시작되기 전에 Apache를 다시 시작했습니다. 두 번째 스파이크가 조금 더 멀어졌으며 인스턴스를 완전히 재부팅해야했습니다.

무닌 메모리 그래프

내가 궁금한 것은 이것을 가장 잘 디버깅하는 방법입니다. FastCGI로 PHP를 설정하고 자체 프로세스에서 실행하는 데 부족한 이유는 Apache인지 또는 PHP와 코드의 조합으로 과도한 메모리 사용을 유발하는지 확인하는 좋은 방법은 무엇입니까? 이 문제를 추적하기 위해 어떤 단계를 수행 하시겠습니까?


업데이트 : Matt이 제안한 것처럼 strace가 관련된 후 누출을 추적 할 수있었습니다.

점차적으로 메모리에서 지속적으로 증가하고있는 apache2 프로세스를 찾은 후 PHP 스크립트에 error_log () 호출을 몇 개 더 추가하여 실행시 다양한 지점에서 사용 된 RSS의 총량을 출력했습니다 (ps의 출력 사용). 그러나 그것은 오도 된 것으로 판명되었습니다. 내 스크립트가 실행 된 후에 만 ​​RSS가 뛰어 오르는 것처럼 보였지만 나중에 디버깅은 실제로 그렇지 않았습니다. 조심해!

다행히도 모든 error_log () 호출은 결국 유용한 것으로 판명되었습니다. strace ( strace -p <pid> -tt -o trace.log -s 256)를 시작했을 때 , 각 요청에 대해 프로세스가 약 400k의 메모리를 할당하는 것을 보았습니다 ( 'brk'시스템 호출을 찾아 마지막 호출의 첫 번째 호출 매개 변수를 빼십시오. 다른 후). 그런 다음 error_log () 메시지가 포함 된 가장 최근의 '쓰기'시스템 호출을 검색하여 메모리에서 메모리가 할당되는 시점을 알려줍니다. 보다 정확하게 위치를 정확하게 찾기 위해 error_log () 호출을 전략적으로 배치하면서 마침내 범인을 발견했습니다.

PHP 스크립트에서 curl_exec ()를 호출했을 때 메모리가 누출되었습니다. SSL 연결 처리와 관련된 일부 컬 코드가 잘못된 일을하고 있습니다 .HTTP로 전환하면 누수가 사라졌습니다. Curl의 changelog는 7.19.5 (우리는 7.18.2에 있음)에서 수정 된 몇 가지 SSL 메모리 누수를 참조하므로 다음에 시도하겠습니다.

그 동안 Apache를 합리적인 범위 내로 유지하는 MaxRequestsPerChild가 매우 낮습니다. 모두 감사합니다!


아파치 자식 프로세스의 수는 같은 기간 동안 어떻게 달라 집니까?
SimonJ

@SimonJ Simon, 좋은 질문입니다. 수는 거의 동일하게 유지되며 몇 가지 프로세스를 뺀 것입니다. 서버가 문제를 겪고 있거나 쉬고있을 때는 60여 대를 이동합니다. 그래도 Munin 그래프를 100 % 확실하게 설정하겠습니다.
ondrej

해결책은 아니지만 응용 프로그램 중 하나가 미친 것처럼 RAM을 먹는 것으로 알려진 경우 스왑을 해제하는 것이 좋습니다. 커널이 RAM 부족을 감지하면 가장 큰 메모리 호그 (apache)를 죽입니다. 스왑이 활성화되면 스왑이 RAM보다 훨씬 느리기 때문에 커널은 일부 프로세스를 훨씬 나중에 종료합니다. 스왑 없음-더 빠른 복구, 더 작은 중단 시간 (8GiB RAM이 장착 된 컴퓨터에서 YMMW와 비슷한 경우에만 스왑을 비활성화하려고 시도했습니다.)
chronos

답변:


5

무엇이 문제를 일으키는 지 추적하면 엉덩이가 아플 수 있습니다. 그런 문제가있는 경우 가장 먼저 할 일은 MaxRequestsPerChild엄청나게 낮은 숫자 (~ 100-200) 로 줄이고 차이가 있는지 확인하는 것입니다. 그렇다면 루프 어딘가에서 메모리가 누수되는 코드가 있고 코드 감사를 실행하고 싶을 것입니다.

살펴볼 또 다른 사항은 Apache의 전체 상태입니다. 메모리 누수의 원인이되는 특정 요청을 찾을 수 있는지 확인하십시오. 의심되는 프로세스에서 PID를 가져 와서 실행합니다.


고마워 매트. 'ps aux | grep apache2 '는 60여 개의 프로세스 중 활성화 된 프로세스 중 약 12 ​​개가 필요한 것보다 훨씬 더 많은 메모리를 사용하고 있음을 알려줍니다 (> 100MB 초과 RSS). / proc / <pid> / smaps의 출력을 살펴본 결과 각각 공간의 95 % 이상을 차지하는 정확히 하나의 익명 매핑이 있음을 발견했습니다. 나는 지금이 거대한 메모리 덩어리를 할당 할 때 무엇을 알아 내려고 노력하고 있습니다. 팁에 감사드립니다.
ondrej

2

금요일 @ 정확히 오후 11시? 백업 시간에 해당합니까? 시스템에 당시 프로세스 및 백업을 제공 할 수있는 I / O가 있습니까? 트렌드 소프트웨어는 # procs 또는 아파치 스코어 보드도 경향이 있습니까? 디스크 I / O는 어떻습니까?

가장 먼저 할 일은 각 proc가 얼마나 많은 mem을 계산하는지 계산 한 다음 $ procmem * $ procs가 사용 가능한 램을 초과 할 수 없도록 아파치에서 MaxRequests에 대한 합리적인 제한을 설정하는 것입니다. OOM이 (종종) 그다지 유익하지 않은 마녀 사냥을 시작하기 때문에 인스턴스를 재부팅해야한다고 생각합니다. 당신 당신의 상자가 그 범위 안에 머물면서 OOM이 아닌 스왑으로 가지 않음으로써 이러한 힘든 시간을 처리 할 수 ​​있도록해야합니다. cronjobs가 진행되는 경우 더 어렵고, cronjobs가 실행해도 안전한지 확인하지 않고 비 정기적으로 실행하는 경우에는 매우 어렵습니다 (예 : 5 분마다 스크립트가 마지막 5 분이 여전히 실행 중인지 확인하지 못함).

사물이 잘못되어도 상자를 다시 부팅 할 필요가없는 경우에도 상황이 훨씬 나아지기 시작합니다. 이 힘든 시간 동안 로그인하여 top, dstat, free -m, iostat 등을 사용하여 진행되는 작업에 대한 좋은 아이디어를 얻을 수 있습니다.

Matt의 방법은 시도해 볼 가치가 있지만 문제 해결을위한 도구로만 사용해야합니다. 다음 번에 찾을 때 전체적인 문제를 찾기가 훨씬 더 어려워 지므로 권장하지 않습니다. 즉, 아파치 / 모듈 관련 문제는 실제로 발생하지만 코드에는 아무런 문제가 없습니다. 나는 당신이 아파치 모듈에서 어떤 종류의 메모리 누출이 아니라고 생각할 가능성이 높다고 생각한다 (당신이 평판이 좋은 배포판을 사용한다고 가정).


0

첫 번째 질문은 Apache를 통해 실행되는 응용 프로그램은 무엇입니까?

당신이 쓴 것입니까, 아니면 타사 앱입니까?

다른 어떤 구성 요소 / 패키지를 참조합니까?

패키지를 최신 상태입니까?

httpd.conf성능과 관련 하여 파일에 특정한 것이 있습니까?


0

PHP 응용 프로그램으로 인해 문제가 발생하고 소프트웨어를 직접 작성한 경우 PHP Quick Profiler 와 같은 프로파일 러를 사용하는 것이 좋습니다 . 많은 데이터베이스 트랜잭션이 진행중인 경우 Kontrollbase 와 같은 소프트웨어 가 문제를 찾는 데 도움이 될 수 있습니다.


라파엘, 고마워 그렇습니다. PHP 앱은 내 것이기 때문에 SQL 데이터베이스에 영향을 미치지 않습니다. PHP Quick Profiler에 샷을 제공하고 다시보고하겠습니다.
ondrej
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.