Unicorn is an HTTP server for Rack applications designed to only serve fast clients on low-latency, high-bandwidth connections and take advantage of features in Unix/Unix-like kernels. Slow clients should only be served by placing a reverse proxy capable of fully buffering both the the request and response in between Unicorn and slow clients.
- Designed for Rack, Unix, fast clients, and ease-of-debugging. We cut out everything that is better supported by the operating system, nginx or Rack.
- Compatible with both Ruby 1.8 and 1.9. Rubinius support is in-progress.
- Process management: Unicorn will reap and restart workers that die from broken apps. There is no need to manage multiple processes or ports yourself. Unicorn can spawn and manage any number of worker processes you choose to scale to your backend.
- Load balancing is done entirely by the operating system kernel. Requests never pile up behind a busy worker process.
- Does not care if your application is thread-safe or not, workers all run within their own isolated address space and only serve one client at a time for maximum robustness.
- Supports all Rack applications, along with pre-Rack versions of Ruby on Rails via a Rack wrapper.
- Builtin reopening of all log files in your application via USR1 signal. This allows logrotate to rotate files atomically and quickly via rename instead of the racy and slow copytruncate method. Unicorn also takes steps to ensure multi-line log entries from one request all stay within the same file.
- nginx-style binary upgrades without losing connections. You can upgrade Unicorn, your entire application, libraries and even your Ruby interpreter without dropping clients.
- before_fork and after_fork hooks in case your application has special needs when dealing with forked processes. These should not be needed when the “preload_app” directive is false (the default).
- Can be used with copy-on-write-friendly memory management to save memory (by setting “preload_app” to true).
- Able to listen on multiple interfaces including UNIX sockets, each worker process can also bind to a private port via the after_fork hook for easy debugging.
- Simple and easy Ruby DSL for configuration.
- Decodes chunked transfers on-the-fly, thus allowing upload progress notification to be implemented as well as being able to tunnel arbitrary stream-based protocols over HTTP.
In APP_ROOT
, run:
unicorn
for Rails applications (should work for all 1.2 or later versions)
In RAILS_ROOT
, run:
unicorn_rails
Unicorn will bind to all interfaces on TCP port 8080 by default. You may use the --listen/-l
switch to bind to a different address:port or a UNIX socket.
# Sample verbose configuration file for Unicorn (not Rack)
#
# This configuration file documents many features of Unicorn
# that may not be needed for some applications. See
# http://unicorn.bogomips.org/examples/unicorn.conf.minimal.rb
# for a much simpler configuration file.
#
# See http://unicorn.bogomips.org/Unicorn/Configurator.html for complete
# documentation.
# Use at least one worker per core if you're on a dedicated server,
# more will usually help for _short_ waits on databases/caches.
worker_processes 15
# Since Unicorn is never exposed to outside clients, it does not need to
# run on the standard HTTP port (80), there is no reason to start Unicorn
# as root unless it's from system init scripts.
# If running the master process as root and the workers as an unprivileged
# user, do this to switch euid/egid in the workers (also chowns logs):
# user "unprivileged_user", "unprivileged_group"
module Rails
class << self
def root
File.expand_path("../..", __FILE__)
end
end
end
# Help ensure your application will always spawn in the symlinked
# "current" directory that Capistrano sets up.
# working_directory "/path/to/app/current" # available in 0.94.0+
working_directory Rails.root
# listen on both a Unix domain socket and a TCP port,
# we use a shorter backlog for quicker failover when busy
# listen "/path/to/.unicorn.sock", :backlog => 64
listen "/tmp/unicorn.guanxi_cms.sock"
listen 8000, :tcp_nopush => true
# nuke workers after 30 seconds instead of 60 seconds (the default)
timeout 30
# feel free to point this anywhere accessible on the filesystem
# pid "/path/to/app/shared/pids/unicorn.pid"
pid "#{Rails.root}/tmp/pids/unicorn.pid"
# By default, the Unicorn logger will write to stderr.
# Additionally, ome applications/frameworks log to stderr or stdout,
# so prevent them from going to /dev/null when daemonized here:
# stderr_path "/path/to/app/shared/log/unicorn.stderr.log"
# stdout_path "/path/to/app/shared/log/unicorn.stdout.log"
stderr_path "#{Rails.root}/log/unicorn.log"
stdout_path "#{Rails.root}/log/unicorn.log"
# combine Ruby 2.0.0dev or REE with "preload_app true" for memory savings
# http://rubyenterpriseedition.com/faq.html#adapt_apps_for_cow
# http://unicorn.bogomips.org/Unicorn/Configurator.html#method-i-preload_app
# preload_app true
GC.respond_to?(:copy_on_write_friendly=) and
GC.copy_on_write_friendly = true
# Enable this flag to have unicorn test client connections by writing the
# beginning of the HTTP headers before calling the application. This
# prevents calling the application for connections that have disconnected
# while queued. This is only guaranteed to detect clients on the same
# host unicorn runs on, and unlikely to detect disconnects even on a
# fast LAN.
check_client_connection false
module Rails
class << self
def root
File.expand_path("../..", __FILE__)
end
end
end
rails_env = ENV["RAILS_ENV"] || "production"
before_exec do |server|
ENV["BUNDLE_GEMFILE"] = "#{Rails.root}/Gemfile"
end
before_fork do |server, worker|
old_pid = "#{Rails.root}/tmp/pids/unicorn.pid.oldbin"
if File.exists?(old_pid) && server.pid != old_pid
begin
Process.kill("QUIT", File.read(old_pid).to_i)
rescue Errno::ENOENT, Errno::ESRCH
puts "Send 'QUIT' signal to unicorn error!"
end
end
end
after_fork do |server, worker|
# per-process listener ports for debugging/admin/migrations
# addr = "127.0.0.1:#{9293 + worker.nr}"
# server.listen(addr, :tries => -1, :delay => 5, :tcp_nopush => true)
# the following is *required* for Rails + "preload_app true",
# defined?(ActiveRecord::Base) and
# ActiveRecord::Base.establish_connection
# if preload_app is true, then you may also want to check and
# restart any other shared sockets/descriptors such as Memcached,
# and Redis. TokyoCabinet file handles are safe to reuse
# between any number of forked children (assuming your kernel
# correctly implements pread()/pwrite() system calls)
end
# unicorn.conf.rb path
set :unicorn_conf, "#{deploy_to}/current/config/unicorn.conf.rb"
set :unicorn_pid, "#{deploy_to}/current/tmp/pids/unicorn.pid"
namespace :deploy do
task :start, :roles => :app do
run "cd #{deploy_to}/current/; RAILS_ENV=production bundle exec unicorn_rails -c #{unicorn_conf} -D"
end
task :stop, :roles => :app do
run "kill -QUIT `cat #{unicorn_pid}`"
end
desc "Restart Application"
task :restart, :roles => :app do
#run "kill -USR2 `cat #{deploy_to}/current/tmp/pids/unicorn.pid`"
run "if [ -f #{unicorn_pid} ] ; then kill -USR2 \`cat #{unicorn_pid}\`; else cd #{deploy_to}/current && bundle exec unicorn -c #{unicorn_conf} -E #{rails_env} -D; fi"
end
end
http://my.oschina.net/cfanlds/blog/61890
#config/nginx.conf
# Sample verbose configuration file for Unicorn (not Rack)
#
# This configuration file documents many features of Unicorn
# that may not be needed for some applications. See
# http://unicorn.bogomips.org/examples/unicorn.conf.minimal.rb
# for a much simpler configuration file.
#
# See http://unicorn.bogomips.org/Unicorn/Configurator.html for complete
# documentation.
# Use at least one worker per core if you're on a dedicated server,
# more will usually help for _short_ waits on databases/caches.
worker_processes 15
# Since Unicorn is never exposed to outside clients, it does not need to
# run on the standard HTTP port (80), there is no reason to start Unicorn
# as root unless it's from system init scripts.
# If running the master process as root and the workers as an unprivileged
# user, do this to switch euid/egid in the workers (also chowns logs):
# user "unprivileged_user", "unprivileged_group"
module Rails
class << self
def root
File.expand_path("../..", __FILE__)
end
end
end
# Help ensure your application will always spawn in the symlinked
# "current" directory that Capistrano sets up.
# working_directory "/path/to/app/current" # available in 0.94.0+
working_directory Rails.root
# listen on both a Unix domain socket and a TCP port,
# we use a shorter backlog for quicker failover when busy
# listen "/path/to/.unicorn.sock", :backlog => 64
listen "/tmp/unicorn.guanxi_cms.sock"
listen 3000, :tcp_nopush => true
# nuke workers after 30 seconds instead of 60 seconds (the default)
timeout 30
# feel free to point this anywhere accessible on the filesystem
# pid "/path/to/app/shared/pids/unicorn.pid"
pid "#{Rails.root}/tmp/pids/unicorn.pid"
# By default, the Unicorn logger will write to stderr.
# Additionally, ome applications/frameworks log to stderr or stdout,
# so prevent them from going to /dev/null when daemonized here:
# stderr_path "/path/to/app/shared/log/unicorn.stderr.log"
# stdout_path "/path/to/app/shared/log/unicorn.stdout.log"
stderr_path "#{Rails.root}/log/unicorn.log"
stdout_path "#{Rails.root}/log/unicorn.log"
# combine Ruby 2.0.0dev or REE with "preload_app true" for memory savings
# http://rubyenterpriseedition.com/faq.html#adapt_apps_for_cow
preload_app true
GC.respond_to?(:copy_on_write_friendly=) and
GC.copy_on_write_friendly = true
# Enable this flag to have unicorn test client connections by writing the
# beginning of the HTTP headers before calling the application. This
# prevents calling the application for connections that have disconnected
# while queued. This is only guaranteed to detect clients on the same
# host unicorn runs on, and unlikely to detect disconnects even on a
# fast LAN.
check_client_connection false
module Rails
class << self
def root
File.expand_path("../..", __FILE__)
end
end
end
rails_env = ENV["RAILS_ENV"] || "production"
before_exec do |server|
ENV["BUNDLE_GEMFILE"] = "#{Rails.root}/Gemfile"
end
before_fork do |server, worker|
old_pid = "#{Rails.root}/tmp/pids/unicorn.pid.oldbin"
if File.exists?(old_pid) && server.pid != old_pid
begin
Process.kill("QUIT", File.read(old_pid).to_i)
rescue Errno::ENOENT, Errno::ESRCH
puts "Send 'QUIT' signal to unicorn error!"
end
end
end
after_fork do |server, worker|
# per-process listener ports for debugging/admin/migrations
# addr = "127.0.0.1:#{9293 + worker.nr}"
# server.listen(addr, :tries => -1, :delay => 5, :tcp_nopush => true)
# the following is *required* for Rails + "preload_app true",
# defined?(ActiveRecord::Base) and
# ActiveRecord::Base.establish_connection
# if preload_app is true, then you may also want to check and
# restart any other shared sockets/descriptors such as Memcached,
# and Redis. TokyoCabinet file handles are safe to reuse
# between any number of forked children (assuming your kernel
# correctly implements pread()/pwrite() system calls)
end
- http://unicorn.bogomips.org/Unicorn/OobGC.html
- http://blog.newrelic.com/2013/05/28/unicorn-rawk-kick-gc-out-of-the-band/
- https://github.com/kzk/unicorn-worker-killer
demo config.ru
# This file is used by Rack-based servers to start the application.
if defined?(ENV) and ENV["RAILS_ENV"].eql?("production")
#if self.class.const_defined?("Unicorn") and self.class.const_defined?("Unicorn::WorkerKiller")
require 'unicorn/oob_gc'
require 'unicorn/worker_killer'
# 每10次请求,才执行一次GC
use Unicorn::OobGC, 10
# 设定最大请求次数后自杀,避免禁止GC带来的内存泄漏(1000~1800之间随机,避免同时多个进程同时自杀,可以和下面的设定任选)
use Unicorn::WorkerKiller::MaxRequests, 1000, 1800
# 设定达到最大内存后自杀,避免禁止GC带来的内存泄漏(192~256MB之间随机,避免同时多个进程同时自杀)
use Unicorn::WorkerKiller::Oom, (192*(1024**2)), (256*(1024**2))
end
require ::File.expand_path('../config/environment', __FILE__)
run GuanxiCms::Application
#config/nginx.conf
upstream unicorn {
server unix:/tmp/unicorn.guanxi_cms.sock fail_timeout=0;
}
server {
listen 8000 default deferred;
server_name cms.guanxi.me;
root /home/guanxi/deployment/guanxi_cms/current/public;
location ^~ /assets/ {
gzip_static on;
expires max;
add_header Cache-Control public;
}
try_files $uri/index.html $uri @unicorn;
location @unicorn {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://unicorn;
}
error_page 500 502 503 504 /500.html;
client_max_body_size 4G;
keepalive_timeout 10;
}
# sudo cp config/nginx.conf /etc/nginx/sites-enabled/
#!/bin/sh
# sudo cp config/unicorn_init.rh
### BEGIN INIT INFO
# Provides: unicorn
# Required-Start: $remote_fs $syslog
# Required-Stop: $remote_fs $syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Manage unicorn server
# Description: Start, stop, restart unicorn server for a specific application.
### END INIT INFO
set -e
# Feel free to change any of the following variables for your app:
TIMEOUT=${TIMEOUT-60}
APP_ROOT=/home/guanxi/deployment/guanxi_cms/current
PID=$APP_ROOT/tmp/pids/unicorn.pid
CMD="cd $APP_ROOT; RAILS_ENV=production bundle exec unicorn -D -c $APP_ROOT/config/unicorn.conf.rb -E production"
AS_USER=guanxi
set -u
OLD_PIN="$PID.oldbin"
sig () {
test -s "$PID" && kill -$1 `cat $PID`
}
oldsig () {
test -s $OLD_PIN && kill -$1 `cat $OLD_PIN`
}
run () {
if [ "$(id -un)" = "$AS_USER" ]; then
eval $1
else
su -c "$1" - $AS_USER
fi
}
case "$1" in
start)
sig 0 && echo >&2 "Already running" && exit 0
run "$CMD"
;;
stop)
sig QUIT && exit 0
echo >&2 "Not running"
;;
force-stop)
sig TERM && exit 0
echo >&2 "Not running"
;;
restart|reload)
sig HUP && echo reloaded OK && exit 0
echo >&2 "Couldn't reload, starting '$CMD' instead"
run "$CMD"
;;
upgrade)
if sig USR2 && sleep 2 && sig 0 && oldsig QUIT
then
n=$TIMEOUT
while test -s $OLD_PIN && test $n -ge 0
do
printf '.' && sleep 1 && n=$(( $n - 1 ))
done
echo
if test $n -lt 0 && test -s $OLD_PIN
then
echo >&2 "$OLD_PIN still exists after $TIMEOUT seconds"
exit 1
fi
exit 0
fi
echo >&2 "Couldn't upgrade, starting '$CMD' instead"
run "$CMD"
;;
reopen-logs)
sig USR1
;;
*)
echo >&2 "Usage: $0 <start|stop|restart|upgrade|force-stop|reopen-logs>"
exit 1
;;
esac
# sudo ln -nfs /data/guanxi/gxservice/config/unicorn_init.sh /etc/init.d/unicorn_gxserver
# chmod a+x /etc/init.d/unicorn_gxserver
# /etc/init.d/unicorn_gxserver restart
namespace :deploy do
%w[start stop restart].each do |command|
desc "#{command} unicorn server"
task command, roles: :app, except: {no_release: true} do
run "chmod a+x /etc/init.d/unicorn_#{application}"
run "/etc/init.d/unicorn_#{application} #{command}" # Using unicorn as the app server
end
end
task :init_path, :roles => :web do
#run "mkdir -p #{deploy_to}/shared/log"
#run "mkdir -p #{deploy_to}/shared/pids"
#run "mkdir -p #{deploy_to}/shared/assets"
end
task :setup_config, roles: :app do
#run "sudo mkdir -p /etc/nginx/sites-enabled/"
#sudo "ln -nfs #{current_path}/config/nginx.conf /etc/nginx/sites-enabled/#{application}"
sudo "ln -nfs #{current_path}/config/nginx.conf /opt/nginx/sites-enabled/#{application}"
sudo "rm /etc/init.d/unicorn_#{application}"
sudo "ln -nfs #{current_path}/config/unicorn_init.sh /etc/init.d/unicorn_#{application}.conf"
run "chmod a+x /etc/init.d/unicorn_#{application}"
#run "mkdir -p #{shared_path}/config"
#put File.read("config/database.yml"), "#{shared_path}/config/database.yml"
puts "Now edit the config files in #{shared_path}."
end
end
执行下面的命令部署
cap deploy:setup_config
#cap deploy:cold
HUP - reloads config file and gracefully restart all workers. If the “preload_app” directive is false (the default), then workers will also pick up any application code changes when restarted. If “preload_app” is true, then application code changes will have no effect; USR2 + QUIT (see below) must be used to load newer code in this case. When reloading the application, Gem.refresh will be called so updated code for your application can pick up newly installed RubyGems. It is not recommended that you uninstall libraries your application depends on while Unicorn is running, as respawned workers may enter a spawn loop when they fail to load an uninstalled dependency.