세스코가 필요해
예전에 있던 일이다. 급하게 인수인계 받은 어플리케이션이있다. 인수인계가 끝나고(전임자가 떠나고) 내 손에 착륙한 그 날부터 에러가 터지기 시작했다. 상황 1. 시스템에 대해 물어볼 사람은 없다. 2. 어플리케이션 동작을 이해하기 위한 로그는 없었다. 3. 모니터링 툴은 프로메테우스만 있다. 4. 환경과 상황상 어플리케이션을 모니터링하기 위한 무언가를 설치할 수 없다. 이러한 상황에서 시스템을 해부하다보니 발견되는 비밀들은 덤이었다. 일부러 인수인계를 안해줬다기보단 디테일에 있어서 챙기지 못한 부분들인 것 같다. (프로메테우스도 파드를 뒤져보다가 찾았다.) 뭐가 됐든 이미 팽팽 돌고 있으며 사용량이 한 단계 증가함에 따라 이전에는 발생하지 않던 현상들이 나타나고 있는 시스템을 치료해줘야했다. 치료를 하려면 어디가 아픈지 알아야 한다. 사람이라면 질문을 해가며 어디가 아픈지 구체화할 수 있지만, 컴퓨터는 대화가 안 된다. 이를 위해서 시스템 로그를 넣어서 올리기엔 리스크가 너무 컸다. 유일한 관찰 수단은 키바나와 프로메테우스였다. 먼저 프로메테우스를 살펴봤다. 메모리 부분을 살펴보니 몇 개 파드에서 full gc가 발생한 듯한 현상을 확인했다. 비슷한 시간대에 로그를 키바나 통해 확인해보았다. 특별한 로그는 없었다. 일단 메모리가 뭔가 문제는 있구나를 깨달았다. 그러나 프러메테우스를 더 관찰해보니 full gc와 비슷한 현상이 발생하고 나서 바로 급격히 메모리가 차는 현상을 발견했다. 이게 이렇게 빠르게 찰 일인가? 메모리릭인가? 싶어 어플리케이션의 메모리를 확인할 방법을 찾았다. 다행히 자바 기반 어플리케이션이라 jmap, jstat 과 같은 것으로 힙 메모리 확인이 가능했다. 주기적으로 각 파드 내부 어플리케이션을 대상으로 힙 메모리 사이즈와 gc상황을 모니터링했다. 그 결과, 어느 순간부터 특정 인스턴스의 메모리가 누적되었고 어플리케이션에 설정한 힙 사이즈에 도달한 순간 메모리와 gc count가 리셋됐다. gc count가 리셋되기 직전에는 full gc가 몇 차례 반복되었으나, old 영역은 줄어들지 않았다. 이러한 관찰 결과를 바탕으로 세운 가설은 이렇다. 1. 어느 순간(특정 이벤트 이후) 메모리 릭으로 메모리가 차올랐다. 2. 메모리가 어플리케이션 빌드 시 지정한 힙사이즈에 가까워지자 full gc가 발생했다. 3. Full gc가 발생하는 동안 k8s에서 해당 파드의 health check를 시도했고, 어플리케이션이 정상 응답을 못했다. 4. k8s가 해당 파드를 재시작시켰고, 파드는 재시작하며 메모리를 비웠다. 이 과정에서 깨달는 내용은 프로메테우스 상에 나오는 메모리량을 어플리케이션의 힙 메모리의 현재 크기라고 생각하면 안 된다!! 자 이제, 메모리가 차오르기 시작하게 되는 이유를 찾아야했다. 차오르는 이유의 힌트는 위 1번 특정 이벤트가 되겠다. 해당 이벤트를 찾기 위해 키바나에 쌓인 로그를 뒤졌고 그 결과 gc가 막 일어나기 전에 특정 에러 메세지가 발생하는 것을 확인했다. Could not emit tick. 다음에 이어서..