1
0
Fork 0
mirror of https://github.com/puma/puma.git synced 2022-11-09 13:48:40 -05:00

Added nakayoshi_fork option.

Reduce memory usage in preloaded cluster-mode apps by GCing before
fork and compacting, where available.
This commit is contained in:
Nate Berkopec 2020-05-11 12:50:36 +09:00
parent 1a0e309f08
commit 72ebf4458b
No known key found for this signature in database
GPG key ID: BDD7A4B8E43906A6
5 changed files with 46 additions and 6 deletions

View file

@ -6,9 +6,9 @@ Puma 5 brings new experimental performance features, a few quality-of-life featu
* **Better throughput and lower latency via new experimental option**
* **Better memory usage via new experimental option**
* **Better copy-on-write performance via new experimental option**
* **Loads of bugfixes**
* Faster phased restarts and worker timeouts
* GC Compact/friendly fork
* pumactl now has a `thread-backtraces` command to print thread backtraces, bringing thread backtrace printing to all platforms, not just *BSD and Mac. (#2053)
* Added incrementing `requests_count` to `Puma.stats`. (#2106)
* Faster phased restart and worker timeout (#2220)

View file

@ -1,9 +1,9 @@
## 5.0.0
* Features
* EXPERIMENTAL: Add `fork_worker` option and `refork` command for reduced memory usage. (#2099)
* EXPERIMENTAL: Reduce latency on MRI through inserting a small delay before re-listening on the socket if worker is busy (#2079).
* Possibly reduced memory usage by calling `GC.compact` before fork if available (Ruby 2.7+) (#2093)
* EXPERIMENTAL: Add `fork_worker` option and `refork` command for reduced memory usage by forking from a worker process and eliminating the master process. (#2099)
* EXPERIMENTAL: Added `wait_for_less_busy_worker` config. This may reduce latency on MRI through inserting a small delay before re-listening on the socket if worker is busy (#2079).
* EXPERIMENTAL: Added `nakayoshi_fork` option. Reduce memory usage in preloaded cluster-mode apps by GCing before fork and compacting, where available. (#2093, #2256)
* Added pumactl `thread-backtraces` command to print thread backtraces (#2054)
* Added incrementing `requests_count` to `Puma.stats`. (#2106)
* Increased maximum URI path length from 2048 to 8196 bytes (#2167)

View file

@ -298,7 +298,7 @@ module Puma
restart_server.clear
server.begin_restart(true)
@launcher.config.run_hooks :before_refork, nil, @launcher.events
GC.compact if GC.respond_to?(:compact)
nakayoshi_gc
end
elsif idx == 0 # restart server
restart_server << true << false
@ -540,7 +540,7 @@ module Puma
@master_read, @worker_write = read, @wakeup
@launcher.config.run_hooks :before_fork, nil, @launcher.events
GC.compact if GC.respond_to?(:compact)
nakayoshi_gc
spawn_workers
@ -644,5 +644,16 @@ module Puma
end
end
end
def nakayoshi_gc
return unless @options[:nakayoshi_fork]
log "! Promoting existing objects to old generation..."
4.times { GC.start(full_mark: false) }
if GC.respond_to?(:compact)
log "! Compacting..."
GC.compact
end
log "! Friendly fork preparation complete."
end
end
end

View file

@ -759,5 +759,18 @@ module Puma
def fork_worker(after_requests=1000)
@options[:fork_worker] = Integer(after_requests)
end
# When enabled, Puma will GC 4 times before forking workers.
# If available (Ruby 2.7+), we will also call GC.compact.
# Not recommended for non-MRI Rubies.
#
# Based on the work of Koichi Sasada and Aaron Patterson, this option may
# decrease memory utilization of preload-enabled cluster-mode Pumas. It will
# also increase time to boot and fork. See your logs for details on how much
# time this adds to your boot process. For most apps, it will be less than one
# second.
def nakayoshi_fork(enabled=false)
@options[:nakayoshi_fork] = enabled
end
end
end

View file

@ -168,6 +168,22 @@ RUBY
refute_includes pids, get_worker_pids(1, WORKERS - 1)
end
def test_nakayoshi
cli_server "-w #{WORKERS} test/rackup/hello.ru", config: <<RUBY
nakayoshi_fork true
RUBY
output = nil
Timeout.timeout(10) do
until output
output = @server.gets[/Friendly fork preparation complete/]
sleep(0.01)
end
end
assert output, "Friendly fork didn't run"
end
private
def worker_timeout(timeout, iterations, config)