프로파일링
성능 문제를 추적하기 쉽게 하기 위해 GitLab은 일련의 프로파일링 도구를 제공합니다. 이 중 일부는 기본적으로 제공되며, 다른 일부는 명시적으로 활성화해야 합니다.
URL 프로파일링
특정 URL에 대한 GET 또는 POST 요청을 프로파일링할 수 있는 Gitlab::Profiler.profile
메서드와 해당하는 bin/profile-url
스크립트가 있습니다. 익명 사용자(기본값) 또는 특정 사용자로 프로파일링할 수 있습니다.
프로파일러의 첫 번째 인수는 전체 URL(인스턴스 호스트 이름 포함) 또는 슬래시가 포함된 절대 경로입니다.
기본적으로 보고서 덤프는 임시 파일에 저장되며, 이 파일은 Stackprof API를 사용하여 상호작용할 수 있습니다.
스크립트를 사용할 때는 인수 없이 명령줄 문서를 볼 수 있습니다.
대화형 콘솔 세션에서 메서드를 사용할 경우, 해당 콘솔 세션 내에서 애플리케이션 코드의 모든 변경 사항이 프로파일러 출력에 반영됩니다.
예를 들면:
Gitlab::Profiler.profile('/my-user')
# 보고서 덤프가 저장된 임시 파일의 위치를 반환합니다
class UsersController; def show; sleep 100; end; end
Gitlab::Profiler.profile('/my-user')
# 보고서 덤프가 저장된 임시 파일의 위치를 반환합니다
# UsersController#show에서 100초가 소모됩니다
인증이 필요한 경로의 경우 Gitlab::Profiler
에 사용자를 제공해야 합니다. 다음과 같이 할 수 있습니다:
Gitlab::Profiler.profile('/gitlab-org/gitlab-test', user: User.first)
Gitlab::Profiler.profile
에 logger:
키워드 인수를 전달하면 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
예시 샘플링 데이터:
==================================
모드: wall(1000)
샘플: 8745 (6.92% 누락률)
GC: 1399 (16.00%)
==================================
총계 (pct) 샘플 (pct) 프레임
1022 (11.7%) 1022 (11.7%) Sprockets::PathUtils#stat
957 (10.9%) 957 (10.9%) (marking)
493 (5.6%) 493 (5.6%) Sprockets::PathUtils#entries
576 (6.6%) 471 (5.4%) Mustermann::AST::Translator#decorator_for
439 (5.0%) 439 (5.0%) (sweeping)
630 (7.2%) 241 (2.8%) Sprockets::Cache::FileStore#get
208 (2.4%) 208 (2.4%) ActiveSupport::FileUpdateChecker#watched
206 (2.4%) 206 (2.4%) Digest::Instance#file
544 (6.2%) 176 (2.0%) Sprockets::Cache::FileStore#safe_open
176 (2.0%) 176 (2.0%) ActiveSupport::FileUpdateChecker#max_mtime
268 (3.1%) 147 (1.7%) ActiveRecord::ConnectionAdapters::PostgreSQLAdapter#exec_no_cache
140 (1.6%) 140 (1.6%) ActiveSupport::BacktraceCleaner#add_gem_filter
116 (1.3%) 116 (1.3%) Bootsnap::CompileCache::ISeq.storage_to_output
160 (1.8%) 113 (1.3%) Gem::Version#<=>
109 (1.2%) 109 (1.2%) block in <main>
108 (1.2%) 108 (1.2%) Gem::Version.new
131 (1.5%) 105 (1.2%) Sprockets::EncodingUtils#unmarshaled_deflated
1166 (13.3%) 82 (0.9%) Mustermann::RegexpBased#initialize
82 (0.9%) 78 (0.9%) FileUtils.touch
72 (0.8%) 72 (0.8%) Sprockets::Manifest.compile_match_filter
71 (0.8%) 70 (0.8%) Grape::Router#compile!
91 (1.0%) 65 (0.7%) ActiveRecord::ConnectionAdapters::PostgreSQL::DatabaseStatements#query
93 (1.1%) 64 (0.7%) ActionDispatch::Journey::Path::Pattern::AnchoredRegexp#accept
59 (0.7%) 59 (0.7%) Mustermann::AST::Translator.dispatch_table
62 (0.7%) 59 (0.7%) Rails::BacktraceCleaner#initialize
2492 (28.5%) 49 (0.6%) Sprockets::PathUtils#stat_directory
242 (2.8%) 49 (0.6%) Gitlab::Instrumentation::RedisBase.add_call_details
47 (0.5%) 47 (0.5%) URI::RFC2396_Parser#escape
46 (0.5%) 46 (0.5%) #<Class:0x00000001090c2e70>#__setobj__
44 (0.5%) 44 (0.5%) Sprockets::Base#normalize_logical_path
플레임그래프를 생성할 수도 있습니다:
stackprof --d3-flamegraph tmp/profile.dump > flamegraph.html
자세한 내용은 Stackprof 문서를 참조하세요.
Speedscope 플레임 그래프
특정 URL에 대한 플레임 그래프를 생성하려면 성능 바에서 플레임 그래프 샘플링 모드 버튼을 선택하거나 요청에 performance_bar=flamegraph
매개변수를 추가하십시오.
Speedscope 문서에서 뷰에 대한 자세한 정보를 확인하세요.
Stackprof 문서에서 다양한 샘플링 모드에 대한 자세한 정보를 확인하세요.
성능 바에 접근할 수 있는 모든 사용자에게 사용 가능하도록 설정되어 있습니다.
Bullet
Bullet은 N+1 쿼리 문제를 추적하는 데 사용할 수 있는 Gem입니다. Rails 로그와 브라우저 콘솔에 쿼리 문제를 기록합니다. 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 테스트를 작성하는 것을 고려하십시오.
시스템 통계
프로파일링 중 또는 이후에 Ruby 가상 머신 프로세스에 대한 자세한 정보, 예를 들어 메모리 소비, CPU에서 소요된 시간 또는 가비지 컬렉터 통계를 얻고 싶을 수 있습니다. 이러한 정보는 다양한 도구를 통해 개별적으로 쉽게 생성할 수 있지만, 편의를 위해 이 데이터를 JSON 페이로드로 내보내는 요약 엔드포인트가 추가되었습니다:
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 워커는 이 방법으로 검사할 수 없습니다.
성능에 영향을 미치는 설정
애플리케이션 설정
- 기본적으로
development
환경은 핫 리로딩이 활성화되어 작동하며, 이로 인해 Rails가 매 요청마다 파일 변경 사항을 확인하고, 핫 리로드가 단일 스레드로 작동하므로 잠재적인 경합 잠금을 생성합니다. -
development
환경은 요청이 발생하면 코드를 지연 로딩할 수 있으며, 이로 인해 첫 번째 요청이 항상 느려집니다.
프로파일링/벤치마킹을 위한 이러한 기능을 비활성화하려면 GitLab을 시작하기 전에 RAILS_PROFILE
환경 변수를 true
로 설정하세요. 예를 들어 GDK를 사용할 때:
- 루트 GDK 디렉토리에
env.runit
파일을 생성합니다. -
env.runit
파일에export RAILS_PROFILE=true
를 추가합니다. -
gdk restart
로 GDK를 재시작합니다.
이 환경 변수는 개발 모드에만 적용됩니다.
GC 설정
루비의 가비지 컬렉터(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 (비활성화) |
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은 애플리케이션 성능을 높이거나 메모리 요구 사항을 줄이기 위해 이러한 설정을 변경할 수 있습니다.
각 설정이 GC 성능, 메모리 사용 및 GitLab의 유휴 인스턴스 시작 시간에 어떻게 영향을 미치는지 보려면 scripts/perf/gc/collect_gc_stats.rb
스크립트를 실행하세요. 이 스크립트는 GC 통계 및 일반 타이밍 데이터를 CSV 형식으로 표준 출력에 출력합니다.