MEDIUM: session: maintain per-backend and per-server time statistics
authorWilly Tarreau <w@1wt.eu>
Tue, 17 Jun 2014 10:19:18 +0000 (12:19 +0200)
committerWilly Tarreau <w@1wt.eu>
Tue, 17 Jun 2014 15:15:56 +0000 (17:15 +0200)
Using the last rate counters, we now compute the queue, connect, response
and total times per server and per backend with a 95% accuracy over the last
1024 samples. The operation is cheap so we don't need to condition it.

include/common/defaults.h
include/proto/session.h
include/types/counters.h
src/proto_http.c
src/session.c

index bdd75cf..8d5d62a 100644 (file)
 #define SSL_DEFAULT_DH_PARAM 0
 #endif
 
+/* Number of samples used to compute the times reported in stats. A power of
+ * two is highly recommended, and this value multiplied by the largest response
+ * time must not overflow and unsigned int. See freq_ctr.h for more information.
+ * We consider that values are accurate to 95% with two batches of samples below,
+ * so in order to advertise accurate times across 1k samples, we effectively
+ * measure over 512.
+ */
+#ifndef TIME_STATS_SAMPLES
+#define TIME_STATS_SAMPLES 512
+#endif
+
 #endif /* _COMMON_DEFAULTS_H */
index fc83989..c835bf0 100644 (file)
@@ -50,6 +50,9 @@ int parse_track_counters(char **args, int *arg,
                         struct track_ctr_prm *prm,
                         struct proxy *defpx, char **err);
 
+/* Update the session's backend and server time stats */
+void session_update_time_stats(struct session *s);
+
 /* returns the session from a void *owner */
 static inline struct session *session_from_task(struct task *t)
 {
index ecdc7cb..172f8a6 100644 (file)
@@ -3,7 +3,7 @@
  * This file contains structure declarations for statistics counters.
  *
  * Copyright 2008-2009 Krzysztof Piotr Oledzki <ole@ans.pl>
- * Copyright 2011 Willy Tarreau <w@1wt.eu>
+ * Copyright 2011-2014 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
@@ -55,6 +55,8 @@ struct pxcounters {
        long long redispatches;                 /* retried and redispatched connections (BE only) */
        long long intercepted_req;              /* number of monitoring or stats requests intercepted by the frontend */
 
+       unsigned int q_time, c_time, d_time, t_time; /* sums of conn_time, queue_time, data_time, total_time */
+
        union {
                struct {
                        long long cum_req;      /* cumulated number of processed HTTP requests */
@@ -96,6 +98,8 @@ struct srvcounters {
        long long retries, redispatches;        /* retried and redispatched connections */
        long long failed_secu;                  /* blocked responses because of security concerns */
 
+       unsigned int q_time, c_time, d_time, t_time; /* sums of conn_time, queue_time, data_time, total_time */
+
        union {
                struct {
                        long long rsp[6];       /* http response codes */
index 082f161..48dbc43 100644 (file)
@@ -4714,6 +4714,8 @@ void http_end_txn_clean_session(struct session *s)
                s->do_log(s);
        }
 
+       session_update_time_stats(s);
+
        s->logs.accept_date = date; /* user-visible date for logging */
        s->logs.tv_accept = now;  /* corrected date for internal use */
        tv_zero(&s->logs.tv_request);
index 4412125..f828d9c 100644 (file)
@@ -2600,6 +2600,9 @@ struct task *process_session(struct task *t)
                s->do_log(s);
        }
 
+       /* update time stats for this session */
+       session_update_time_stats(s);
+
        /* the task MUST not be in the run queue anymore */
        session_free(s);
        task_delete(t);
@@ -2607,6 +2610,48 @@ struct task *process_session(struct task *t)
        return NULL;
 }
 
+/* Update the session's backend and server time stats */
+void session_update_time_stats(struct session *s)
+{
+       int t_request;
+       int t_queue;
+       int t_connect;
+       int t_data;
+       int t_close;
+       struct server *srv;
+
+       t_request = 0;
+       t_queue   = s->logs.t_queue;
+       t_connect = s->logs.t_connect;
+       t_close   = s->logs.t_close;
+       t_data    = s->logs.t_data;
+
+       if (s->be->mode != PR_MODE_HTTP)
+               t_data = t_connect;
+
+       if (t_connect < 0 || t_data < 0)
+               return;
+
+       if (tv_isge(&s->logs.tv_request, &s->logs.tv_accept))
+               t_request = tv_ms_elapsed(&s->logs.tv_accept, &s->logs.tv_request);
+
+       t_data    -= t_connect;
+       t_connect -= t_queue;
+       t_queue   -= t_request;
+
+       srv = objt_server(s->target);
+       if (srv) {
+               swrate_add(&srv->counters.q_time, TIME_STATS_SAMPLES, t_queue);
+               swrate_add(&srv->counters.c_time, TIME_STATS_SAMPLES, t_connect);
+               swrate_add(&srv->counters.d_time, TIME_STATS_SAMPLES, t_data);
+               swrate_add(&srv->counters.t_time, TIME_STATS_SAMPLES, t_close);
+       }
+       swrate_add(&s->be->be_counters.q_time, TIME_STATS_SAMPLES, t_queue);
+       swrate_add(&s->be->be_counters.c_time, TIME_STATS_SAMPLES, t_connect);
+       swrate_add(&s->be->be_counters.d_time, TIME_STATS_SAMPLES, t_data);
+       swrate_add(&s->be->be_counters.t_time, TIME_STATS_SAMPLES, t_close);
+}
+
 /*
  * This function adjusts sess->srv_conn and maintains the previous and new
  * server's served session counts. Setting newsrv to NULL is enough to release