Skip to content

Private vs. Shared connections

Carlos Abalde edited this page Apr 20, 2016 · 5 revisions

When using the VMOD and calling redis.db() you choose between using 'private connections' or 'shared connections'.

When using private connections Redis connections are local to each Varnish worker thread. This is great because each worker has its own local connections (i.e. there is not extra thread contention when executing Redis queries); however, depending on the workload of your Varnish servers, and the number of different Redis instances you need to access to from your VCL, that number of connections could be too much.

Using shared connections is the alternative: Redis connections are shared between all Varnish workers threads using one or more pools. Obviously this adds extra thread contention, which may seriously harm the performance of your caching layer if the pools are not correctly dimensioned. On the other hand, this way you can limit the number of Redis connections created by the VMOD.

@davidfb and me crunched some numbers that may help you understand the performance differences between private and shared connections. Please, beware this is not a serious benchmark, but it's definitely something you may want to consider.

Scenario

  • Ubuntu Trusty, Intel Core i3-3220 CPU @ 3.30GHz × 4 (64 bits), 7.5GB RAM.
  • Varnish Cache 4.1.2 revision 0d7404e (default configuration).
  • Redis 3.0.7 (single server & persistence disabled).
  • Redis VMOD 829778b.
  • siege -q -b -c 400 -t 60S http://192.168.4.104:6081/

Results

  • First row shows performance metrics when no Redis queries are executed.
Shared conns Max conns # Varnish workers # Redis conns HTTP reqs / sec Blocked workers
- - 737 - 10570 -
NO 1 811 807 8438 -
YES 1000 808 400 8417 0
YES 500 825 400 8605 0
YES 400 839 400 8285 0
YES 300 836 300 8664 990K
YES 200 808 200 7873 1011K
YES 100 808 100 7953 1211K
YES 50 791 50 9122 1556K
YES 25 790 25 9392 1604K
YES 10 790 10 9431 1633K
YES 5 753 5 9151 1614K
YES 4 698 4 9088 1608K
YES 3 624 3 8849 1561K
YES 2 618 2 7906 1437K
YES 1 535 1 5143 924K

VCL

vcl 4.0;

import std;
import redis;

backend default {
    .host = "127.0.0.1";
    .port = "80";
}

sub vcl_init {
    #new db = redis.db(
    #    location="127.0.0.1:6379",
    #    type=master,
    #    connection_timeout=500,
    #    connection_ttl=0,
    #    command_timeout=0,
    #    max_command_retries=0,
    #    shared_connections=false,
    #    max_connections=1,
    #    password="",
    #    sickness_ttl=0,
    #    max_cluster_hops=0);

    #new db = redis.db(
    #    location="127.0.0.1:6379",
    #    type=master,
    #    connection_timeout=500,
    #    connection_ttl=0,
    #    command_timeout=0,
    #    max_command_retries=0,
    #    shared_connections=true,
    #    max_connections=1000,
    #    password="",
    #    sickness_ttl=0,
    #    max_cluster_hops=0);

    #new db = redis.db(
    #    location="127.0.0.1:6379",
    #    type=master,
    #    connection_timeout=500,
    #    connection_ttl=0,
    #    command_timeout=0,
    #    max_command_retries=0,
    #    shared_connections=true,
    #    max_connections=500,
    #    password="",
    #    sickness_ttl=0,
    #    max_cluster_hops=0);

    # ...
}

sub vcl_recv {
    return (synth(200, "OK"));
}

sub vcl_synth {
    if (req.url == "/stats") {
        synthetic(db.stats());
    } else {
        db.command("SET");
        db.push("foo");
        db.push("Hello world!");
        db.execute(true);
        if (!db.reply_is_status()) {
            std.syslog(6, "500");
            set resp.status = 500;
        }
        db.free();

        db.command("GET");
        db.push("foo");
        db.execute(true);
        if (!db.reply_is_string()) {
            std.syslog(6, "501");
            set resp.status = 501;
        }
        db.free();

        db.command("EVAL");
        db.push({"
            redis.call('SET', KEYS[1], ARGV[1]);
            redis.call('EXPIRE', KEYS[1], ARGV[2]);
        "});
        db.push("1");
        db.push("bar");
        db.push(req.xid);
        db.push("1");
        db.execute(true);
        if (!db.reply_is_nil()) {
            std.syslog(6, "502");
            set resp.status = 502;
        }
        db.free();

        synthetic("");
    }

    return (deliver);
}

Clone this wiki locally