Skip to content

sending multiple metrics in a packet #19

Description

@ct16k

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;
 }

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions