unicorn 3.6.1 → 3.6.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,7 +1,7 @@
1
1
  #!/bin/sh
2
2
 
3
3
  GVF=GIT-VERSION-FILE
4
- DEF_VER=v3.6.1.GIT
4
+ DEF_VER=v3.6.2.GIT
5
5
 
6
6
  LF='
7
7
  '
data/TUNING CHANGED
@@ -1,12 +1,34 @@
1
- = Tuning Unicorn
1
+ = Tuning \Unicorn
2
2
 
3
- Unicorn performance is generally as good as a (mostly) Ruby web server
3
+ \Unicorn performance is generally as good as a (mostly) Ruby web server
4
4
  can provide. Most often the performance bottleneck is in the web
5
5
  application running on Unicorn rather than Unicorn itself.
6
6
 
7
- == Unicorn Configuration
7
+ == \Unicorn Configuration
8
8
 
9
9
  See Unicorn::Configurator for details on the config file format.
10
+ +worker_processes+ is the most-commonly needed tuning parameter.
11
+
12
+ === Unicorn::Configurator#worker_processes
13
+
14
+ * worker_processes should be scaled to the number of processes your
15
+ backend system(s) can support. DO NOT scale it to the number of
16
+ external network clients your application expects to be serving.
17
+ \Unicorn is NOT for serving slow clients, that is the job of nginx.
18
+
19
+ * worker_processes should be *at* *least* the number of CPU cores on
20
+ a dedicated server. If your application has occasionally slow
21
+ responses that are /not/ CPU-intensive, you may increase this to
22
+ workaround those inefficiencies.
23
+
24
+ * worker_processes may be increased for Unicorn::OobGC users to provide
25
+ more consistent response times.
26
+
27
+ * Never, ever, increase worker_processes to the point where the system
28
+ runs out of physical memory and hits swap. Production servers should
29
+ never see heavy swap activity.
30
+
31
+ === Unicorn::Configurator#listen Options
10
32
 
11
33
  * Setting a very low value for the :backlog parameter in "listen"
12
34
  directives can allow failover to happen more quickly if your
@@ -30,6 +52,11 @@ See Unicorn::Configurator for details on the config file format.
30
52
  and may also thrash CPU caches, cancelling out performance gains
31
53
  one would normally expect.
32
54
 
55
+ * UNIX domain sockets are slighly faster than TCP sockets, but only
56
+ work if nginx is on the same machine.
57
+
58
+ == Other \Unicorn settings
59
+
33
60
  * Setting "preload_app true" can allow copy-on-write-friendly GC to
34
61
  be used to save memory. It will probably not work out of the box with
35
62
  applications that open sockets or perform random I/O on files.
@@ -40,12 +67,7 @@ See Unicorn::Configurator for details on the config file format.
40
67
  * On POSIX-compliant filesystems, it is safe for multiple threads or
41
68
  processes to append to one log file as long as all the processes are
