웹서버 메모리 문제

내가 웹서버 설정을 똑바로 해낼 리 없기 때문에 bitnami LAMP Stack을 사용했는데 사양이 낮은 인스턴스에서는 그들의 설정이 기대한 대로 동작하지 않을 수 있고 결국 조금씩 배워가며 설정을 해내는 수밖에 없다는 사실을 깨달았습니다.

검색해보면 초보자들에게 AWS 사용을 권하지 않는 이유는 bitnami가 주요 OS와 설정을 만듦으로 문제가 있을 때 해결방법을 검색한 다음 시도해도 설정이 달라 사용할 수 없을 가능성이 높기 때문이라고 합니다. 저는 오히려 반대로 생각했는데 초보자들이 OS만 덜렁 있는 이미지로 인스턴스를 만든 다음 필요한 소프트웨어를 하나씩 설치하며 제대로 설정을 해낼 수 있을 거라고 생각하지 않았습니다. 멍청한 초기설정 그대로 서비스를 돌려놓고 온갖 문제에 빠지게 될 거라고 생각했어요. 그래서 오히려 bitnami에서 만들어둔 LAMP 스택이 더 안전할 거라고 생각해 사용하기 시작했습니다. 또 그것만으로는 제가 온갖 보안설정을 똑바로 해낼 가능성이 없으므로 클라우드플레어를 앞에 붙인 다음 최소한의 보안장치를 설정했고요.

문제

하지만 작년 11월에 라이트세일로 이사하고 나서 남들이 해준 설정과 남들이 만들어놓은 보안 서비스 위에서 어떻게든 서비스를 돌릴 수 있을 거라고 생각한 것이 꽤 순진한 생각이었다는 사실이 금새 드러났습니다. 이때까지는 모니터링에 클라우드워치를 사용하고 있었는데 이따금씩 높은 메모리 사용량 경고가 발송됐기 때문입니다. 어떻게 해야 하는지 몰랐습니다. 처음엔 그대로 뒀는데 잠시 후에는 CPU 사용량이 높다고 메일이 왔고 또 그대로 두면 서버가 응답이 없어졌습니다. 그럼 라이트세일 웹사이트에서 서버를 재시작해야 했습니다. 그러다가 높은 메모리 사용량은 아파치 웹서버 때문이라는 것을 알게 된 상태까지 갔습니다. 그러는 사이에 tophtop 같은 프로그램들을 알게됐고요. 그 다음 번에 메모리 사용량 경고 메일이 오자 터미널에서 아파치만 재시작했고 일시적으로 상황을 모면할 수 있었습니다. 잠깐 동안은 이를 반복했습니다. 아이폰에서 Blink앱과 mosh 조합으로 아파치를 순식간에 재시작할 수 있었습니다. 하지만 이건 제가 기대한 상황은 아니었습니다.

그러는 사이에 지옥의 cacti를 거쳐 zabbix로 모니터링환경을 변경했고 이제 돈 걱정 안 하고 여러 메트릭을 지속적으로 관찰할 수 있도록 환경을 바꿨습니다. 이럴 즈음에도 여전히 위에 이야기한 웹서버의 메모리 경고가 계속해서 일어났고 이제 문제를 해결할 방법을 찾기 시작했습니다.

흔한 원인

여러 가지로 검색해본 결과 가능성이 높은 원인은 MaxRequestsPerChild라는 값의 설정이었습니다. 아마도 웹서버는 사용자로부터 요청을 처리하는 서비스 - 윈도우에선 비슷한 걸 서비스라고 불렀으니 일단 그렇게 설명하겠습니다. - 를 몇 개 만들어놓고 각각이 요청을 몇 개 처리했는지 세고 있다가 지정된 수량을 처리하고 나면 그 서비스만 재시작하도록 되어 있는 모양이었습니다. 일부 서비스를 재시작하는 이유는 위에서 제가 겪고 있는 상황과 비슷한 메모리 누수 문제를 완화하기 위함이라는 문장을 읽다가 얼굴을 찌뿌렸습니다. 이해할 수가 없었습니다. 이건 근본적은 소프트웨어 디자인의 문제를 튜닝 가능한 설정으로 위장한 것이 아닐까 싶었습니다. 어쨌든 지금 제가 겪고 있는 문제를 해결하기 위해 인터넷의 수많은 사람들이 위에 이야기한 값을 올렸다 내렸다 하며 적당한 값을 찾는 모양이었고 저도 해보기로 했습니다.

가정은 이렇습니다. 저 값을 올리면 한 서비스가 더 많은 요청을 처리합니다. 더 오래살아있고 그만큼 메모리를 더 점유합니다. 대신 메모리를 점유하고 있으므로 유사한 요청을 더 빨리 처리할 것으로 기대합니다. 특히 이 위키 같은 페이지 수정은 적고 조회가 압도적으로 많은 사이트에서는 이런 효과를 더 기대해볼만 합니다. 반대로 값을 내리면 한 서비스가 더 적은 요청을 처리합니다. 더 짧게 살아있고 그만큼 메모리를 덜 점유합니다. 대신 서비스가 빠른 시점에 재시작되므로 유사한 요청을 처리할때 CPU를 더 많이 점유하고 응답속도가 더 느려질 것을 기대합니다. 양쪽 다 테스트해봤습니다.

