Posts 프로파일러로 시스템 성능 향상시키기
Post
Cancel

프로파일러로 시스템 성능 향상시키기

토스 SLASH23 의 ‘프로파일러로 시스템 성능 향상시키기’’ 에 대한 학습 내용을 정리하기 위한 목적의 TIL 포스팅입니다.🙆‍♂️

pinpoint

  • MSA 환경에서 클라이언트 요청은 여러 서비스들을 통해 처리되곤하다보니 한 서버의 문제가 다른 서버로 영향을 미치게됨
  • pinpoint는 분산 트랜잭션 툴
  • 서비스간 호출 확인 및 어느 코드가 얼머나 걸렸는지 알 수 있음 (datadog 처럼)

힙덤프 분석으로 Old Gen 개선 사례

  • 한 마이크로서비스에서 old generation 이 다른 서비스에 비해 빠르게 증가하였고, gc gime 이 늘어나는 현상이 있었음
  • gc time 을 줄이기 위해 힙덤프를 떠보기로했음
  • 힙덤프 분석으로 인해 어느 객체가 가장 많이 차지하고 있고, 어느 클래스에서 사용되었는지를 트리로 확인 가능하여 아래와 같은 개선작업 진행
    • 1)레디스 응답 속도 메트릭을 쌓으며 새로운 객체를 만들고 있었음. 그래서 지속적으로 메모리가 높아진 경우임. 옵션을 꺼서 객체가 많아지는것 방지
    • 2)JSON 라이브러리가 필드 이름을 사용하며 메모리가 높아지는 경우가 있었음. 새로운 필드명이 계속 생성되는 경우 메모리가 높아질수있어서 CANONICALIZE_FIELD_NAMES 옵션을 꺼서 사용중임

Note: 힙덤프뜰떄 기본적이 gc 가 발생하기에 분석대상이 사라지는 경우가 있는데 all옵션을 주게되면 gc 대상도 그대로 남게되고 memory analyzer tool에서 해당 옵션을 선택하면 분석대상을 보존할수 있음

Jemalloc 이용 사례

  • 컨테이너 메모리는 사용하는 양보다 어느 정도 여유를 줘서 메모리를 할당함
  • 그렇지않으면 메모리부족으로 애플리케이션이 내려갈수있음
  • 그런데 예상치 못하게 서비스가 할당된 양보다 더 많이 사용하려는 경우가 있음
  • 힙은 옵션으로 최대사용량이 정해져있어서 문제가 안되고 대부분 Native Memory 사용량이 늘면서 발생함
  • Native Memory 분석툴이 Jemalloc을 사용하면 Native Memory 를 개선할 수 있음

Async-Profiler 이용 사례

  • CPU와 메모리 프로파일링
  • 일정시간마다 샘플 수집하는 Wall-Clock 모드도 있어서 스레드가 멈춰있는 경우도 확인 가능
  • 애플리케이션 스택도 샘플링하고 리눅스 커널의 Perf_event도 함께 사용되서 시스템 분석도 동시에 가능하다는 장점도 있음
  • 프로파일 결과는 Flamegrapth, JFR 파일로 저장 가능하고, JFR 파일은 인텔리제이에서 보다 편리하게 확인 가능함
  • 토스는 엘라스틱서치를 로그 검색으로 사용중인데 로그양이 많아 점점 CPU 부하가 심해졌음
  • 엘라스틱서치같이 내부 코드를 잘몰라도 Asny-Profiler 를 통해 어느부분에서 CPU 를 많이 사용하는지 알수있음
    • 프로파일 결과를 살펴보다 날짜 관련 포맷 변환처리가 cpu 를 꽤 많이 차지하였고, 내부적으로 iso 형식의 긴날짜 문자열을 사용중이었음
    • 에폭밀리스로 개선후 프로파일러로 성능 개선 효과 확인 가능
  • Spring Cloud Gateway 를 사용중이고 정기적으로 프로파일링을 진행하는데 메모리가 많이 사용되는 부분을 찾게 되었음
    • Gateway 에 요청이 들어올때마다 매번 Route 개수만큼 주소를 파싱하고 있었음
    • Route를 미리 파싱하고 캐시하는것으로 성능 향상시켰음

