Mercurial > hg > nginx-quic
annotate src/mysql/ngx_http_mysql_test.c @ 4207:4fc91bae6f83
Better recheck of dead upstream servers.
Previously nginx used to mark backend again as live as soon as fail_timeout
passes (10s by default) since last failure. On the other hand, detecting
dead backend takes up to 60s (proxy_connect_timeout) in typical situation
"backend is down and doesn't respond to any packets". This resulted in
suboptimal behaviour in the above situation (up to 23% of requests were
directed to dead backend with default settings).
More detailed description of the problem may be found here (in Russian):
http://mailman.nginx.org/pipermail/nginx-ru/2011-August/042172.html
Fix is to only allow one request after fail_timeout passes, and
mark backend as "live" only if this request succeeds.
Note that with new code backend will not be marked "live" unless "check"
request is completed, and this may take a while in some specific workloads
(e.g. streaming). This is believed to be acceptable.
author | Maxim Dounin <mdounin@mdounin.ru> |
---|---|
date | Wed, 12 Oct 2011 14:22:48 +0000 |
parents | f0d596e84634 |
children | d620f497c50f |
rev | line source |
---|---|
653 | 1 |
2 /* | |
3 * Copyright (C) Igor Sysoev | |
4 */ | |
5 | |
6 #include <ngx_config.h> | |
7 #include <ngx_core.h> | |
8 #include <ngx_mysql.h> | |
9 #include <ngx_http.h> | |
10 | |
11 | |
12 typedef struct { | |
3269
f0d596e84634
rename ngx_peer_addr_t to ngx_addr_t
Igor Sysoev <igor@sysoev.ru>
parents:
2049
diff
changeset
|
13 ngx_addr_t *peers; |
f0d596e84634
rename ngx_peer_addr_t to ngx_addr_t
Igor Sysoev <igor@sysoev.ru>
parents:
2049
diff
changeset
|
14 ngx_uint_t npeers; |
653 | 15 } ngx_http_mysql_test_conf_t; |
16 | |
17 | |
18 static void ngx_http_mysql_auth(ngx_mysql_t *m); | |
19 static void ngx_http_mysql_done(ngx_mysql_t *m); | |
20 static void *ngx_http_mysql_test_create_loc_conf(ngx_conf_t *cf); | |
21 static char *ngx_http_mysql_test(ngx_conf_t *cf, ngx_command_t *cmd, | |
22 void *conf); | |
23 | |
24 static ngx_command_t ngx_http_mysql_test_commands[] = { | |
25 | |
26 { ngx_string("mysql_test"), | |
27 NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, | |
28 ngx_http_mysql_test, | |
29 NGX_HTTP_LOC_CONF_OFFSET, | |
30 0, | |
31 NULL }, | |
32 | |
33 ngx_null_command | |
34 }; | |
35 | |
36 | |
667 | 37 static ngx_http_module_t ngx_http_mysql_test_module_ctx = { |
653 | 38 NULL, /* preconfiguration */ |
39 NULL, /* postconfiguration */ | |
40 | |
41 NULL, /* create main configuration */ | |
42 NULL, /* init main configuration */ | |
43 | |
44 NULL, /* create server configuration */ | |
45 NULL, /* merge server configuration */ | |
46 | |
47 ngx_http_mysql_test_create_loc_conf, /* create location configuration */ | |
48 NULL /* merge location configuration */ | |
49 }; | |
50 | |
51 | |
52 ngx_module_t ngx_http_mysql_test_module = { | |
53 NGX_MODULE_V1, | |
54 &ngx_http_mysql_test_module_ctx, /* module context */ | |
55 ngx_http_mysql_test_commands, /* module directives */ | |
56 NGX_HTTP_MODULE, /* module type */ | |
57 NULL, /* init master */ | |
58 NULL, /* init module */ | |
59 NULL, /* init process */ | |
60 NULL, /* init thread */ | |
61 NULL, /* exit thread */ | |
62 NULL, /* exit process */ | |
63 NULL, /* exit master */ | |
64 NGX_MODULE_V1_PADDING | |
65 }; | |
66 | |
67 | |
68 static ngx_str_t ngx_mysql_login = ngx_string("root"); | |
69 static ngx_str_t ngx_mysql_passwd = ngx_string("tp"); | |
70 static ngx_str_t ngx_mysql_database = ngx_string("mysql"); | |
71 static ngx_str_t ngx_mysql_command_query = | |
72 ngx_string("select * from user"); | |
73 | |
74 | |
75 static ngx_int_t | |
76 ngx_http_mysql_test_handler(ngx_http_request_t *r) | |
77 { | |
78 ngx_int_t rc; | |
79 ngx_mysql_t *m; | |
80 ngx_http_mysql_test_conf_t *mtcf; | |
81 | |
82 mtcf = ngx_http_get_module_loc_conf(r, ngx_http_mysql_test_module); | |
83 | |
84 m = ngx_pcalloc(r->pool, sizeof(ngx_mysql_t)); | |
85 | |
86 if (m == NULL) { | |
87 return NGX_HTTP_INTERNAL_SERVER_ERROR; | |
88 } | |
89 | |
90 m->pool = r->pool; | |
91 m->handler = ngx_http_mysql_auth; | |
92 m->data = r; | |
93 | |
94 m->login = &ngx_mysql_login; | |
95 m->passwd = &ngx_mysql_passwd; | |
96 m->database = &ngx_mysql_database; | |
97 | |
884 | 98 /* STUB */ |
99 m->peer.sockaddr = mtcf->peers[0].sockaddr; | |
100 m->peer.socklen = mtcf->peers[0].socklen; | |
101 m->peer.name = &mtcf->peers[0].name; | |
102 m->peer.tries = mtcf->npeers; | |
103 m->peer.get = ngx_event_get_peer; | |
104 /**/ | |
653 | 105 m->peer.log = r->connection->log; |
106 m->peer.log_error = NGX_ERROR_ERR; | |
107 | |
108 rc = ngx_mysql_connect(m); | |
109 | |
110 if (rc == NGX_OK || rc == NGX_AGAIN) { | |
111 return NGX_DONE; | |
112 } | |
113 | |
114 return NGX_HTTP_INTERNAL_SERVER_ERROR; | |
115 } | |
116 | |
117 | |
118 static void | |
119 ngx_http_mysql_auth(ngx_mysql_t *m) | |
120 { | |
121 ngx_http_request_t *r; | |
122 | |
123 r = m->data; | |
124 | |
125 if (m->state != NGX_OK) { | |
126 ngx_http_finalize_request(r, NGX_HTTP_NO_CONTENT); | |
127 return; | |
128 } | |
129 | |
130 m->query.len = NGX_MYSQL_CMDPKT_LEN + ngx_mysql_command_query.len; | |
131 | |
2049 | 132 m->query.data = ngx_pnalloc(r->pool, m->query.len); |
653 | 133 if (m->query.data == NULL) { |
134 ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); | |
135 return; | |
136 } | |
137 | |
138 ngx_memcpy(m->query.data + NGX_MYSQL_CMDPKT_LEN, | |
139 ngx_mysql_command_query.data, ngx_mysql_command_query.len); | |
140 | |
141 m->handler = ngx_http_mysql_done; | |
142 | |
143 ngx_mysql_query(m); | |
144 } | |
145 | |
146 | |
147 static void | |
148 ngx_http_mysql_done(ngx_mysql_t *m) | |
149 { | |
150 ngx_http_request_t *r; | |
151 | |
152 r = m->data; | |
153 | |
154 ngx_http_finalize_request(r, NGX_HTTP_NO_CONTENT); | |
155 } | |
156 | |
157 | |
158 static void * | |
159 ngx_http_mysql_test_create_loc_conf(ngx_conf_t *cf) | |
160 { | |
161 ngx_http_mysql_test_conf_t *conf; | |
162 | |
163 conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_mysql_test_conf_t)); | |
164 if (conf == NULL) { | |
165 return NGX_CONF_ERROR; | |
166 } | |
167 | |
168 return conf; | |
169 } | |
170 | |
171 static char * | |
172 ngx_http_mysql_test(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) | |
173 { | |
174 ngx_http_mysql_test_conf_t *mtcf = conf; | |
175 | |
176 ngx_str_t *value; | |
177 ngx_url_t u; | |
178 ngx_http_core_loc_conf_t *clcf; | |
179 | |
180 clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); | |
181 clcf->handler = ngx_http_mysql_test_handler; | |
182 | |
183 value = cf->args->elts; | |
184 | |
185 ngx_memzero(&u, sizeof(ngx_url_t)); | |
186 | |
187 u.url = value[1]; | |
906 | 188 u.default_port = 3306; |
653 | 189 |
1559
fe11e2a3946d
use pool instead of ngx_conf_t
Igor Sysoev <igor@sysoev.ru>
parents:
906
diff
changeset
|
190 if (ngx_parse_url(cf->pool, &u) != NGX_OK) { |
653 | 191 if (u.err) { |
192 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
193 "%s in upstream \"%V\"", u.err, &u.url); | |
194 } | |
195 | |
196 return NGX_CONF_ERROR; | |
197 } | |
198 | |
884 | 199 mtcf->peers = u.addrs; |
200 mtcf->npeers = u.naddrs; | |
653 | 201 |
202 return NGX_CONF_OK; | |
203 } |