Skip to content

Commit

Permalink
Added nakayoshi_fork option.
Browse files Browse the repository at this point in the history
Reduce memory usage in preloaded cluster-mode apps by GCing before
fork and compacting, where available.
  • Loading branch information
nateberkopec committed May 11, 2020
1 parent 1a0e309 commit 731a2f1
Show file tree
Hide file tree
Showing 5 changed files with 31 additions and 7 deletions.
2 changes: 1 addition & 1 deletion 5.0-Upgrade.md
Expand Up @@ -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)
Expand Down
6 changes: 3 additions & 3 deletions History.md
@@ -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)
* 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)
Expand Down
2 changes: 1 addition & 1 deletion lib/puma/binder.rb
Expand Up @@ -113,7 +113,7 @@ def parse(binds, logger, log_msg = 'Listening')
i.local_address.ip_unpack.join(':')
end

logger.log "* #{log_msg} on tcp://#{addr}"
logger.log "* #{log_msg} on http://#{addr}"
end
end

Expand Down
15 changes: 13 additions & 2 deletions lib/puma/cluster.rb
Expand Up @@ -298,7 +298,7 @@ def worker(index, master)
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
Expand Down Expand Up @@ -540,7 +540,7 @@ def run
@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

Expand Down Expand Up @@ -644,5 +644,16 @@ def timeout_workers
end
end
end

def nakayoshi_gc
return unless @options[:nakayoshi_fork]
log "! Promoting existing objects to old generation..."
3.times { GC.start }
if GC.respond_to?(:compact)
log "! Compacting..."
GC.compact
end
log "! Friendly fork preparation complete."
end
end
end
13 changes: 13 additions & 0 deletions lib/puma/dsl.rb
Expand Up @@ -759,5 +759,18 @@ def set_remote_address(val=:socket)
def fork_worker(after_requests=1000)
@options[:fork_worker] = Integer(after_requests)
end

# When enabled, Puma will GC 3 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

0 comments on commit 731a2f1

Please sign in to comment.