프로파일링

성능 문제를 추적하기 쉽게하기 위해 GitLab에는 일부 기본적으로 제공되는 프로파일링 도구가 함께 제공됩니다. 다른 일부 도구를 명시적으로 활성화해야 할 수도 있습니다.

URL 프로파일링

Gitlab::Profiler.profile 메서드와 해당하는 bin/profile-url 스크립트는 특정 URL의 GET 또는 POST 요청을 프로파일링하도록 설정합니다. 기본적으로 익명 사용자(기본값) 또는 특정 사용자로 프로파일링할 수 있습니다.

프로파일러의 첫 번째 인수는 완전한 URL(인스턴스 호스트명 포함) 또는 선행 슬래시를 포함한 절대 경로입니다.

기본 설정으로 보고서 덤프는 임시 파일에 저장되며, 이러한 파일은 Stackprof API를 사용하여 상호 작용할 수 있습니다.

스크립트를 사용할 때 인수를 전달하지 않고 실행하면 명령줄 문서가 사용 가능합니다.

대화형 콘솔 세션에서 메서드를 사용할 때 해당 콘솔 세션 내의 응용 프로그램 코드의 모든 변경 사항이 프로파일러 출력에 반영됩니다.

예를 들어:

Gitlab::Profiler.profile('/my-user')
# 보고서 덤프가 저장된 임시 파일 위치를 반환합니다
class UsersController; def show; sleep 100; end; end
Gitlab::Profiler.profile('/my-user')
# 100초가 UsersController#show에서 소비되었는지 확인할 수 있는 임시 파일의 위치를 반환합니다

인가를 필요로 하는 경로의 경우 Gitlab::Profiler에 사용자를 제공해야 합니다. 다음과 같이 수행할 수 있습니다.

Gitlab::Profiler.profile('/gitlab-org/gitlab-test', user: User.first)

Gitlab::Profiler.profilelogger: 키워드 인수를 전달하면 ActiveRecord 및 ActionController 로그 출력이 해당 로거로 전송됩니다. 추가적인 옵션은 메서드 소스와 함께 문서화되어 있습니다.

Gitlab::Profiler.profile('/gitlab-org/gitlab-test', user: User.first, logger: Logger.new($stdout))

샘플링 데이터의 출력 파일 (out)을 구성하려면 profiler_options 해시를 전달합니다. 예를 들어:

Gitlab::Profiler.profile('/gitlab-org/gitlab-test', user: User.first, profiler_options: { out: 'tmp/profile.dump' })

GitLab::Profiler 보고서 읽기

샘플링 데이터로 Stackprof를 실행하여 시간이 어디에 사용되었는지에 대한 요약 정보를 얻을 수 있습니다. 예를 들어:

stackprof tmp/profile.dump

샘플링 데이터의 예시:

==================================
  Mode: wall(1000)
  Samples: 8745 (6.92% miss rate)
  GC: 1399 (16.00%)
==================================
     TOTAL    (pct)     SAMPLES    (pct)     FRAME
      1022  (11.7%)        1022  (11.7%)     Sprockets::PathUtils#stat
      (이하 생략)

또한 플레임그래프를 생성할 수 있습니다:

stackprof --d3-flamegraph tmp/profile.dump > flamegraph.html

자세한 정보는 Stackprof 문서를 참조하세요.

Speedscope flamegraphs

특정 URL에 대한 Flamegraph를 생성하려면 성능 모니터링 막대에서 Flamegraph 샘플링 모드 버튼을 선택하거나 요청에 performance_bar=flamegraph 매개변수를 추가하면 됩니다.

Speedscope

Speedscope 문서에서 다양한 뷰에 대한 자세한 정보를 찾을 수 있습니다.

다양한 샘플링 모드에 대한 자세한 정보는 Stackprof 문서에서 확인할 수 있습니다.

이 기능은 성능 모니터링 막대에 액세스할 수 있는 모든 사용자에게 사용할 수 있습니다.

Bullet

Bullet는 N+1 쿼리 문제를 추적하는 데 사용할 수 있는 Gem입니다. 쿼리 문제를 레일즈 로그 및 브라우저 콘솔에 기록합니다. Bullet 섹션은 성능 모니터링 막대에 표시됩니다.

Bullet

기본적으로 Bullet는 개발 모드에서만 활성화됩니다. 그러나 로깅은 노이즈가 발생하므로 로깅이 비활성화됩니다. Bullet 및 해당 로깅을 구성하려면:

  • 환경별로 Bullet를 수동으로 활성화하거나 비활성화하려면 config/gitlab.yml에 다음 줄을 추가하고 enabled 값을 필요에 맞게 변경하세요.

    bullet:
      enabled: false
    
  • Bullet 로깅을 활성화하려면 GitLab을 시작하기 전에 ENABLE_BULLET 환경 변수를 비어 있지 않은 값으로 설정하세요.

    ENABLE_BULLET=true bundle exec rails s
    

Bullet를 사용하여 N+1 쿼리를 찾은 후에는 회귀를 방지하기 위해 QueryRecoder test를 작성하는 것을 고려하세요.

시스템 통계