42
69
  have them unbuffered (File#sync = true) or they are
43
- record(line)-buffered in userspace.
44
-
45
- * worker_processes should be scaled to the number of processes your
46
- backend system(s) can support. DO NOT scale it to the number of
47
- external network clients your application expects to be serving.
48
- Unicorn is NOT for serving slow clients, that is the job of nginx.
70
+ record(line)-buffered in userspace before any writes.
49
71
 
50
72
  == Kernel Parameters (Linux sysctl)
51
73
 
@@ -1,33 +1,2 @@
1
- # Run GC after every request, before attempting to accept more connections.
2
- #
3
- # You could customize this patch to read REQ["PATH_INFO"] and only
4
- # call GC.start after expensive requests.
5
- #
6
- # We could have this wrap the response body.close as middleware, but the
7
- # scannable stack is would still be bigger than it would be here.
8
- #
9
- # This shouldn't hurt overall performance as long as the server cluster
10
- # is at <=50% CPU capacity, and improves the performance of most memory
11
- # intensive requests. This serves to improve _client-visible_
12
- # performance (possibly at the cost of overall performance).
13
- #
14
- # We'll call GC after each request is been written out to the socket, so
15
- # the client never sees the extra GC hit it. It's ideal to call the GC
16
- # inside the HTTP server (vs middleware or hooks) since the stack is
17
- # smaller at this point, so the GC will both be faster and more
18
- # effective at releasing unused memory.
19
- #
20
- # This monkey patch is _only_ effective for applications that use a lot
21
- # of memory, and will hurt simpler apps/endpoints that can process
22
- # multiple requests before incurring GC.
23
-
24
- class Unicorn::HttpServer
25
- REQ = Unicorn::HttpRequest::REQ
26
- alias _process_client process_client
27
- undef_method :process_client
28
- def process_client(client)
29
- _process_client(client)
30
- REQ.clear
31
- GC.start
32
- end
33
- end if defined?(Unicorn)
1
+ # see {Unicorn::OobGC}[http://unicorn.bogomips.org/Unicorn/OobGC.html]
2
+ # Unicorn::OobGC was broken in Unicorn v3.3.1 - v3.6.1 and fixed in v3.6.2
@@ -125,10 +125,15 @@ http {
125
125
  proxy_redirect off;
126
126
 
127
127
  # set "proxy_buffering off" *only* for Rainbows! when doing
128
- # Comet/long-poll stuff. It's also safe to set if you're
129
- # using only serving fast clients with Unicorn + nginx.
130
- # Otherwise you _want_ nginx to buffer responses to slow
131
- # clients, really.
128
+ # Comet/long-poll/streaming. It's also safe to set if you're using
129
+ # only serving fast clients with Unicorn + nginx, but not slow
130
+ # clients. You normally want nginx to buffer responses to slow
131
+ # clients, even with Rails 3.1 streaming because otherwise a slow
132
+ # client can become a bottleneck of Unicorn.
133
+ #
134
+ # The Rack application may also set "X-Accel-Buffering (yes|no)"
135
+ # in the response headers do disable/enable buffering on a
136
+ # per-response basis.
132
137
  # proxy_buffering off;
133
138
 
134
139
  proxy_pass http://app_server;
@@ -8,6 +8,8 @@ require 'logger'
8
8
  # example configuration files. An example config file for use with
9
9
  # nginx is also available at
10
10
  # http://unicorn.bogomips.org/examples/nginx.conf
11
+ #
12
+ # See the link:/TUNING.html document for more information on tuning unicorn.
11
13
  class Unicorn::Configurator
12
14
  include Unicorn
13
15
 
@@ -253,24 +255,32 @@ class Unicorn::Configurator
253
255
  #
254
256
  # [:tcp_nodelay => true or false]
255
257
  #
256
- # Disables Nagle's algorithm on TCP sockets if +true+
258
+ # Disables Nagle's algorithm on TCP sockets if +true+.
259
+ #
260
+ # Setting this to +true+ can make streaming responses in Rails 3.1
261
+ # appear more quickly at the cost of slightly higher bandwidth usage.
262
+ # The effect of this option is most visible if nginx is not used,
263
+ # but nginx remains highly recommended with \Unicorn.
257
264
  #
258
265
  # This has no effect on UNIX sockets.
259
266
  #
260
- # Default: operating system defaults (usually Nagle's algorithm enabled)
267
+ # Default: +false+ (Nagle's algorithm enabled) in \Unicorn,
268
+ # +true+ in Rainbows!
261
269
  #
262
270
  # [:tcp_nopush => true or false]
263
271
  #
264
272
  # Enables/disables TCP_CORK in Linux or TCP_NOPUSH in FreeBSD
265
273
  #
266
- # This is enabled by default as of Unicorn 3.4. This prevents partial
267
- # TCP frames from being sent out and reduces wakeups in nginx if it is
268
- # on a different machine. Since Unicorn is only designed for applications
269
- # that send the response body quickly without keepalive, sockets will
270
- # always be flushed on close to prevent delays.
274
+ # This prevents partial TCP frames from being sent out and reduces
275
+ # wakeups in nginx if it is on a different machine. Since \Unicorn
276
+ # is only designed for applications that send the response body
277
+ # quickly without keepalive, sockets will always be flushed on close
278
+ # to prevent delays.
271
279
  #
272
280
  # This has no effect on UNIX sockets.
273
281
  #
282
+ # Default: +true+ in \Unicorn 3.4+, +false+ in Rainbows!
283
+ #
274
284
  # [:tries => Integer]
275
285
  #
276
286
  # Times to retry binding a socket if it is already in use
@@ -8,8 +8,8 @@
8
8
  # improve things much compared to constants.
9
9
  module Unicorn::Const
10
10
 
11
- # The current version of Unicorn, currently 3.4.0
12
- UNICORN_VERSION = "3.4.0"
11
+ # The current version of Unicorn, currently 3.6.2
12
+ UNICORN_VERSION = "3.6.2"
13
13
 
14
14
  # default TCP listen host address (0.0.0.0, all interfaces)
15
15
  DEFAULT_HOST = "0.0.0.0"
@@ -1,58 +1,69 @@
1
1
  # -*- encoding: binary -*-
2
- module Unicorn
3
2
 
4
- # Run GC after every request, after closing the client socket and
5
- # before attempting to accept more connections.
6
- #
7
- # This shouldn't hurt overall performance as long as the server cluster
8
- # is at <50% CPU capacity, and improves the performance of most memory
9
- # intensive requests. This serves to improve _client-visible_
10
- # performance (possibly at the cost of overall performance).
11
- #
12
- # We'll call GC after each request is been written out to the socket, so
13
- # the client never sees the extra GC hit it.
14
- #
15
- # This middleware is _only_ effective for applications that use a lot
16
- # of memory, and will hurt simpler apps/endpoints that can process
17
- # multiple requests before incurring GC.
18
- #
19
- # This middleware is only designed to work with Unicorn, as it harms
20
- # keepalive performance.
21
- #
22
- # Example (in config.ru):
23
- #
24
- # require 'unicorn/oob_gc'
25
- #
26
- # # GC ever two requests that hit /expensive/foo or /more_expensive/foo
27
- # # in your app. By default, this will GC once every 5 requests
28
- # # for all endpoints in your app
29
- # use Unicorn::OobGC, 2, %r{\A/(?:expensive/foo|more_expensive/foo)}
30
- class OobGC < Struct.new(:app, :interval, :path, :nr, :env, :body)
31
-
32
- def initialize(app, interval = 5, path = %r{\A/})
33
- super(app, interval, path, interval)
34
- end
35
-
36
- def call(env)
37
- status, headers, self.body = app.call(self.env = env)
38
- [ status, headers, self ]
39
- end
3
+ # Runs GC after requests, after closing the client socket and
4
+ # before attempting to accept more connections.
5
+ #
6
+ # This shouldn't hurt overall performance as long as the server cluster
7
+ # is at <50% CPU capacity, and improves the performance of most memory
8
+ # intensive requests. This serves to improve _client-visible_
9
+ # performance (possibly at the cost of overall performance).
10
+ #
11
+ # Increasing the number of +worker_processes+ may be necessary to
12
+ # improve average client response times because some of your workers
13
+ # will be busy doing GC and unable to service clients. Think of
14
+ # using more workers with this module as a poor man's concurrent GC.
15
+ #
16
+ # We'll call GC after each request is been written out to the socket, so
17
+ # the client never sees the extra GC hit it.
18
+ #
19
+ # This middleware is _only_ effective for applications that use a lot
20
+ # of memory, and will hurt simpler apps/endpoints that can process
21
+ # multiple requests before incurring GC.
22
+ #
23
+ # This middleware is only designed to work with unicorn, as it harms
24
+ # performance with keepalive-enabled servers.
25
+ #
26
+ # Example (in config.ru):
27
+ #
28
+ # require 'unicorn/oob_gc'
29
+ #
30
+ # # GC ever two requests that hit /expensive/foo or /more_expensive/foo
31
+ # # in your app. By default, this will GC once every 5 requests
32
+ # # for all endpoints in your app
33
+ # use Unicorn::OobGC, 2, %r{\A/(?:expensive/foo|more_expensive/foo)}
34
+ #
35
+ # Feedback from users of early implementations of this module:
36
+ # * http://comments.gmane.org/gmane.comp.lang.ruby.unicorn.general/486
37
+ # * http://article.gmane.org/gmane.comp.lang.ruby.unicorn.general/596
38
+ module Unicorn::OobGC
40
39
 
41
- def each
42
- body.each { |x| yield x }
40
+ # this pretends to be Rack middleware because it used to be
41
+ # But we need to hook into unicorn internals so we need to close
42
+ # the socket before clearing the request env.
43
+ #
44
+ # +interval+ is the number of requests matching the +path+ regular
45
+ # expression before invoking GC.
46
+ def self.new(app, interval = 5, path = %r{\A/})
47
+ @@nr = interval
48
+ self.const_set :OOBGC_PATH, path
49
+ self.const_set :OOBGC_INTERVAL, interval
50
+ ObjectSpace.each_object(Unicorn::HttpServer) do |s|
51
+ s.extend(self)
52
+ self.const_set :OOBGC_ENV, s.instance_variable_get(:@request).env
43
53
  end
54
+ app # pretend to be Rack middleware since it was in the past
55
+ end
44
56
 
45
- # in Unicorn, this is closed _after_ the client socket
46
- def close
47
- body.close if body.respond_to?(:close)
48
-
49
- if path =~ env['PATH_INFO'] && ((self.nr -= 1) <= 0)
50
- self.nr = interval
51
- self.body = nil
52
- env.clear
53
- GC.start
54
- end
57
+ #:stopdoc:
58
+ PATH_INFO = "PATH_INFO"
59
+ def process_client(client)
60
+ super(client) # Unicorn::HttpServer#process_client
61
+ if OOBGC_PATH =~ OOBGC_ENV[PATH_INFO] && ((@@nr -= 1) <= 0)
62
+ @@nr = OOBGC_INTERVAL
63
+ OOBGC_ENV.clear
64
+ GC.start
55
65
  end
56
-
57
66
  end
67
+
68
+ # :startdoc:
58
69
  end
@@ -0,0 +1,21 @@
1
+ #\-E none
2
+ require 'unicorn/oob_gc'
3
+ use Rack::ContentLength
4
+ use Rack::ContentType, "text/plain"
5
+ use Unicorn::OobGC
6
+ $gc_started = false
7
+
8
+ # Mock GC.start
9
+ def GC.start
10
+ ObjectSpace.each_object(BasicSocket) do |x|
11
+ next if Unicorn::HttpServer::LISTENERS.include?(x)
12
+ x.closed? or abort "not closed #{x}"
13
+ end
14
+ $gc_started = true
15
+ end
16
+ run lambda { |env|
17
+ if "/gc_reset" == env["PATH_INFO"] && "POST" == env["REQUEST_METHOD"]
18
+ $gc_started = false
19
+ end
20
+ [ 200, {}, [ "#$gc_started\n" ] ]
21
+ }
@@ -0,0 +1,21 @@
1
+ #\-E none
2
+ require 'unicorn/oob_gc'
3
+ use Rack::ContentLength
4
+ use Rack::ContentType, "text/plain"
5
+ use Unicorn::OobGC, 5, /BAD/
6
+ $gc_started = false
7
+
8
+ # Mock GC.start
9
+ def GC.start
10
+ ObjectSpace.each_object(BasicSocket) do |x|
11
+ next if Unicorn::HttpServer::LISTENERS.include?(x)
12
+ x.closed? or abort "not closed #{x}"
13
+ end
14
+ $gc_started = true
15
+ end
16
+ run lambda { |env|
17
+ if "/gc_reset" == env["PATH_INFO"] && "POST" == env["REQUEST_METHOD"]
18
+ $gc_started = false
19
+ end
20
+ [ 200, {}, [ "#$gc_started\n" ] ]
21
+ }
@@ -0,0 +1,47 @@
1
+ #!/bin/sh
2
+ . ./test-lib.sh
3
+ t_plan 9 "OobGC test"
4
+
5
+ t_begin "setup and start" && {
6
+ unicorn_setup
7
+ unicorn -D -c $unicorn_config oob_gc.ru
8
+ unicorn_wait_start
9
+ }
10
+
11
+ t_begin "test default interval (4 requests)" && {
12
+ test xfalse = x$(curl -vsSf http://$listen/ 2>> $tmp)
13
+ test xfalse = x$(curl -vsSf http://$listen/ 2>> $tmp)
14
+ test xfalse = x$(curl -vsSf http://$listen/ 2>> $tmp)
15
+ test xfalse = x$(curl -vsSf http://$listen/ 2>> $tmp)
16
+ }
17
+
18
+ t_begin "GC starting-request returns immediately" && {
19
+ test xfalse = x$(curl -vsSf http://$listen/ 2>> $tmp)
20
+ }
21
+
22
+ t_begin "GC is started after 5 requests" && {
23
+ test xtrue = x$(curl -vsSf http://$listen/ 2>> $tmp)
24
+ }
25
+
26
+ t_begin "reset GC" && {
27
+ test xfalse = x$(curl -vsSf -X POST http://$listen/gc_reset 2>> $tmp)
28
+ }
29
+
30
+ t_begin "test default interval again (3 requests)" && {
31
+ test xfalse = x$(curl -vsSf http://$listen/ 2>> $tmp)
32
+ test xfalse = x$(curl -vsSf http://$listen/ 2>> $tmp)
33
+ test xfalse = x$(curl -vsSf http://$listen/ 2>> $tmp)
34
+ }
35
+
36
+ t_begin "GC is started after 5 requests" && {
37
+ test xtrue = x$(curl -vsSf http://$listen/ 2>> $tmp)
38
+ }
39
+
40
+ t_begin "killing succeeds" && {
41
+ kill -QUIT $unicorn_pid
42
+ }
43
+
44
+ t_begin "check_stderr" && check_stderr
45
+ dbgcat r_err
46
+
47
+ t_done
@@ -0,0 +1,75 @@
1
+ #!/bin/sh
2
+ . ./test-lib.sh
3
+ t_plan 12 "OobGC test with limited path"
4
+
5
+ t_begin "setup and start" && {
6
+ unicorn_setup
7
+ unicorn -D -c $unicorn_config oob_gc_path.ru
8
+ unicorn_wait_start
9
+ }
10
+
11
+ t_begin "test default is noop" && {
12
+ test xfalse = x$(curl -vsSf http://$listen/ 2>> $tmp)
13
+ test xfalse = x$(curl -vsSf http://$listen/ 2>> $tmp)
14
+ test xfalse = x$(curl -vsSf http://$listen/ 2>> $tmp)
15
+ test xfalse = x$(curl -vsSf http://$listen/ 2>> $tmp)
16
+ test xfalse = x$(curl -vsSf http://$listen/ 2>> $tmp)
17
+ test xfalse = x$(curl -vsSf http://$listen/ 2>> $tmp)
18
+ test xfalse = x$(curl -vsSf http://$listen/ 2>> $tmp)
19
+ test xfalse = x$(curl -vsSf http://$listen/ 2>> $tmp)
20
+ test xfalse = x$(curl -vsSf http://$listen/ 2>> $tmp)
21
+ }
22
+
23
+ t_begin "4 bad requests to bump counter" && {
24
+ test xfalse = x$(curl -vsSf http://$listen/BAD 2>> $tmp)
25
+ test xfalse = x$(curl -vsSf http://$listen/BAD 2>> $tmp)
26
+ test xfalse = x$(curl -vsSf http://$listen/BAD 2>> $tmp)
27
+ test xfalse = x$(curl -vsSf http://$listen/BAD 2>> $tmp)
28
+ }
29
+
30
+ t_begin "GC-starting request returns immediately" && {
31
+ test xfalse = x$(curl -vsSf http://$listen/BAD 2>> $tmp)
32
+ }
33
+
34
+ t_begin "GC was started after 5 requests" && {
35
+ test xtrue = x$(curl -vsSf http://$listen/ 2>> $tmp)
36
+ }
37
+
38
+ t_begin "reset GC" && {
39
+ test xfalse = x$(curl -vsSf -X POST http://$listen/gc_reset 2>> $tmp)
40
+ }
41
+
42
+ t_begin "test default is noop" && {
43
+ test xfalse = x$(curl -vsSf http://$listen/ 2>> $tmp)
44
+ test xfalse = x$(curl -vsSf http://$listen/ 2>> $tmp)
45
+ test xfalse = x$(curl -vsSf http://$listen/ 2>> $tmp)
46
+ test xfalse = x$(curl -vsSf http://$listen/ 2>> $tmp)
47
+ test xfalse = x$(curl -vsSf http://$listen/ 2>> $tmp)
48
+ test xfalse = x$(curl -vsSf http://$listen/ 2>> $tmp)
49
+ test xfalse = x$(curl -vsSf http://$listen/ 2>> $tmp)
50
+ test xfalse = x$(curl -vsSf http://$listen/ 2>> $tmp)
51
+ test xfalse = x$(curl -vsSf http://$listen/ 2>> $tmp)
52
+ }
53
+
54
+ t_begin "4 bad requests to bump counter" && {
55
+ test xfalse = x$(curl -vsSf http://$listen/BAD 2>> $tmp)
56
+ test xfalse = x$(curl -vsSf http://$listen/BAD 2>> $tmp)
57
+ test xfalse = x$(curl -vsSf http://$listen/BAD 2>> $tmp)
58
+ test xfalse = x$(curl -vsSf http://$listen/BAD 2>> $tmp)
59
+ }
60
+
61
+ t_begin "GC-starting request returns immediately" && {
62
+ test xfalse = x$(curl -vsSf http://$listen/BAD 2>> $tmp)
63
+ }
64
+
65
+ t_begin "GC was started after 5 requests" && {
66
+ test xtrue = x$(curl -vsSf http://$listen/ 2>> $tmp)
67
+ }
68
+
69
+ t_begin "killing succeeds" && {
70
+ kill -QUIT $unicorn_pid
71
+ }
72
+
73
+ t_begin "check_stderr" && check_stderr
74
+
75
+ t_done
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: unicorn
3
3
  version: !ruby/object:Gem::Version
4
- hash: 29
4
+ hash: 27
5
5
  prerelease:
6
6
  segments:
7
7
  - 3
8
8
  - 6
9
- - 1
10
- version: 3.6.1
9
+ - 2
10
+ version: 3.6.2
11
11
  platform: ruby
12
12
  authors:
13
13
  - Unicorn hackers
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-04-26 00:00:00 Z
18
+ date: 2011-04-30 00:00:00 Z
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  name: rack
@@ -213,6 +213,8 @@ files:
213
213
  - t/bin/utee
214
214
  - t/env.ru
215
215
  - t/my-tap-lib.sh
216
+ - t/oob_gc.ru
217
+ - t/oob_gc_path.ru
216
218
  - t/pid.ru
217
219
  - t/preread_input.ru
218
220
  - t/rack-input-tests.ru
@@ -279,6 +281,8 @@ files:
279
281
  - t/t0303-rails3-alt-working_directory_config.ru.sh
280
282
  - t/t0304-rails3-alt-working_directory_no_embed_cli.sh
281
283
  - t/t9000-preread-input.sh
284
+ - t/t9001-oob_gc.sh
285
+ - t/t9002-oob_gc-path.sh
282
286
  - t/test-lib.sh
283
287
  - t/test-rails3.sh
284
288
  - t/write-on-close.ru