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)
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
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
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)
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
#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 */
--- /dev/null
+/*
+ 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 <common/config.h>
+#include <types/freq_ctr.h>
+
+/* 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 <inc> 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:
+ */
#include <common/ticks.h>
#include <common/time.h>
#include <types/proxy.h>
+#include <proto/freq_ctr.h>
int start_proxies(int verbose);
void maintain_proxies(int *next);
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 */
/*
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
#include <types/server.h>
#include <proto/queue.h>
+#include <proto/freq_ctr.h>
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 */
/*
--- /dev/null
+/*
+ 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 <common/config.h>
+
+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:
+ */
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
#include <types/acl.h>
#include <types/buffers.h>
+#include <types/freq_ctr.h>
#include <types/httperr.h>
#include <types/log.h>
#include <types/protocols.h>
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 */
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
#include <common/mini-clist.h>
#include <types/buffers.h>
+#include <types/freq_ctr.h>
#include <types/proxy.h>
#include <types/queue.h>
#include <types/task.h>
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 */
#include <proto/proto_http.h>
#include <proto/proto_tcp.h>
#include <proto/queue.h>
+#include <proto/server.h>
#include <proto/session.h>
#include <proto/stream_sock.h>
#include <proto/task.h>
}
if (t->srv)
- t->srv->cum_sess++;
+ srv_inc_sess_ctr(t->srv);
if (t->srv)
t->srv->failed_conns++;
t->be->failed_conns++;
#include <proto/log.h>
#include <proto/hdr_idx.h>
#include <proto/proto_http.h>
+#include <proto/proxy.h>
#include <proto/session.h>
#include <proto/stream_interface.h>
#include <proto/stream_sock.h>
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;
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;
#include <proto/buffers.h>
#include <proto/dumpstats.h>
#include <proto/fd.h>
+#include <proto/freq_ctr.h>
#include <proto/pipe.h>
#include <proto/proto_uxst.h>
#include <proto/session.h>
"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");
}
if (!(s->data_ctx.stats.flags & STAT_FMT_CSV)) {
/* print a new table */
chunk_printf(&msg, sizeof(trash),
- "<table cols=\"26\" class=\"tbl\" width=\"100%%\">\n"
+ "<table cols=\"27\" class=\"tbl\" width=\"100%%\">\n"
"<tr align=\"center\" class=\"titre\">"
"<th colspan=2 class=\"pxname\">%s</th>"
- "<th colspan=24 class=\"empty\"></th>"
+ "<th colspan=25 class=\"empty\"></th>"
"</tr>\n"
"<tr align=\"center\" class=\"titre\">"
"<th rowspan=2></th>"
- "<th colspan=3>Queue</th><th colspan=5>Sessions</th>"
+ "<th colspan=3>Queue</th><th colspan=6>Sessions</th>"
"<th colspan=2>Bytes</th><th colspan=2>Denied</th>"
"<th colspan=3>Errors</th><th colspan=2>Warnings</th>"
"<th colspan=8>Server</th>"
"</tr>\n"
"<tr align=\"center\" class=\"titre\">"
"<th>Cur</th><th>Max</th><th>Limit</th><th>Cur</th><th>Max</th>"
- "<th>Limit</th><th>Total</th><th>LbTot</th><th>In</th><th>Out</th>"
+ "<th>Limit</th><th>Rate</th><th>Total</th><th>LbTot</th><th>In</th><th>Out</th>"
"<th>Req</th><th>Resp</th><th>Req</th><th>Conn</th>"
"<th>Resp</th><th>Retr</th><th>Redis</th>"
"<th>Status</th><th>Wght</th><th>Act</th>"
chunk_printf(&msg, sizeof(trash),
/* name, queue */
"<tr align=center class=\"frontend\"><td>Frontend</td><td colspan=3></td>"
- /* sessions : current, max, limit, total, lbtot */
+ /* sessions : current, max, limit, rate, total, lbtot */
"<td align=right>%d</td><td align=right>%d</td>"
"<td align=right>%d</td><td align=right>%d</td>"
- "<td align=right></td>"
+ "<td align=right>%d</td><td align=right></td>"
/* bytes : in, out */
"<td align=right>%lld</td><td align=right>%lld</td>"
/* denied: req, resp */
/* rest of server: nothing */
"<td align=center colspan=7></td></tr>"
"",
- 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,
",,,,,,,,"
/* 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,
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)
"<tr align=\"center\" class=\"%s%d\"><td>%s</td>"
/* queue : current, max, limit */
"<td align=right>%d</td><td align=right>%d</td><td align=right>%s</td>"
- /* sessions : current, max, limit, total, lbtot */
+ /* sessions : current, max, limit, rate, total, lbtot */
"<td align=right>%d</td><td align=right>%d</td>"
"<td align=right>%s</td><td align=right>%d</td>"
- "<td align=right>%d</td>"
+ "<td align=right>%d</td><td align=right>%d</td>"
/* bytes : in, out */
"<td align=right>%lld</td><td align=right>%lld</td>"
/* denied: req, resp */
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,
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;
"<tr align=center class=\"backend\"><td>Backend</td>"
/* queue : current, max */
"<td align=right>%d</td><td align=right>%d</td><td></td>"
- /* sessions : current, max, limit, total, lbtot */
+ /* sessions : current, max, limit, rate, total, lbtot */
+ "<td align=right>%d</td><td align=right>%d</td>"
"<td align=right>%d</td><td align=right>%d</td>"
"<td align=right>%d</td><td align=right>%d</td>"
- "<td align=right>%d</td>"
/* bytes : in, out */
"<td align=right>%lld</td><td align=right>%lld</td>"
/* denied: req, resp */
"<td align=center nowrap>%s %s</td><td align=center>%d</td>"
"<td align=center>%d</td><td align=center>%d</td>",
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,
",%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,
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;
--- /dev/null
+/*
+ * Event rate calculation functions.
+ *
+ * Copyright 2000-2009 Willy Tarreau <w@1wt.eu>
+ *
+ * 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 <common/config.h>
+#include <common/standard.h>
+#include <common/time.h>
+#include <proto/freq_ctr.h>
+
+/* 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:
+ */
#include <proto/hdr_idx.h>
#include <proto/proto_tcp.h>
#include <proto/proto_http.h>
+#include <proto/proxy.h>
#include <proto/queue.h>
+#include <proto/server.h>
#include <proto/session.h>
#include <proto/stream_interface.h>
#include <proto/stream_sock.h>
/* 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
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;
}
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;
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;
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;
}
#include <proto/proto_http.h>
#include <proto/proto_tcp.h>
#include <proto/queue.h>
+#include <proto/server.h>
#include <proto/stream_interface.h>
#include <proto/stream_sock.h>
#include <proto/task.h>
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;
}
}
if (s->srv)
- s->srv->cum_sess++;
+ srv_inc_sess_ctr(s->srv);
if (s->srv)
s->srv->failed_conns++;
s->be->failed_conns++;