From: Willy Tarreau Date: Thu, 5 Mar 2009 17:43:00 +0000 (+0100) Subject: [MEDIUM] measure and report session rate on frontend, backends and servers X-Git-Tag: v1.3.16-rc1~29 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=7f062c41933143d7cd55be492a5af3f1c7c93c8e;p=thirdparty%2Fhaproxy.git [MEDIUM] measure and report session rate on frontend, backends and servers With this change, all frontends, backends, and servers maintain a session counter and a timer to compute a session rate over the last second. This value will be very useful because it varies instantly and can be used to check thresholds. This value is also reported in the stats in a new "rate" column. --- diff --git a/Makefile b/Makefile index 855c902982..3d87d70e1a 100644 --- a/Makefile +++ b/Makefile @@ -460,7 +460,7 @@ OBJS = src/haproxy.o src/sessionhash.o src/base64.o src/protocols.o \ src/proto_http.o src/stream_sock.o src/appsession.o src/backend.o \ src/stream_interface.o src/dumpstats.o src/proto_tcp.o \ src/session.o src/hdr_idx.o src/ev_select.o \ - src/acl.o src/memory.o \ + src/acl.o src/memory.o src/freq_ctr.o \ src/ebtree.o src/eb32tree.o haproxy: $(OBJS) $(OPTIONS_OBJS) diff --git a/Makefile.bsd b/Makefile.bsd index 22dc3e778f..d1f3e68767 100644 --- a/Makefile.bsd +++ b/Makefile.bsd @@ -106,7 +106,7 @@ OBJS = src/haproxy.o src/sessionhash.o src/base64.o src/protocols.o \ src/stream_interface.o src/dumpstats.o src/proto_tcp.o \ src/session.o src/hdr_idx.o src/ev_select.o \ src/ev_poll.o src/ev_kqueue.o \ - src/acl.o src/memory.o \ + src/acl.o src/memory.o src/freq_ctr.o \ src/ebtree.o src/eb32tree.o all: haproxy diff --git a/Makefile.osx b/Makefile.osx index cb4d4c8863..b736eef168 100644 --- a/Makefile.osx +++ b/Makefile.osx @@ -103,7 +103,7 @@ OBJS = src/haproxy.o src/sessionhash.o src/base64.o src/protocols.o \ src/stream_interface.o src/dumpstats.o src/proto_tcp.o \ src/session.o src/hdr_idx.o src/ev_select.o \ src/ev_poll.o \ - src/acl.o src/memory.o \ + src/acl.o src/memory.o src/freq_ctr.o \ src/ebtree.o src/eb32tree.o all: haproxy diff --git a/doc/configuration.txt b/doc/configuration.txt index 0590b61f5b..84465e82bb 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -5778,6 +5778,9 @@ reading. Their sole purpose is to explain how to decipher them. 2.7) CSV format --------------- +The statistics may be consulted either from the unix socket or from the HTTP +page. Both means provide a CSV format whose fields follow. + 0. pxname: proxy name 1. svname: service name (FRONTEND for frontend, BACKEND for backend, any name for server) @@ -5812,6 +5815,7 @@ reading. Their sole purpose is to explain how to decipher them. 30. lbtot: total number of times a server was selected 31. tracked: id of proxy/server if tracking is enabled 32. type (0=frontend, 1=backend, 2=server) + 33. rate (number of sessions per second over last elapsed second) 2.8) Unix Socket commands diff --git a/include/common/standard.h b/include/common/standard.h index 892f516e52..84f768cbbe 100644 --- a/include/common/standard.h +++ b/include/common/standard.h @@ -280,4 +280,13 @@ extern const char *parse_time_err(const char *text, unsigned *ret, unsigned unit #define TIME_UNIT_DAY 0x0005 #define TIME_UNIT_MASK 0x0007 +/* Multiply the two 32-bit operands and shift the 64-bit result right 32 bits. + * This is used to compute fixed ratios by setting one of the operands to + * (2^32*ratio). + */ +static inline unsigned int mul32hi(unsigned int a, unsigned int b) +{ + return ((unsigned long long)a * b) >> 32; +} + #endif /* _COMMON_STANDARD_H */ diff --git a/include/proto/freq_ctr.h b/include/proto/freq_ctr.h new file mode 100644 index 0000000000..caa2b6bc44 --- /dev/null +++ b/include/proto/freq_ctr.h @@ -0,0 +1,70 @@ +/* + include/proto/freq_ctr.h + This file contains macros and inline functions for frequency counters. + + Copyright (C) 2000-2009 Willy Tarreau - w@1wt.eu + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation, version 2.1 + exclusively. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _PROTO_FREQ_CTR_H +#define _PROTO_FREQ_CTR_H + +#include +#include + +/* Rotate a frequency counter when current period is over. Must not be called + * during a valid period. It is important that it correctly initializes a null + * area. + */ +static inline void rotate_freq_ctr(struct freq_ctr *ctr) +{ + ctr->prev_ctr = ctr->curr_ctr; + if (likely(now.tv_sec - ctr->curr_sec != 1)) { + /* we missed more than one second */ + ctr->prev_ctr = 0; + } + ctr->curr_sec = now.tv_sec; + ctr->curr_ctr = 0; /* leave it at the end to help gcc optimize it away */ +} + +/* Update a frequency counter by incremental units. It is automatically + * rotated if the period is over. It is important that it correctly initializes + * a null area. + */ +static inline void update_freq_ctr(struct freq_ctr *ctr, unsigned int inc) +{ + if (likely(ctr->curr_sec == now.tv_sec)) { + ctr->curr_ctr += inc; + return; + } + rotate_freq_ctr(ctr); + ctr->curr_ctr = inc; + /* Note: later we may want to propagate the update to other counters */ +} + +/* Read a frequency counter taking history into account for missing time in + * current period. + */ +unsigned int read_freq_ctr(struct freq_ctr *ctr); + +#endif /* _PROTO_FREQ_CTR_H */ + +/* + * Local variables: + * c-indent-level: 8 + * c-basic-offset: 8 + * End: + */ diff --git a/include/proto/proxy.h b/include/proto/proxy.h index 30a12472e8..012c1b27fe 100644 --- a/include/proto/proxy.h +++ b/include/proto/proxy.h @@ -26,6 +26,7 @@ #include #include #include +#include int start_proxies(int verbose); void maintain_proxies(int *next); @@ -62,6 +63,20 @@ static inline void proxy_reset_timeouts(struct proxy *proxy) proxy->timeout.check = TICK_ETERNITY; } +/* increase the number of cumulated connections on the designated frontend */ +static void inline proxy_inc_fe_ctr(struct proxy *fe) +{ + fe->cum_feconn++; + update_freq_ctr(&fe->fe_sess_per_sec, 1); +} + +/* increase the number of cumulated connections on the designated backend */ +static void inline proxy_inc_be_ctr(struct proxy *be) +{ + be->cum_beconn++; + update_freq_ctr(&be->be_sess_per_sec, 1); +} + #endif /* _PROTO_PROXY_H */ /* diff --git a/include/proto/server.h b/include/proto/server.h index f3b5e16b91..e05a4acec5 100644 --- a/include/proto/server.h +++ b/include/proto/server.h @@ -2,7 +2,7 @@ include/proto/server.h This file defines everything related to servers. - Copyright (C) 2000-2006 Willy Tarreau - w@1wt.eu + Copyright (C) 2000-2009 Willy Tarreau - w@1wt.eu This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -30,10 +30,18 @@ #include #include +#include int srv_downtime(struct server *s); int srv_getinter(struct server *s); +/* increase the number of cumulated connections on the designated server */ +static void inline srv_inc_sess_ctr(struct server *s) +{ + s->cum_sess++; + update_freq_ctr(&s->sess_per_sec, 1); +} + #endif /* _PROTO_SERVER_H */ /* diff --git a/include/types/freq_ctr.h b/include/types/freq_ctr.h new file mode 100644 index 0000000000..a8cfbd7d84 --- /dev/null +++ b/include/types/freq_ctr.h @@ -0,0 +1,40 @@ +/* + include/types/freq_ctr.h + This file contains structure declarations for frequency counters. + + Copyright (C) 2000-2009 Willy Tarreau - w@1wt.eu + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation, version 2.1 + exclusively. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _TYPES_FREQ_CTR_H +#define _TYPES_FREQ_CTR_H + +#include + +struct freq_ctr { + unsigned int curr_sec; /* start date of current period (seconds from now.tv_sec) */ + unsigned int curr_ctr; /* cumulated value for current period */ + unsigned int prev_ctr; /* value for last period */ +}; + +#endif /* _TYPES_FREQ_CTR_H */ + +/* + * Local variables: + * c-indent-level: 8 + * c-basic-offset: 8 + * End: + */ diff --git a/include/types/proxy.h b/include/types/proxy.h index 9adf5cde23..87b6f14f56 100644 --- a/include/types/proxy.h +++ b/include/types/proxy.h @@ -2,7 +2,7 @@ include/types/proxy.h This file defines everything related to proxies. - Copyright (C) 2000-2008 Willy Tarreau - w@1wt.eu + Copyright (C) 2000-2009 Willy Tarreau - w@1wt.eu This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -37,6 +37,7 @@ #include #include +#include #include #include #include @@ -220,6 +221,8 @@ struct proxy { int totpend; /* total number of pending connections on this instance (for stats) */ unsigned int feconn, feconn_max; /* # of active frontend sessions */ unsigned int beconn, beconn_max; /* # of active backend sessions */ + struct freq_ctr fe_sess_per_sec; /* sessions per second on the frontend */ + struct freq_ctr be_sess_per_sec; /* sessions per second on the backend */ unsigned int cum_feconn, cum_beconn; /* cumulated number of processed sessions */ unsigned int cum_lbconn; /* cumulated number of sessions processed by load balancing */ unsigned int maxconn; /* max # of active sessions on the frontend */ diff --git a/include/types/server.h b/include/types/server.h index 5c0186a884..8fb8a1f66b 100644 --- a/include/types/server.h +++ b/include/types/server.h @@ -2,7 +2,7 @@ include/types/server.h This file defines everything related to servers. - Copyright (C) 2000-2008 Willy Tarreau - w@1wt.eu + Copyright (C) 2000-2009 Willy Tarreau - w@1wt.eu This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -30,6 +30,7 @@ #include #include +#include #include #include #include @@ -122,6 +123,7 @@ struct server { unsigned failed_conns, failed_resp; /* failed connect() and responses */ unsigned retries, redispatches; /* retried and redispatched connections */ unsigned failed_secu; /* blocked responses because of security concerns */ + struct freq_ctr sess_per_sec; /* sessions per second on this server */ unsigned cum_sess; /* cumulated number of sessions really sent to this server */ unsigned cum_lbconn; /* cumulated number of sessions directed by load balancing */ diff --git a/src/backend.c b/src/backend.c index e1911c5e3b..ed291dacf7 100644 --- a/src/backend.c +++ b/src/backend.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -1912,7 +1913,7 @@ int srv_redispatch_connect(struct session *t) } if (t->srv) - t->srv->cum_sess++; + srv_inc_sess_ctr(t->srv); if (t->srv) t->srv->failed_conns++; t->be->failed_conns++; diff --git a/src/client.c b/src/client.c index 4cc3d7ea03..3e1ff58404 100644 --- a/src/client.c +++ b/src/client.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -236,7 +237,7 @@ int event_accept(int fd) { s->data_source = DATA_SRC_NONE; s->uniq_id = totalconn; - p->cum_feconn++; /* cum_beconn will be increased once assigned */ + proxy_inc_fe_ctr(p); /* note: cum_beconn will be increased once assigned */ txn = &s->txn; txn->flags = 0; @@ -444,7 +445,7 @@ int event_accept(int fd) { p->feconn_max = p->feconn; if (s->flags & SN_BE_ASSIGNED) { - s->be->cum_beconn++; + proxy_inc_be_ctr(s->be); s->be->beconn++; if (s->be->beconn > s->be->beconn_max) s->be->beconn_max = s->be->beconn; diff --git a/src/dumpstats.c b/src/dumpstats.c index dd047b76c2..97443a122f 100644 --- a/src/dumpstats.c +++ b/src/dumpstats.c @@ -41,6 +41,7 @@ #include #include #include +#include #include #include #include @@ -173,7 +174,7 @@ int print_csv_header(struct chunk *msg, int size) "wretr,wredis," "status,weight,act,bck," "chkfail,chkdown,lastchg,downtime,qlimit," - "pid,iid,sid,throttle,lbtot,tracked,type," + "pid,iid,sid,throttle,lbtot,tracked,type,rate," "\n"); } @@ -650,21 +651,21 @@ int stats_dump_proxy(struct session *s, struct proxy *px, struct uri_auth *uri) if (!(s->data_ctx.stats.flags & STAT_FMT_CSV)) { /* print a new table */ chunk_printf(&msg, sizeof(trash), - "\n" + "
\n" "" "" - "" + "" "\n" "" "" - "" + "" "" "" "" "\n" "" "" - "" + "" "" "" "" @@ -688,10 +689,10 @@ int stats_dump_proxy(struct session *s, struct proxy *px, struct uri_auth *uri) chunk_printf(&msg, sizeof(trash), /* name, queue */ "" - /* sessions : current, max, limit, total, lbtot */ + /* sessions : current, max, limit, rate, total, lbtot */ "" "" - "" + "" /* bytes : in, out */ "" /* denied: req, resp */ @@ -705,7 +706,8 @@ int stats_dump_proxy(struct session *s, struct proxy *px, struct uri_auth *uri) /* rest of server: nothing */ "" "", - px->feconn, px->feconn_max, px->maxconn, px->cum_feconn, + px->feconn, px->feconn_max, px->maxconn, + read_freq_ctr(&px->fe_sess_per_sec), px->cum_feconn, px->bytes_in, px->bytes_out, px->denied_req, px->denied_resp, px->failed_req, @@ -731,6 +733,8 @@ int stats_dump_proxy(struct session *s, struct proxy *px, struct uri_auth *uri) ",,,,,,,," /* pid, iid, sid, throttle, lbtot, tracked, type */ "%d,%d,0,,,,%d," + /* rate */ + "%u," "\n", px->id, px->feconn, px->feconn_max, px->maxconn, px->cum_feconn, @@ -739,7 +743,8 @@ int stats_dump_proxy(struct session *s, struct proxy *px, struct uri_auth *uri) px->failed_req, px->state == PR_STRUN ? "OPEN" : px->state == PR_STIDLE ? "FULL" : "STOP", - relative_pid, px->uuid, STATS_TYPE_FE); + relative_pid, px->uuid, STATS_TYPE_FE, + read_freq_ctr(&px->fe_sess_per_sec)); } if (buffer_write_chunk(rep, &msg) >= 0) @@ -805,10 +810,10 @@ int stats_dump_proxy(struct session *s, struct proxy *px, struct uri_auth *uri) "" /* queue : current, max, limit */ "" - /* sessions : current, max, limit, total, lbtot */ + /* sessions : current, max, limit, rate, total, lbtot */ "" "" - "" + "" /* bytes : in, out */ "" /* denied: req, resp */ @@ -822,6 +827,7 @@ int stats_dump_proxy(struct session *s, struct proxy *px, struct uri_auth *uri) sv_state, sv->id, sv->nbpend, sv->nbpend_max, LIM2A0(sv->maxqueue, "-"), sv->cur_sess, sv->cur_sess_max, LIM2A1(sv->maxconn, "-"), + read_freq_ctr(&sv->sess_per_sec), sv->cum_sess, sv->cum_lbconn, sv->bytes_in, sv->bytes_out, sv->failed_secu, @@ -956,8 +962,14 @@ int stats_dump_proxy(struct session *s, struct proxy *px, struct uri_auth *uri) else chunk_printf(&msg, sizeof(trash), ","); - /* type, then EOL */ - chunk_printf(&msg, sizeof(trash), "%d,\n", STATS_TYPE_SV); + /* type */ + chunk_printf(&msg, sizeof(trash), "%d,", STATS_TYPE_SV); + + /* rate */ + chunk_printf(&msg, sizeof(trash), "%u,", read_freq_ctr(&sv->sess_per_sec)); + + /* finish with EOL */ + chunk_printf(&msg, sizeof(trash), "\n"); } if (buffer_write_chunk(rep, &msg) >= 0) return 0; @@ -976,10 +988,10 @@ int stats_dump_proxy(struct session *s, struct proxy *px, struct uri_auth *uri) "" /* queue : current, max */ "" - /* sessions : current, max, limit, total, lbtot */ + /* sessions : current, max, limit, rate, total, lbtot */ + "" "" "" - "" /* bytes : in, out */ "" /* denied: req, resp */ @@ -995,7 +1007,9 @@ int stats_dump_proxy(struct session *s, struct proxy *px, struct uri_auth *uri) "" "", px->nbpend /* or px->totpend ? */, px->nbpend_max, - px->beconn, px->beconn_max, px->fullconn, px->cum_beconn, px->cum_lbconn, + px->beconn, px->beconn_max, px->fullconn, + read_freq_ctr(&px->be_sess_per_sec), + px->cum_beconn, px->cum_lbconn, px->bytes_in, px->bytes_out, px->denied_req, px->denied_resp, px->failed_conns, px->failed_resp, @@ -1040,6 +1054,8 @@ int stats_dump_proxy(struct session *s, struct proxy *px, struct uri_auth *uri) ",%d,%d,%d,," /* pid, iid, sid, throttle, lbtot, tracked, type */ "%d,%d,0,,%d,,%d," + /* rate */ + "%u," "\n", px->id, px->nbpend /* or px->totpend ? */, px->nbpend_max, @@ -1054,7 +1070,8 @@ int stats_dump_proxy(struct session *s, struct proxy *px, struct uri_auth *uri) px->down_trans, now.tv_sec - px->last_change, px->srv?be_downtime(px):0, relative_pid, px->uuid, - px->cum_lbconn, STATS_TYPE_BE); + px->cum_lbconn, STATS_TYPE_BE, + read_freq_ctr(&px->be_sess_per_sec)); } if (buffer_write_chunk(rep, &msg) >= 0) return 0; diff --git a/src/freq_ctr.c b/src/freq_ctr.c new file mode 100644 index 0000000000..4522ff3589 --- /dev/null +++ b/src/freq_ctr.c @@ -0,0 +1,45 @@ +/* + * Event rate calculation functions. + * + * Copyright 2000-2009 Willy Tarreau + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ + +#include +#include +#include +#include + +/* Read a frequency counter taking history into account for missing time in + * current period. Current second is sub-divided in 1000 chunks of one ms, + * and the missing ones are read proportionally from previous value. The + * return value has the same precision as one input data sample, so low rates + * will be inaccurate still appropriate for max checking. One trick we use for + * low values is to specially handle the case where the rate is between 0 and 1 + * in order to avoid flapping while waiting for the next event. + */ +unsigned int read_freq_ctr(struct freq_ctr *ctr) +{ + unsigned int cur; + if (unlikely(ctr->curr_sec != now.tv_sec)) + rotate_freq_ctr(ctr); + + cur = ctr->curr_ctr; + if (ctr->prev_ctr <= 1 && !ctr->curr_ctr) + return ctr->prev_ctr; /* very low rate, avoid flapping */ + + return cur + mul32hi(ctr->prev_ctr, ~curr_sec_ms_scaled); +} + + +/* + * Local variables: + * c-indent-level: 8 + * c-basic-offset: 8 + * End: + */ diff --git a/src/proto_http.c b/src/proto_http.c index 6acb0b7b28..a8ade23c14 100644 --- a/src/proto_http.c +++ b/src/proto_http.c @@ -47,7 +47,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -692,7 +694,7 @@ void perform_http_redirect(struct session *s, struct stream_interface *si) /* FIXME: we should increase a counter of redirects per server and per backend. */ if (s->srv) - s->srv->cum_sess++; + srv_inc_sess_ctr(s->srv); } /* Return the error message corresponding to si->err_type. It is assumed @@ -1943,7 +1945,7 @@ int http_process_request(struct session *s, struct buffer *req) s->be->beconn++; if (s->be->beconn > s->be->beconn_max) s->be->beconn_max = s->be->beconn; - s->be->cum_beconn++; + proxy_inc_be_ctr(s->be); s->flags |= SN_BE_ASSIGNED; } @@ -2046,7 +2048,7 @@ int http_process_request(struct session *s, struct buffer *req) s->be->beconn++; if (s->be->beconn > s->be->beconn_max) s->be->beconn_max = s->be->beconn; - s->be->cum_beconn++; + proxy_inc_be_ctr(s->be); /* assign new parameters to the session from the new backend */ s->rep->rto = s->req->wto = s->be->timeout.server; @@ -2067,7 +2069,7 @@ int http_process_request(struct session *s, struct buffer *req) s->be->beconn++; if (s->be->beconn > s->be->beconn_max) s->be->beconn_max = s->be->beconn; - s->be->cum_beconn++; + proxy_inc_be_ctr(s->be); /* assign new parameters to the session from the new backend */ s->rep->rto = s->req->wto = s->be->timeout.server; @@ -2085,7 +2087,7 @@ int http_process_request(struct session *s, struct buffer *req) s->be->beconn++; if (s->be->beconn > s->be->beconn_max) s->be->beconn_max = s->be->beconn; - s->be->cum_beconn++; + proxy_inc_be_ctr(s->be); s->flags |= SN_BE_ASSIGNED; } diff --git a/src/session.c b/src/session.c index 8ced9b8bf3..b3c50ca346 100644 --- a/src/session.c +++ b/src/session.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -367,7 +368,7 @@ void sess_update_stream_int(struct session *s, struct stream_interface *si) if (conn_err == SN_ERR_NONE) { /* state = SI_ST_CON now */ if (s->srv) - s->srv->cum_sess++; + srv_inc_sess_ctr(s->srv); return; } @@ -381,7 +382,7 @@ void sess_update_stream_int(struct session *s, struct stream_interface *si) } if (s->srv) - s->srv->cum_sess++; + srv_inc_sess_ctr(s->srv); if (s->srv) s->srv->failed_conns++; s->be->failed_conns++;
%s
QueueSessionsQueueSessionsBytesDeniedErrorsWarningsServer
CurMaxLimitCurMaxLimitTotalLbTotInOutLimitRateTotalLbTotInOutReqRespReqConnRespRetrRedisStatusWghtAct
Frontend%d%d%d%d%d%lld%lld
%s%d%d%s%d%d%s%d%d%d%d%lld%lld
Backend%d%d%d%d%d%d%d%d%d%lld%lld%s %s%d%d%d