comparison upstream_max_conns.t @ 1041:187524328926

Tests: upstream max_conns tests.
author Sergey Kandaurov <pluknet@nginx.com>
date Fri, 23 Sep 2016 00:02:46 +0300
parents
children 766bcbb632ee
comparison
equal deleted inserted replaced
1040:1a820a5a32ae 1041:187524328926
1 #!/usr/bin/perl
2
3 # (C) Nginx, Inc.
4
5 # Tests for upstream module with max_conns feature.
6
7 ###############################################################################
8
9 use warnings;
10 use strict;
11
12 use Test::More;
13
14 use IO::Select;
15
16 BEGIN { use FindBin; chdir($FindBin::Bin); }
17
18 use lib 'lib';
19 use Test::Nginx qw/ :DEFAULT http_end /;
20
21 ###############################################################################
22
23 select STDERR; $| = 1;
24 select STDOUT; $| = 1;
25
26 my $t = Test::Nginx->new()
27 ->has(qw/http proxy rewrite upstream_least_conn upstream_ip_hash/);
28
29 $t->write_file_expand('nginx.conf', <<'EOF');
30
31 %%TEST_GLOBALS%%
32
33 daemon off;
34
35 events {
36 }
37
38 http {
39 %%TEST_GLOBALS_HTTP%%
40
41 upstream u_unlim {
42 server 127.0.0.1:8081 max_conns=0;
43 server 127.0.0.1:8082;
44 }
45 upstream u_lim {
46 server 127.0.0.1:8081 max_conns=3;
47 }
48
49 upstream u_backup {
50 server 127.0.0.1:8081 max_conns=2;
51 server 127.0.0.1:8082 backup;
52 }
53 upstream u_backup_lim {
54 server 127.0.0.1:8081 max_conns=2;
55 server 127.0.0.1:8082 backup max_conns=3;
56 }
57
58 upstream u_two {
59 server 127.0.0.1:8081 max_conns=1;
60 server 127.0.0.1:8082 max_conns=1;
61 }
62 upstream u_some {
63 server 127.0.0.1:8081 max_conns=1;
64 server 127.0.0.1:8082;
65 }
66 upstream u_many {
67 server 127.0.0.1:8081 max_conns=1;
68 server 127.0.0.1:8081 max_conns=1;
69 server 127.0.0.1:8082;
70 }
71
72 upstream u_weight {
73 server 127.0.0.1:8081 weight=2 max_conns=1;
74 server 127.0.0.1:8082;
75 }
76
77 upstream u_pnu {
78 # special server to force next upstream
79 server 127.0.0.1:8084;
80
81 server 127.0.0.1:8081 max_conns=1;
82 server 127.0.0.1:8082 max_conns=2;
83 }
84
85 upstream u_lc {
86 least_conn;
87 server 127.0.0.1:8081 max_conns=1;
88 server 127.0.0.1:8082;
89 }
90 upstream u_lc_backup {
91 least_conn;
92 server 127.0.0.1:8081 max_conns=2;
93 server 127.0.0.1:8082 backup;
94 }
95 upstream u_lc_backup_lim {
96 least_conn;
97 server 127.0.0.1:8081 max_conns=2;
98 server 127.0.0.1:8082 backup max_conns=3;
99 }
100
101 upstream u_ih {
102 ip_hash;
103 server 127.0.0.1:8081 max_conns=1;
104 }
105
106 server {
107 listen 127.0.0.1:8084;
108 server_name localhost;
109
110 location / {
111 return 444;
112 }
113 }
114
115 server {
116 listen 127.0.0.1:8080;
117 server_name localhost;
118
119 proxy_http_version 1.1;
120 proxy_set_header Connection "";
121 proxy_buffering off;
122
123 location /u {
124 proxy_pass http:/$uri;
125 }
126
127 location /close {
128 proxy_pass http://127.0.0.1:8085;
129 }
130 }
131 }
132
133 EOF
134
135
136 $t->run_daemon(\&http_daemon, port(8081), port(8082), port(8085));
137 $t->try_run('no upstream max_conns')->plan(14);
138
139 $t->waitforsocket('127.0.0.1:' . port(8081));
140 $t->waitforsocket('127.0.0.1:' . port(8082));
141 $t->waitforsocket('127.0.0.1:' . port(8085));
142
143 ###############################################################################
144
145 my @ports = my ($p1, $p2) = (port(8081), port(8082));
146
147 # two peers without max_conns
148
149 is(parallel('/u_unlim?delay=0', 4), "$p1: 2, $p2: 2", 'unlimited');
150
151 # simple test with limited peer
152
153 is(parallel('/u_lim', 4), "$p1: 3", 'single');
154
155 # reopen connection to test connection subtraction
156
157 my @s = http_get_multi('/u_lim', 1, 1.1);
158 http_get('/u_lim/close');
159 push @s, http_get_multi('/u_lim', 1, 1.1);
160 http_get('/closeall');
161
162 is(http_end_multi(\@s), "$p1: 2", 'conn subtraction');
163
164 # limited peer with backup peer
165
166 is(peers('/u_backup', 6), "$p1 $p1 $p2 $p2 $p2 $p2", 'backup');
167
168 # peer and backup peer, both limited
169
170 is(peers('/u_backup_lim', 6), "$p1 $p1 $p2 $p2 $p2 ", 'backup limited');
171
172 # all peers limited
173
174 is(parallel('/u_two', 4), "$p1: 1, $p2: 1", 'all peers');
175
176 # subset of peers limited
177
178 is(parallel('/u_some', 4), "$p1: 1, $p2: 3", 'some peers');
179
180 # ensure that peer "weight" does not affect its max_conns limit
181
182 is(parallel('/u_weight', 4), "$p1: 1, $p2: 3", 'weight');
183
184 # peers with equal server value aggregate max_conns limit
185
186 is(parallel('/u_many', 6), "$p1: 2, $p2: 4", 'equal peer');
187
188 # connections to peer selected with proxy_next_upstream are counted
189
190 is(parallel('/u_pnu', 4), "$p1: 1, $p2: 2", 'proxy_next_upstream');
191
192 # least_conn balancer tests
193
194 is(parallel('/u_lc', 4), "$p1: 1, $p2: 3", 'least_conn');
195 is(peers('/u_lc_backup', 6), "$p1 $p1 $p2 $p2 $p2 $p2", 'least_conn backup');
196 is(peers('/u_lc_backup_lim', 6), "$p1 $p1 $p2 $p2 $p2 ",
197 'least_conn backup limited');
198
199 # ip_hash balancer tests
200
201 is(parallel('/u_ih', 4), "$p1: 1", 'ip_hash');
202
203 ###############################################################################
204
205 sub peers {
206 my ($uri, $count) = @_;
207
208 my @sockets = http_get_multi($uri, $count, 1.1);
209 http_get('/closeall');
210
211 join ' ', map { /X-Port: (\d+)/ && $1 }
212 map { http_end $_ } (@sockets);
213 }
214
215 sub parallel {
216 my ($uri, $count) = @_;
217
218 my @sockets = http_get_multi($uri, $count);
219 for (1 .. 20) {
220 last if IO::Select->new(@sockets)->can_read(3) == $count;
221 select undef, undef, undef, 0.01;
222 }
223 http_get('/closeall');
224 return http_end_multi(\@sockets);
225 }
226
227 sub http_get_multi {
228 my ($uri, $count, $wait) = @_;
229 my @sockets;
230
231 for (0 .. $count - 1) {
232 $sockets[$_] = http_get($uri, start => 1);
233 IO::Select->new($sockets[$_])->can_read($wait) if $wait;
234 }
235
236 return @sockets;
237 }
238
239 sub http_end_multi {
240 my ($sockets) = @_;
241 my %ports;
242
243 for my $sock (@$sockets) {
244 if (http_end($sock) =~ /X-Port: (\d+)/) {
245 $ports{$1} = 0 unless defined $ports{$1};
246 $ports{$1}++;
247 }
248 close $sock;
249 }
250
251 my @keys = map { my $p = $_; grep { $p == $_ } keys %ports } @ports;
252 return join ', ', map { $_ . ": " . $ports{$_} } @keys;
253 }
254
255 ###############################################################################
256
257 sub http_daemon {
258 my (@ports) = @_;
259 my (@socks, @clients);
260
261 for my $port (@ports) {
262 my $server = IO::Socket::INET->new(
263 Proto => 'tcp',
264 LocalHost => "127.0.0.1:$port",
265 Listen => 42,
266 Reuse => 1
267 )
268 or die "Can't create listening socket: $!\n";
269 push @socks, $server;
270 }
271
272 my $sel = IO::Select->new(@socks);
273 my $skip = 4;
274 my $count = 0;
275
276 local $SIG{PIPE} = 'IGNORE';
277
278 OUTER:
279 while (my @ready = $sel->can_read) {
280 foreach my $fh (@ready) {
281 if (grep $_ == $fh, @socks) {
282 my $new = $fh->accept;
283 $new->autoflush(1);
284 $sel->add($new);
285 $count++;
286
287 } else {
288 my @busy = grep { $_->sockport() } @ready;
289
290 # finish other handles
291 if ($fh->sockport() == port(8085) && @busy > 1
292 && grep $_->sockport() != port(8085),
293 @busy)
294 {
295 next;
296 }
297
298 # late events in other handles
299 if ($fh->sockport() == port(8085) && @busy == 1
300 && $count > 1 && $skip-- > 0)
301 {
302 select undef, undef, undef, 0.1;
303 next OUTER;
304 }
305
306 my $rv = process_socket($fh, \@clients);
307 if ($rv == 1) {
308 $sel->remove($fh);
309 $fh->close;
310 }
311 if ($rv == 2) {
312 for (@clients) {
313 $sel->remove($_);
314 $_->close;
315 }
316 $sel->remove($fh);
317 $fh->close;
318 $skip = 4;
319 }
320 $count--;
321 }
322 }
323 }
324 }
325
326 # Returns true to close connection
327
328 sub process_socket {
329 my ($client, $saved) = @_;
330 my $port = $client->sockport();
331
332 my $headers = '';
333 my $uri = '';
334
335 while (<$client>) {
336 $headers .= $_;
337 last if (/^\x0d?\x0a?$/);
338 }
339 return 1 if $headers eq '';
340
341 $uri = $1 if $headers =~ /^\S+\s+([^ ]+)\s+HTTP/i;
342 return 1 if $uri eq '';
343
344 Test::Nginx::log_core('||', "$port: response, 200");
345 print $client <<EOF;
346 HTTP/1.1 200 OK
347 X-Port: $port
348
349 OK
350 EOF
351
352 return 2 if $uri =~ /closeall/;
353 return 1 if $uri =~ /close/;
354
355 push @$saved, $client;
356 return 0;
357 }
358
359 ###############################################################################