테스트

테스트 1: 올려본다

첫번째 시도는 실패했습니다. 설정을 24시간 동안의 리퀘스트 평균값 정도로 설정하는 것이 널리 알려진 설정 방법이라길래 시도했는데 이 설정은 bitnami가 해 준 설정보다 굉장히 큰 값이었습니다. 서버를 재시작하고 24시간을 좀 넘기자 문제가 다시 일어났습니다. 남은 메모리는 쭉 줄어들다가 10% 미만으로 떨어졌고 다시 경고 메시지를 받았습니다. 한번 더 해볼까 하다가 이 정도면 됐다고 생각했습니다. 하루 리퀘스트 수에 가까운 숫자로 설정하는건 적절한 수준의 응답과 적절한 수준의 메모리를 사용하는 기준인 듯 하지만 제가 사용하는 인스턴스는 메모리가 2기가 뿐이라 제게는 잘 어울리지 않는 기준인 것 같았습니다.

테스트 2: 내려본다

두번째 시도는 값을 좀 줄여보는 겁니다. 줄였지만 여전히 처음 시작한 값보다는 컸습니다. 제가 경고를 받기까지 좀 더 오랜 시간동안 서버가 유지되었는데 남은 메모리가 줄어들다가 서비스가 재시작되면 일부가 반환되기를 반복하면서 얼마동안 유지됐습니다. 하지만 이 상황이 반복될수록 남은 메모리량은 점점 더 줄어들었고 어느 순간에는 더이상 회복되지 않는 것처럼 보였습니다. 그 상태로 놔두면 이 그래프 너머에서는 이전에 설정해둔 스왑 사용량이 증가하며 서버가 유지되었습니다만 썩 좋은 상황은 아니라고 판단했습니다. 다른 설정을 해볼 차례였습니다.

테스트 3: 더 더 내려본다

마지막으로 설정한 값은 1000입니다. bitnami LAMP Stack의 기본설정은 5000이고요. 메모리는 2기가이고 이전에 서버가 중단되는 상황을 겪을 때 스왑 2기가를 설정했습니다. 여기 저기서 읽은 글에는 서버에 스왑을 설정하고 이 공간이 사용되기 시작하면 큰 일인 것처럼 적혀있었지만 나이브하게 '요즘 세상에 스토리지도 SSD인데 괜찮지 않을까?'라고 생각하며 설정해놓은 것이었습니다. 더 적은 요청을 처리한 다음 서비스가 재시작되면 좀 더 오래 버티고 스왑을 좀 더 적게 사용하고 그 댓가로 응답시간이 더 늦어지는걸 감수하는 정도로 끝날 거라고 생각했습니다.

이전과 비슷하게 남은 메모리가 적은 상태로 서비스가 재시작되지 않은 채 유지되는 구간이 있기는 합니다만 저한테 경고가 날아올 상태는 아니었고 잠깐 그 상태를 유지하다가 재시작되며 메모리를 반환했고 며칠째 이런 상태가 안정적으로 유지되기 시작했습니다. 아이폰으로 터미널에 접근해 아파치를 재시작할 일이 없어졌고 체감 상 웹사이트는 이전과 큰 차이 없이 돌아가는 것처럼 보였습니다.

결과

예상과 달리 이 테스트를 진행한 기간 동안에 응답속도는 딱히 더 느려진 것처럼 보이지 않았습니다. 눈으로 대강 훑어보기에는요. 제 입장에서는 더이상 메모리 경고가 전달되지 않는 상태가 됐고 체감속도는 이전과 별 차이가 없는 것 같으며 응답속도 기록 역시 이전과 큰 차이가 없어 보이므로 이 정도면 일단 문제를 완화시킨 거라고 판단해도 되지 않을까 싶었습니다.

한편

한편 남은 메모리량이 그럭저럭 안정적으로 보이는 사이에 수면 아래에서도 일은 일어나고 있었습니다. 서비스가 재시작되지 않고 메모리를 점유하고 있는 동안 그 밑에서는 스왑을 적극적으로 사용하며 서버가 응답이 없어지는 상황을 간신히 모면하고 있는 것처럼 보였습니다. 이 판단이 옳은지는 알 수 없지만 어쨌든 체감속도에 별 차이 없이 서버가 유지되는 걸로 일단 이 문제에는 더이상 신경 쓰지 않을 작정입니다.

결론

내가 웹서버 설정을 똑바로 해낼 리 없기 때문에 bitnami LAMP Stack을 사용했는데 사양이 낮은 인스턴스에서는 그들의 설정이 기대한 대로 동작하지 않을 수 있고 결국 조금씩 배워가며 설정을 해내는 수밖에 없다는 사실을 깨달았습니다.