Get memory data after booting app in production

Preload the app in `production` env, hit it with a single request, and
gather total gem memory consumption data using `derailed exec perf:mem`
from `derailed_benchmarks`. Present the result as MR metrics.
This commit is contained in:
Aleksei Lipniagov 2019-06-25 15:11:06 +03:00
parent 5ee5b280b0
commit fb1d433703
4 changed files with 40 additions and 5 deletions

View file

@ -17,3 +17,26 @@ memory-static:
- tmp/memory_*.txt - tmp/memory_*.txt
reports: reports:
metrics: tmp/memory_metrics.txt metrics: tmp/memory_metrics.txt
# Show memory usage caused by invoking require per gem.
# Unlike `memory-static`, it hits the app with one request to ensure that any last minute require-s have been called.
# The application is booted in `production` environment.
# All tests are run without a webserver (directly using Rack::Mock by default).
memory-on-boot:
extends: .rspec-metadata-pg-10
variables:
NODE_ENV: "production"
RAILS_ENV: "production"
SETUP_DB: "true"
SKIP_STORAGE_VALIDATION: "true"
# we override the max_old_space_size to prevent OOM errors
NODE_OPTIONS: --max_old_space_size=3584
script:
# Both bootsnap and derailed monkey-patch Kernel#require, which leads to circular dependency
- DISABLE_BOOTSNAP=true PATH_TO_HIT="/users/sign_in" CUT_OFF=0.3 bundle exec derailed exec perf:mem >> 'tmp/memory_on_boot.txt'
- scripts/generate-memory-metrics-on-boot tmp/memory_on_boot.txt >> 'tmp/memory_on_boot_metrics.txt'
artifacts:
paths:
- tmp/memory_*.txt
reports:
metrics: tmp/memory_on_boot_metrics.txt

View file

@ -3,7 +3,7 @@ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
# Set up gems listed in the Gemfile. # Set up gems listed in the Gemfile.
require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE']) require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])
begin begin
require 'bootsnap/setup' require 'bootsnap/setup' unless ENV['DISABLE_BOOTSNAP']
rescue LoadError rescue LoadError
# bootsnap is an optional dependency, so if we don't have it, it's fine # bootsnap is an optional dependency, so if we don't have it, it's fine
end end

View file

@ -0,0 +1,11 @@
#!/usr/bin/env ruby
abort "usage: #{__FILE__} <memory_bundle_mem_file_name>" unless ARGV.length == 1
memory_bundle_mem_file_name = ARGV.first
full_report = File.open(memory_bundle_mem_file_name).read
stats = /TOP: (?<total_mibs_str>.*) MiB/.match(full_report)
abort 'failed to process the benchmark output' unless stats
puts "total_memory_used_by_dependencies_on_boot_prod_env_mb #{stats[:total_mibs_str].to_f.round(1)}"

View file

@ -35,6 +35,7 @@ sed -i 's/username: root/username: gitlab/g' config/database.yml
if [ "$GITLAB_DATABASE" = 'postgresql' ]; then if [ "$GITLAB_DATABASE" = 'postgresql' ]; then
sed -i 's/localhost/postgres/g' config/database.yml sed -i 's/localhost/postgres/g' config/database.yml
sed -i 's/username: git/username: postgres/g' config/database.yml
if [ -f config/database_geo.yml ]; then if [ -f config/database_geo.yml ]; then
sed -i 's/localhost/postgres/g' config/database_geo.yml sed -i 's/localhost/postgres/g' config/database_geo.yml
@ -48,16 +49,16 @@ else # Assume it's mysql
fi fi
cp config/resque.yml.example config/resque.yml cp config/resque.yml.example config/resque.yml
sed -i 's/localhost/redis/g' config/resque.yml sed -i 's|url:.*$|url: redis://redis:6379|g' config/resque.yml
cp config/redis.cache.yml.example config/redis.cache.yml cp config/redis.cache.yml.example config/redis.cache.yml
sed -i 's/localhost/redis/g' config/redis.cache.yml sed -i 's|url:.*$|url: redis://redis:6379/10|g' config/redis.cache.yml
cp config/redis.queues.yml.example config/redis.queues.yml cp config/redis.queues.yml.example config/redis.queues.yml
sed -i 's/localhost/redis/g' config/redis.queues.yml sed -i 's|url:.*$|url: redis://redis:6379/11|g' config/redis.queues.yml
cp config/redis.shared_state.yml.example config/redis.shared_state.yml cp config/redis.shared_state.yml.example config/redis.shared_state.yml
sed -i 's/localhost/redis/g' config/redis.shared_state.yml sed -i 's|url:.*$|url: redis://redis:6379/12|g' config/redis.shared_state.yml
if [ "$SETUP_DB" != "false" ]; then if [ "$SETUP_DB" != "false" ]; then
setup_db setup_db