While looking for a quick and easy way to send some nginx data to statsd I came upon this module and while it's doing its job properly, there is one thing that was bothering me: for each configured metric it would generate a separate UDP packet. This would mean that when used in a relatively large farm with multiple vhosts, each with multiple metrics defined, it would generate a flurry of packets, even when not under heavy load, that would hammer the statsd service. One obvious solution to this was to combine multiple metrics in a single packet, and the following patch tries to do just that.
--- ngx_http_statsd.c.orig 2015-11-02 22:07:22.736000288 +0000
+++ ngx_http_statsd.c 2015-11-02 22:20:44.615986241 +0000
@@ -18,7 +18,7 @@
#define STATSD_TYPE_COUNTER 0x0001
#define STATSD_TYPE_TIMING 0x0002
-#define STATSD_MAX_STR 256
+#define STATSD_MAX_STR 1432
#define ngx_conf_merge_ptr_value(conf, prev, default) \
if (conf == NGX_CONF_UNSET_PTR) { \
@@ -235,7 +235,8 @@
ngx_int_t
ngx_http_statsd_handler(ngx_http_request_t *r)
{
- u_char line[STATSD_MAX_STR], *p;
+ u_char startline[STATSD_MAX_STR], *p, *line;
+ size_t togo;
const char * metric_type;
ngx_http_statsd_conf_t *ulcf;
ngx_statsd_stat_t *stats;
@@ -262,6 +263,8 @@
}
stats = ulcf->stats->elts;
+ line = startline;
+ togo = STATSD_MAX_STR;
for (c = 0; c < ulcf->stats->nelts; c++) {
stat = stats[c];
@@ -287,13 +290,26 @@
if (metric_type) {
if (ulcf->sample_rate < 100) {
- p = ngx_snprintf(line, STATSD_MAX_STR, "%V:%d|%s|@0.%02d", &s, n, metric_type, ulcf->sample_rate);
+ p = ngx_snprintf(line, togo, "%V:%d|%s|@0.%02d\n", &s, n, metric_type, ulcf->sample_rate);
} else {
- p = ngx_snprintf(line, STATSD_MAX_STR, "%V:%d|%s", &s, n, metric_type);
+ p = ngx_snprintf(line, togo, "%V:%d|%s\n", &s, n, metric_type);
+ }
+ if (p - line >= togo) {
+ if (line != startline) {
+ ngx_http_statsd_udp_send(ulcf->endpoint, startline, line - startline - sizeof(char));
+ c--;
+ }
+ line = startline;
+ togo = STATSD_MAX_STR;
+ } else {
+ togo -= p - line;
+ line = p;
}
- ngx_http_statsd_udp_send(ulcf->endpoint, line, p - line);
}
}
+ if (togo < STATSD_MAX_STR) {
+ ngx_http_statsd_udp_send(ulcf->endpoint, startline, line - startline - sizeof(char));
+ }
return NGX_OK;
}
While looking for a quick and easy way to send some nginx data to statsd I came upon this module and while it's doing its job properly, there is one thing that was bothering me: for each configured metric it would generate a separate UDP packet. This would mean that when used in a relatively large farm with multiple vhosts, each with multiple metrics defined, it would generate a flurry of packets, even when not under heavy load, that would hammer the statsd service. One obvious solution to this was to combine multiple metrics in a single packet, and the following patch tries to do just that.