Browse Source

[ruby/grape] Use autotune for puma and unicorn workers/threads (#8534)

Petrik de Heus 1 year ago
parent
commit
7c3ee349d9

+ 41 - 0
frameworks/Ruby/grape/config/auto_tune.rb

@@ -0,0 +1,41 @@
+#!/usr/bin/env ruby
+# Instantiate about one process per X MiB of available memory, scaling up to as
+# close to MAX_THREADS as possible while observing an upper bound based on the
+# number of virtual/logical CPUs. If there are fewer processes than
+# MAX_THREADS, add threads per process to reach MAX_THREADS.
+require 'etc'
+
+KB_PER_WORKER = 64 * 1_024 # average of peak PSS of single-threaded processes (watch smem -k)
+MIN_WORKERS = 2
+MAX_WORKERS_PER_VCPU = 1.25 # virtual/logical
+MIN_THREADS_PER_WORKER = 1
+MAX_THREADS = Integer(ENV['MAX_CONCURRENCY'] || 256)
+
+def meminfo(arg)
+  File.open('/proc/meminfo') do |f|
+    f.each_line do |line|
+      key, value = line.split(/:\s+/)
+      return value.split(/\s+/).first.to_i if key == arg
+    end
+  end
+
+  raise "Unable to find `#{arg}' in /proc/meminfo!"
+end
+
+def auto_tune
+  avail_mem = meminfo('MemAvailable') * 0.8 - MAX_THREADS * 1_024
+
+  workers = [
+    [(1.0 * avail_mem / KB_PER_WORKER).floor, MIN_WORKERS].max,
+    [(Etc.nprocessors * MAX_WORKERS_PER_VCPU).ceil, MIN_WORKERS].max
+  ].min
+
+  threads_per_worker = [
+    workers < MAX_THREADS ? (1.0 * MAX_THREADS / workers).ceil : -Float::INFINITY,
+    MIN_THREADS_PER_WORKER
+  ].max
+
+  [workers, threads_per_worker]
+end
+
+p auto_tune if $PROGRAM_NAME == __FILE__

+ 13 - 0
frameworks/Ruby/grape/config/puma.rb

@@ -0,0 +1,13 @@
+require_relative 'auto_tune'
+
+# FWBM only... use the puma_auto_tune gem in production!
+num_workers, num_threads = auto_tune
+
+workers num_workers
+threads num_threads, num_threads
+# Use the `preload_app!` method when specifying a `workers` number.
+# This directive tells Puma to first boot the application and load code
+# before forking the application. This takes advantage of Copy On Write
+# process behavior so workers use less memory.
+#
+preload_app!

+ 3 - 1
frameworks/Ruby/grape/config/unicorn.rb

@@ -1,4 +1,6 @@
-worker_processes 8
+require_relative 'auto_tune'
+
+worker_processes, = auto_tune
 listen "/tmp/unicorn.sock", :backlog => 4096
 listen "/tmp/unicorn.sock", :backlog => 4096
 
 
 preload_app true
 preload_app true

+ 1 - 1
frameworks/Ruby/grape/grape.dockerfile

@@ -10,4 +10,4 @@ RUN bundle install --jobs=4 --gemfile=/grape/Gemfile --path=/grape/grape/bundle
 
 
 EXPOSE 8080
 EXPOSE 8080
 
 
-CMD bundle exec puma -t 8:32 -w 8 --preload -b tcp://0.0.0.0:8080 -e production
+CMD bundle exec puma -C config/puma.rb -b tcp://0.0.0.0:8080 -e production