매우 중요한 세 가지 프로파일링 기법에 대해 살펴보자.
- 샘플링을 통해 앱 코드의 어떤 부분이 실행되는지 확인한다.
- 실행을 프로파일링(인스트루멘테이션(instrumentation))하여 잘못된 부분을 찾아내 최적화한다.
- 앱을 프로파일링하여 DB와 통신하는 SQL 쿼리를 식별한다.
1. 샘플링으로 실행되는 코드 관찰
샘플링이란 프로파일러로 앱이 실행되는 코드를 찾아내는 방법이다.
실행 자체에 대한 상세 정보는 많이 제공하지 않지만, 어떤 일이 일어나고 있는지 큰 그림을 그려보고 추가 분석에 필요한 정보를 제공한다.
샘플링은 항상 앱 프로파일링의 첫 단계로 활용하는 것이 좋고, 사실 샘플링만으로도 충분한 경우가 많다.
실습 시나리오는 다음과 같다.
- cURL 또는 포스트맨으로 앱에 구현된 /demo 엔드포인트를 호출한다.
- 앱은 다시 httpbin.org에 있는 엔드포인트를 호출한다. 응답시간은 5초인데 너무 오래 걸린다.
- /demo 엔드포인트의 실행 시간이 왜 이렇게 오래 걸리는지 모른다고 가정하고 원인을 조사한다.
프로파일링은 다음 두 단계로 진행된다.
- 샘플링을 통해 어떤 코드가 실행되는지 파악하고 어느 부분을 좀 더 자세히 들여다봐야 하는지 알아낸다.
- 프로파일링을 통해 특정 코드의 실행에 관한 상세 정보를 얻는다.
이번 예제의 문제는 /demo 엔드포인트를 호출하면 응답 시간이 5초 이상 걸리는데 너무 느리다는 것이다.
그럼 왜 이렇게 느린걸까? 앱 자체의 문제인가, 아니면 다른 문제인가?
본인이 코드를 잘 모르는 앱의 속도 저하 문제를 조사할 때는 제일 먼저 프로파일러를 떠올리는 것이 좋다.
이제 실제로 샘플링을 진행해보자. 샘플링하는 목적은 크게 세 가지다.
1. 어떤 코드가 실행되는지 알아낸다
샘플링을 수행하려면 백그라운드에서 어떤 코드가 실행되는지 알 수 있다. 앱에서 어느 부분을 조사해야할지 알려주는 방법
2. CPU 사용량 파악하기
레이턴시 문제를 조사하면서 어떤 메서드가 실행 시간을 공유하는지 파악한다.
3. 메모리 소비량 파악하기
메모리와 관련된 문제를 분석한다.
Sampler 탭을 열어 앱 샘플링을 진행한다.
CPU 버튼을 클릭하면 실행 중인 스레드를 VM이 가로챈다.
우리는 실행중인 스레드를 확인할 수 있다. 또한 스레드별 실행 스택을 확인할 수 있다.
/demo 엔드포인트를 호출한 후, 스레드 실행 스택을 펼쳐보면 앱이 실행되는 도중에 무슨 일을 하는지 정확히 알 수 있다.
예제에서 속도 저하를 일으킨 범인은 바로 HttpURLConnection 클래스의 getResponseCode()다.
여기서 중요한건 CPU 시간이 0인 것이다.
이 메서드는 HTTP 호출을 하고 응답을 대기만 5초를 했기 때문에 CPU 리소스를 전혀 사용하지 않았다.
따라서 앱에 문제가 있는게 아니라 HTTP 요청을 보내고 응답을 기다리는 과정에서 느려졌다는 결론을 내릴 수 있다.
참고로 샘플링을 활용하면 자바 진영의 다이내믹 프록시 파악이 쉬우므로 프레임워크를 공부할 때 편리하다.
2. 프로파일링으로 메서드의 실행 횟수 파악
앱을 프로파일링할 때 전체 코드베이스를 조사하는 대신, 조사에 꼭 필요한 부분만 걸러내는 것이 좋다.
프로파일링은 리소스가 많이 소모되는 작업이므로 정말 성능이 좋은 시스템이 아닌 한, 만사를 프로파일링하려면 엄청난 시간이 소요된다.
따라서 항상 먼저 샘플링부터 해본 후에 프로파일링 대상을 식별하는 것이 합리적이다.
규모가 큰 앱에서는 프로파일링할 때에는 가급적 가로챌 코드의 범위를 제한하라.
여담으로 프로파일러 세팅을 하는데 Preset 설정이 안되어서 한참 헤맸는데.. 해당 프로젝트에게 other 쓰기 권한을 주니 변경이 가능했다.
com.example.**과 feign.**로 필터링하면서 코드 범위를 제한했다.
프로파일링을 통해 메서드 호출횟수는 모두 1회인 것을 확인할 수 있다.
3. 프로파일러로 앱이 실제로 실행하는 SQL 쿼리 파악
우리는 프로파일러를 통해 코드 분석을 하지 않고, 앱이 어떻게 작동하는지 분석할 수 있다.
위 내용처럼 어떤 메서드가 몇번 호출되는지 확인할 수 있고, 어떤 SQL이 몇번 날라갔는지 확인할 수 있다.
위 예제에서는 쿼리가 10번 실행되는 것을 찾았으므로 이를 개선하면 된다.
ORM을 쓰거나 직접 쿼리를 보내는 것도 동일하게 SQL을 확인할 수 있다.
이유는 프로파일러가 JDBC 드라이버를 거쳐 DB로 흘러가는 SQL 쿼리라면 어느것도 가로챌 수 있기 때문이다.
댓글