Apache HTTPD
mod_lbmethod_heartbeat.c
Go to the documentation of this file.
1/* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "mod_proxy.h"
18#include "scoreboard.h"
19#include "ap_mpm.h"
20#include "apr_version.h"
21#include "ap_hooks.h"
22#include "ap_slotmem.h"
23#include "heartbeat.h"
24
25#ifndef LBM_HEARTBEAT_MAX_LASTSEEN
26/* If we haven't seen a heartbeat in the last N seconds, don't count this IP
27 * as allive.
28 */
29#define LBM_HEARTBEAT_MAX_LASTSEEN (10)
30#endif
31
32module AP_MODULE_DECLARE_DATA lbmethod_heartbeat_module;
33
35 proxy_worker *worker, server_rec *s) = NULL;
36
39
40/*
41 * configuration structure
42 * path: path of the file where the heartbeat information is stored.
43 */
44typedef struct lb_hb_ctx_t
45{
46 const char *path;
48
49typedef struct hb_server_t {
50 const char *ip;
51 int busy;
52 int ready;
53 int port;
54 int id;
58
63
64static void
66{
67 char *key;
68 char *value;
69 char *strtok_state;
70
72 while (key) {
73 value = strchr(key, '=');
74 if (value) {
75 *value = '\0'; /* Split the string in two */
76 value++; /* Skip passed the = */
77 }
78 else {
79 value = "1";
80 }
84 /*
85 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(03230)
86 "Found query arg: %s = %s", key, value);
87 */
89 }
90}
91
92static apr_status_t readfile_heartbeats(const char *path, apr_hash_t *servers,
94{
96 apr_status_t rv;
97 apr_file_t *fp;
98
99 if (!path) {
100 return APR_SUCCESS;
101 }
102
105
106 if (rv) {
107 return rv;
108 }
109
111
112 if (rv) {
113 return rv;
114 }
115
116 {
117 char *t;
122
123 apr_brigade_insert_file(bb, fp, 0, fi.size, pool);
124
125 do {
127 char buf[4096];
128 apr_size_t bsize = sizeof(buf);
129 const char *ip, *val;
130
131 apr_brigade_cleanup(tmpbb);
132
133 if (APR_BRIGADE_EMPTY(bb)) {
134 break;
135 }
136
137 rv = apr_brigade_split_line(tmpbb, bb,
138 APR_BLOCK_READ, sizeof(buf));
139
140 if (rv) {
141 return rv;
142 }
143
144 apr_brigade_flatten(tmpbb, buf, &bsize);
145
146 if (bsize == 0) {
147 break;
148 }
149
150 buf[bsize - 1] = 0;
151
152 /* comment */
153 if (buf[0] == '#') {
154 continue;
155 }
156
157 /* line format: <IP> <query_string>\n */
158 t = strchr(buf, ' ');
159 if (!t) {
160 continue;
161 }
162
163 ip = apr_pstrmemdup(pool, buf, t - buf);
164 t++;
165
167
168 if (server == NULL) {
170 server->ip = ip;
171 server->port = 80;
172 server->seen = -1;
173
175 }
176
178
180
181 if ((val = apr_table_get(hbt, "busy"))) {
182 server->busy = atoi(val);
183 }
184
185 if ((val = apr_table_get(hbt, "ready"))) {
186 server->ready = atoi(val);
187 }
188
189 if ((val = apr_table_get(hbt, "lastseen"))) {
190 server->seen = atoi(val);
191 }
192
193 if ((val = apr_table_get(hbt, "port"))) {
194 server->port = atoi(val);
195 }
196
197 if (server->busy == 0 && server->ready != 0) {
198 /* Server has zero threads active, but lots of them ready,
199 * it likely just started up, so lets /4 the number ready,
200 * to prevent us from completely flooding it with all new
201 * requests.
202 */
203 server->ready = server->ready / 4;
204 }
205
206 } while (1);
207 }
208
209 return APR_SUCCESS;
210}
211
213{
216 apr_hash_t *servers = (apr_hash_t *) ctx->servers;
218 if (server == NULL) {
220 server->ip = apr_pstrdup(pool, slotserver->ip);
221 server->seen = -1;
222
224
225 }
226 server->busy = slotserver->busy;
227 server->ready = slotserver->ready;
228 server->seen = apr_time_sec(ctx->now - slotserver->seen);
229 server->id = slotserver->id;
230 if (server->busy == 0 && server->ready != 0) {
231 server->ready = server->ready / 4;
232 }
233 return APR_SUCCESS;
234}
241
242
243static apr_status_t read_heartbeats(const char *path, apr_hash_t *servers,
245{
246 apr_status_t rv;
247 if (hm_serversmem) {
249 ctx.now = apr_time_now();
250 ctx.servers = servers;
252 } else
253 rv = readfile_heartbeats(path, servers, pool);
254 return rv;
255}
256
258 request_rec *r)
259{
260 apr_status_t rv;
261 int i;
263 proxy_worker **worker;
267 apr_pool_t *tpool;
268 apr_hash_t *servers;
269
272 &lbmethod_heartbeat_module);
273
277 /* can only happen if mod_proxy isn't loaded */
278 return NULL;
279 }
280
281 apr_pool_create(&tpool, r->pool);
282 apr_pool_tag(tpool, "lb_heartbeat_tpool");
283
284 servers = apr_hash_make(tpool);
285
286 rv = read_heartbeats(ctx->path, servers, tpool);
287
288 if (rv) {
290 "lb_heartbeat: Unable to read heartbeats at '%s'",
291 ctx->path);
292 apr_pool_destroy(tpool);
293 return NULL;
294 }
295
296 up_servers = apr_array_make(tpool, apr_hash_count(servers), sizeof(hb_server_t *));
297
298 for (i = 0; i < balancer->workers->nelts; i++) {
299 worker = &APR_ARRAY_IDX(balancer->workers, i, proxy_worker *);
300 server = apr_hash_get(servers, (*worker)->s->hostname_ex, APR_HASH_KEY_STRING);
301
302 if (!server) {
304 "lb_heartbeat: No server for worker %s", (*worker)->s->name_ex);
305 continue;
306 }
307
308 if (!PROXY_WORKER_IS_USABLE(*worker)) {
309 ap_proxy_retry_worker_fn("BALANCER", *worker, r->server);
310 }
311
312 if (PROXY_WORKER_IS_USABLE(*worker)) {
313 server->worker = *worker;
315 openslots += server->ready;
317 }
318 }
319 }
320
321 if (openslots > 0) {
322 apr_uint32_t c = 0;
323 apr_uint32_t pick = 0;
324
326
327 for (i = 0; i < up_servers->nelts; i++) {
329 if (pick >= c && pick <= c + server->ready) {
330 mycandidate = server->worker;
331 }
332
333 c += server->ready;
334 }
335 }
336
337 apr_pool_destroy(tpool);
338
339 return mycandidate;
340}
341
343{
344 return APR_SUCCESS;
345}
346
348{
349 return APR_SUCCESS;
350}
351
353{
354 "heartbeat",
356 NULL,
357 &reset,
358 &age,
359 NULL
360};
361
363 apr_pool_t *ptemp, server_rec *s)
364{
366 unsigned int num;
367 lb_hb_ctx_t *ctx = ap_get_module_config(s->module_config,
368 &lbmethod_heartbeat_module);
369
370 /* do nothing on first call */
372 return OK;
373
376 if (!storage) {
378 "Failed to lookup provider 'shm' for '%s'. Maybe you "
379 "need to load mod_slotmem_shm?",
381 return OK;
382 }
383
384 /* Try to use a slotmem created by mod_heartmonitor */
385 storage->attach(&hm_serversmem, "mod_heartmonitor", &size, &num, p);
386 if (!hm_serversmem)
388 "No slotmem from mod_heartmonitor");
389 else
391 "Using slotmem from mod_heartmonitor");
392
393 if (hm_serversmem)
394 ctx->path = "(slotmem)";
395
396 return OK;
397}
398
400{
401 static const char * const aszPred[]={ "mod_heartmonitor.c", NULL };
402 ap_register_provider(p, PROXY_LBMETHOD, "heartbeat", "0", &heartbeat);
404}
405
414
415static void *lb_hb_merge_config(apr_pool_t *p, void *basev, void *overridesv)
416{
420
421 if (overrides->path) {
422 ps->path = apr_pstrdup(p, overrides->path);
423 }
424 else {
425 ps->path = apr_pstrdup(p, base->path);
426 }
427
428 return ps;
429}
430
431static const char *cmd_lb_hb_storage(cmd_parms *cmd,
432 void *dconf, const char *path)
433{
434 apr_pool_t *p = cmd->pool;
436 (lb_hb_ctx_t *) ap_get_module_config(cmd->server->module_config,
437 &lbmethod_heartbeat_module);
438
439 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
440
441 if (err != NULL) {
442 return err;
443 }
444
446
447 return NULL;
448}
449
450static const command_rec cmds[] = {
451 AP_INIT_TAKE1("HeartbeatStorage", cmd_lb_hb_storage, NULL, RSRC_CONF,
452 "Path to read heartbeat data."),
453 {NULL}
454};
455
458 NULL, /* create per-directory config structure */
459 NULL, /* merge per-directory config structures */
460 lb_hb_create_config, /* create per-server config structure */
461 lb_hb_merge_config, /* merge per-server config structures */
462 cmds, /* command apr_table_t */
463 register_hooks /* register hooks */
464};
ap hook functions and macros
Apache Multi-Processing Module library.
Memory Slot Extension Storage Module for Apache.
APR Versioning Interface.
#define AP_INIT_TAKE1(directive, func, mconfig, where, help)
char * ap_runtime_dir_relative(apr_pool_t *p, const char *fname)
Definition config.c:1610
#define ap_get_module_config(v, m)
void ap_hook_post_config(ap_HOOK_post_config_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder)
Definition config.c:105
#define AP_DECLARE_MODULE(foo)
ap_conf_vector_t * base
request_rec int int apr_table_t const char * path
const char server_rec server_rec ** ps
request_rec * r
#define OK
Definition httpd.h:456
#define AP_SQ_MS_CREATE_PRE_CONFIG
Definition http_core.h:1047
int ap_state_query(int query_code)
Definition core.c:5378
#define AP_SQ_MAIN_STATE
Definition http_core.h:1030
#define APLOGNO(n)
Definition http_log.h:117
#define APLOG_NOTICE
Definition http_log.h:69
#define ap_log_rerror
Definition http_log.h:454
#define APLOG_ERR
Definition http_log.h:67
#define ap_log_error
Definition http_log.h:370
#define APLOG_MARK
Definition http_log.h:283
#define APLOG_DEBUG
Definition http_log.h:71
const unsigned char * buf
Definition util_md5.h:50
apr_status_t ap_register_provider(apr_pool_t *pool, const char *provider_group, const char *provider_name, const char *provider_version, const void *provider)
Definition provider.c:35
void * ap_lookup_provider(const char *provider_group, const char *provider_name, const char *provider_version)
Definition provider.c:99
#define APR_BRIGADE_EMPTY(b)
apr_brigade_flush void * ctx
@ APR_BLOCK_READ
Definition apr_buckets.h:58
#define APR_HOOK_MIDDLE
Definition apr_hooks.h:303
apr_memcache_server_t * server
#define APR_RETRIEVE_OPTIONAL_FN(name)
#define RSRC_CONF
#define DEFAULT_HEARTBEAT_STORAGE
Definition heartbeat.h:53
#define AP_SLOTMEM_PROVIDER_GROUP
Definition ap_slotmem.h:52
#define AP_SLOTMEM_PROVIDER_VERSION
Definition ap_slotmem.h:53
#define PROXY_WORKER_IS_USABLE(f)
Definition mod_proxy.h:358
#define PROXY_LBMETHOD
Definition mod_proxy.h:1444
#define STANDARD20_MODULE_STUFF
int ap_unescape_url(char *url)
Definition util.c:1939
apr_uint32_t ap_random_pick(apr_uint32_t min, apr_uint32_t max)
Definition core.c:5485
#define GLOBAL_ONLY
const char * ap_check_cmd_context(cmd_parms *cmd, unsigned forbidden)
Definition core.c:1301
apr_size_t size
apr_uint32_t val
Definition apr_atomic.h:66
const char int apr_pool_t * pool
Definition apr_cstr.h:84
const char * value
Definition apr_env.h:51
#define APR_SUCCESS
Definition apr_errno.h:225
int apr_status_t
Definition apr_errno.h:44
const char * key
void * data
#define APR_READ
Definition apr_file_io.h:93
#define APR_BINARY
Definition apr_file_io.h:98
#define APR_BUFFERED
#define APR_OS_DEFAULT
#define APR_FINFO_SIZE
#define APR_HASH_KEY_STRING
Definition apr_hash.h:47
apr_vformatter_buff_t * c
Definition apr_lib.h:175
apr_interval_time_t t
apr_interval_time_t apr_int32_t * num
Definition apr_poll.h:273
#define apr_pool_create(newpool, parent)
Definition apr_pools.h:322
#define apr_pcalloc(p, size)
Definition apr_pools.h:465
void * mem
const char * s
Definition apr_strings.h:95
#define APR_ARRAY_PUSH(ary, type)
Definition apr_tables.h:150
#define APR_ARRAY_IDX(ary, i, type)
Definition apr_tables.h:141
apr_int32_t apr_int32_t apr_int32_t err
apr_cmdtype_e cmd
apr_int64_t apr_time_t
Definition apr_time.h:45
#define apr_time_sec(time)
Definition apr_time.h:63
commun structures for mod_heartmonitor.c and mod_lbmethod_heartbeat.c
apr_pool_t * p
Definition md_event.c:32
static int lb_hb_init(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s)
static apr_status_t age(proxy_balancer *balancer, server_rec *s)
static apr_status_t readslot_heartbeats(ctx_servers_t *ctx, apr_pool_t *pool)
static void argstr_to_table(apr_pool_t *p, char *str, apr_table_t *parms)
static proxy_worker * find_best_hb(proxy_balancer *balancer, request_rec *r)
static apr_status_t readfile_heartbeats(const char *path, apr_hash_t *servers, apr_pool_t *pool)
static const ap_slotmem_provider_t * storage
struct ctx_servers ctx_servers_t
static const char * cmd_lb_hb_storage(cmd_parms *cmd, void *dconf, const char *path)
static const proxy_balancer_method heartbeat
static void register_hooks(apr_pool_t *p)
static void * lb_hb_create_config(apr_pool_t *p, server_rec *s)
static apr_status_t reset(proxy_balancer *balancer, server_rec *s)
static ap_slotmem_instance_t * hm_serversmem
static apr_status_t read_heartbeats(const char *path, apr_hash_t *servers, apr_pool_t *pool)
static const command_rec cmds[]
#define LBM_HEARTBEAT_MAX_LASTSEEN
static apr_status_t hm_read(void *mem, void *data, apr_pool_t *pool)
static void * lb_hb_merge_config(apr_pool_t *p, void *basev, void *overridesv)
static int(* ap_proxy_retry_worker_fn)(const char *proxy_function, proxy_worker *worker, server_rec *s)
Proxy Extension Module for Apache.
return NULL
Definition mod_so.c:359
int i
Definition mod_so.c:347
static int ap_proxy_retry_worker(const char *proxy_function, proxy_worker *worker, server_rec *s)
Apache scoreboard library.
apr_status_t(* doall)(ap_slotmem_instance_t *s, ap_slotmem_callback_fn_t *func, void *data, apr_pool_t *pool)
Definition ap_slotmem.h:99
apr_status_t(* attach)(ap_slotmem_instance_t **inst, const char *name, apr_size_t *item_size, unsigned int *item_num, apr_pool_t *pool)
Definition ap_slotmem.h:122
proxy_worker * worker
apr_array_header_t * workers
Definition mod_proxy.h:559
A structure that represents the current request.
Definition httpd.h:845
apr_pool_t * pool
Definition httpd.h:847
server_rec * server
Definition httpd.h:851
A structure to store information for each virtual server.
Definition httpd.h:1322
const char * path
Definition httpd.h:1386
struct ap_conf_vector_t * module_config
Definition httpd.h:1341
#define str
typedef int(WSAAPI *apr_winapi_fpt_WSAPoll)(IN OUT LPWSAPOLLFD fdArray