프로파일링 중이거나 프로파일링 이후에는 루비 가상 머신 프로세스에 대한 메모리 사용, CPU에서 보낸 시간 또는 가비지 컬렉터 통계와 같은 자세한 정보를 얻고 싶을 수 있습니다. 이러한 정보는 각각의 도구를 통해 쉽게 생성할 수 있지만 편리하게 데이터를 내보내는 요약 엔드포인트가 추가되었습니다.

curl localhost:3000/-/metrics/system | jq

예시 출력:

{
  "version": "ruby 2.7.2p137 (2020-10-01 revision a8323b79eb) [x86_64-linux-gnu]",
  "gc_stat": {
    "count": 118,
    "heap_allocated_pages": 11503,
    "heap_sorted_length": 11503,
    "heap_allocatable_pages": 0,
    "heap_available_slots": 4688580,
    "heap_live_slots": 3451712,
    "heap_free_slots": 1236868,
    "heap_final_slots": 0,
    "heap_marked_slots": 3451450,
    "heap_eden_pages": 11503,
    "heap_tomb_pages": 0,
    "total_allocated_pages": 11503,
    "total_freed_pages": 0,
    "total_allocated_objects": 32679478,
    "total_freed_objects": 29227766,
    "malloc_increase_bytes": 84760,
    "malloc_increase_bytes_limit": 32883343,
    "minor_gc_count": 88,
    "major_gc_count": 30,
    "compact_count": 0,
    "remembered_wb_unprotected_objects": 114228,
    "remembered_wb_unprotected_objects_limit": 228456,
    "old_objects": 3185330,
    "old_objects_limit": 6370660,
    "oldmalloc_increase_bytes": 21838024,
    "oldmalloc_increase_bytes_limit": 119181499
  },
  "memory_rss": 1326501888,
  "memory_uss": 1048563712,
  "memory_pss": 1139554304,
  "time_cputime": 82.885264633,
  "time_realtime": 1610459445.5579069,
  "time_monotonic": 24001.23145713,
  "worker_id": "puma_0"
}

참고: 이 엔드포인트는 Rails 웹 워커에만 사용할 수 있습니다. Sidekiq 워커는 이 방식으로 검사할 수 없습니다.

성능에 영향을 주는 설정

애플리케이션 설정

  1. 기본적으로 development 환경에서는 핫 리로딩이 활성화되어 있어서 Rails가 모든 요청마다 파일 변경을 확인하고 잠재적 충돌 잠금을 만듭니다. 개발용 프로파일링/벤치마킹을 위해 이러한 기능을 비활성화하려면 GitLab을 시작하기 전에 RAILS_PROFILE 환경 변수를 true로 설정하세요. 예를 들어 GDK를 사용하는 경우:
    • 루트 GDK 디렉터리에 env.runit 파일을 만드세요.
    • env.runit 파일에 export RAILS_PROFILE=true를 추가하세요.
    • gdk restart로 GDK를 다시 시작하세요.

이 환경 변수는 개발 모드에만 적용됩니다.

GC 설정

Ruby의 가비지 컬렉터(GC)는 응용 프로그램 성능에 직접적인 영향을 미칠 수 있는 다양한 환경 변수를 통해 조정할 수 있습니다.

다음 표는 이러한 변수들과 기본 값들을 나열하고 있습니다.

환경 변수 기본 값
RUBY_GC_HEAP_INIT_SLOTS 10000
RUBY_GC_HEAP_FREE_SLOTS 4096
RUBY_GC_HEAP_FREE_SLOTS_MIN_RATIO 0.20
RUBY_GC_HEAP_FREE_SLOTS_GOAL_RATIO 0.40
RUBY_GC_HEAP_FREE_SLOTS_MAX_RATIO 0.65
RUBY_GC_HEAP_GROWTH_FACTOR 1.8
RUBY_GC_HEAP_GROWTH_MAX_SLOTS 0 (disable)
RUBY_GC_HEAP_OLDOBJECT_LIMIT_FACTOR 2.0
RUBY_GC_MALLOC_LIMIT(_MIN) (16 * 1024 * 1024 /* 16MB */)
RUBY_GC_MALLOC_LIMIT_MAX (32 * 1024 * 1024 /* 32MB */)
RUBY_GC_MALLOC_LIMIT_GROWTH_FACTOR 1.4
RUBY_GC_OLDMALLOC_LIMIT(_MIN) (16 * 1024 * 1024 /* 16MB */)
RUBY_GC_OLDMALLOC_LIMIT_MAX (128 * 1024 * 1024 /* 128MB */)
RUBY_GC_OLDMALLOC_LIMIT_GROWTH_FACTOR 1.2

(원본)

GitLab은 이러한 설정들을 변경하여 응용 프로그램 성능을 향상시키고 메모리 요구 사항을 줄이거나 둘 다를 위해 결정할 수 있습니다.

scripts/perf/gc/collect_gc_stats.rb 스크립트를 실행하여 GitLab의 유휴 상태에서 각 설정이 GC 성능, 메모리 사용 및 응용 프로그램 시작 시간에 어떻게 영향을 미치는지 확인할 수 있습니다. 이 스크립트는 표준 출력으로 GC 통계 및 일반 타이밍 데이터를 CSV 형식으로 출력합니다.