Strace, Perf Trace 이용 사례

  • 가끔 애플리케이션 문제인지 시스템 문제인지 분석이 필요할때가 있음
  • Strace는 시스템 콜분석으로 유용한 툴
  • 어떤 시스템콜이 어떠 스레드에서 호출되었고 얼만큼 시간이 걸렸는지 알 수 있음
  • 하지만 프로파일 하는동안 성능이 떨어지는 문제점이 있음
  • Perf Trace 또한 시스템 콜분석인데 훨씬 좋은 성능을 가짐
  • 다만 낮은 리눅스 버전에선 지원 x
  • 때로는 빌드된 Perf 버전을 못 구할수 있는데 그럴땐 커널툴을 비륻해서 사용할 수 있음
  • 애플리케이션 로그에서 레디스 응답속도가 느린경우가 있었음. 핀포인트에서도 동일하게 파악되었음
  • 네트워크 문제인것 같아 TCPdump 로 확인하였더니
    • 1)레디스에서 늦게 보내는 경우도 있었고
    • 2)레디스에서 빨리 보냈지만, 애플리케이션에서 늦게 응답받는 경우도 있었음
  • 일단 레디스에서 빨리 보냈지만 애플리케이션에서 늦게 응답받는 경우에 집중하기로 하였음
  • 패킷을 받은 다음 애플리케이션 처리하는 과정을 생각해보면, 시스템콜이 있고, 이벤트루프가 있음
  • 시스템콜이 늦게 올라왔거나, 이벤트 루프가 멈춰있거나 둘 중 하나로 예상되었음
  • Async-Profiler 의 Wall-Clock은 멈춰있는 스레드를 찾아서 실행해보았음
  • 이벤트 루프에서 네트워크 데이터가 올 때까지 기다리다보니 패킷이 왔지만 기다리는 경우와 오지 않아서 기다리는 경우가 구분이 안됨
  • 그래서 Strace로 시스템콜을 확인하였음(리눅스 커널버전이 낮아서)
  • 애플리케이션 로그에서 응답이 느린 스레드를 찾고, 비슷한 시간대의 Strace 로그를 찾아서 200ms 이상 응답이 느린 부분을 발견하게 되었지만 Rocky Linux 로 커널 버전 업그레이드후 사라짐

Unix Domain Socket 이용 사례

Binary Ninja 이용 사례

  • 외부 라이브러리를 사용하다 문제 발생시 스스로 문제 원인을 파악하고 싶을때가 있음. 분석 결과를 외부 라이브러리 회사에 전달하면 더 빠르게 대응이 가능하기에
  • 좋은 디컴파일러 사용시 어셈블리보다 훨씬 보기 쉬운 형태로 코드 확인 가능
  • 레거시 코드를 컨테이너화하는 도중 사용중인 라이브러리에 문제가 있는 경우가 있었음
  • 그때 Binary Ninja 툴을 사용하여 에러 지점에서 어떤 작업을하는지 확인할수있었고, 라이센스 문제를 바로 파악할수 있었음.
  • 담당회사에 이 내용을 전달하여 라이센스 파일을 바로 받아 빠르게 문제 해결을 할 수 있었음

앞으로..

  • 위와 같이 분석한 경험을 바탕으로 똑같은 장애를 다시 겪지 않도록 자동화

1) 핀포인트로 Anti-Pattern 파악

  • 핀포인트를 통해 서비스 스택을 분석하고, 문제 있는 패턴이 존재하는지 파악
  • 배포 프로세스에 적용한다면 장애 예방이 가능

2) JFR 분석 자동화

  • 하나하나 직접 분석하지 않아도 CPU, 메모리가 많이 사용되거나 기존에 비해 비약적으로 증가하는 부분을 담당자에게 노티되도록

3)eBPF를 활용한 가시성 강화

  • eBPF를 활용해서 애플리케이션, 네트워크, 시스템 지표를 분리
  • 이렇게 분리된 지표는 장애발생시 빠른 원인 분석에 도움됨
This post is licensed under CC BY 4.0 by the author.

지속 성장 가능한 코드를 만들어 가는 방법

Service Mesh