Slow connection to cluster


#1

We just started using Aerospike Community Edition with the C# driver and have found that the initial connection to the cluster can sometimes take several seconds. The cluster is hosted in AWS across the same availability zones as the servers connecting to it. Is a connection time > 2 seconds expected? Is there something we can do to reduce this time?


#2

Aerospike clusters are meant to be grouped together as close as possible, usually the same rack if they’re physical servers.

In AWS, this usually means putting them in the same availability zone. If you do spread out across a zone, make sure to update your interval timings to account for the increased latency. Interval 150 / timeout 20 works pretty well.

Are you using the EC2 DNS names to connect to the nodes? Use the ec2-123-456-789-123.compute-1.amazonaws.com addresses as these will automatically resolve to either the public IPs outside AWS or the internal IPs inside your VPC. You can also use the ip-map feature to map internal IPs to external IPs if you’re using your clients from outside AWS.

Can you post a summarized version of the code you’re using to connect with the driver?


#3

Thanks for your response. We are using the internal IP addresses to connect. This issue is occurring on machines that are in the same availability zone as the cluster.

We can update the interval and give that a try. After some further testing, the slowness seems to be recurrent. It happens every 2-3 minutes. Would this correspond to the interval settings?

The code we are using to connect is below.

internal class AerospikeConnectionProvider
{
    private static readonly AerospikeConnectionProvider _instance = new AerospikeConnectionProvider();
    private readonly ConcurrentDictionary<string, AsyncCluster> _connections;

    private AerospikeConnectionProvider()
    {
        _connections = new ConcurrentDictionary<string, AsyncCluster>();
    }

    /// <summary>
    ///     Single instance of the AerospikeClient Provider.
    /// </summary>
    public static AerospikeConnectionProvider Instance
    {
        get { return _instance; }
    }

    /// <summary>
    ///     Get a aerospike cluster connection by a connection string in hostname:portnumber format.
    /// </summary>
    internal AsyncCluster GetAerospikeConnection(string hostname, int port = 3000, AsyncClientPolicy policy = null)
    {
        var connectionKey = string.Format("{0}:{1}", hostname, port);

        var cluster = _connections.GetOrAdd(connectionKey, s =>
        {
            var hosts = GetHostEntry(hostname).Select(x => new Host(x, port));
            var newcluster = new AsyncCluster(policy ?? new AsyncClientPolicy(),
                hosts.ToArray());
            return newcluster;
        });

        return cluster;
    }

    internal static IEnumerable<string> GetHostEntry(string hostname)
    {
        try
        {
            return Dns.GetHostEntry(hostname).AddressList.Select(x=>x.ToString());
        }
        catch (Exception)
        {
            return new[] {hostname};
        }
    }

    /// <summary>
    ///     Removes all current cluster connections
    /// </summary>
    internal void Reset()
    {
        foreach (var asyncCluster in _connections)
        {
            asyncCluster.Value.Close();
        }
        _connections.Clear();
    }
}

#4

Why are you using the AsyncCluster class?

All you have to do is maintain a static instance of either the AerospikeClient (which is synchronous) or AsyncClient. This is all you need to interact with the database.

Both are instantiated with a client policy class and a list of connection strings. If you just have a single cluster, you don’t need to create a client for each host, the C# driver will automatically handle this. You can pass in just 1 hostname if you want and the driver will find all the nodes in the cluster and will monitor for any changes with the nodes if the cluster changes. The main benefit in providing multiple hostnames is if one of the nodes is unavailable when restarting your application.

You also don’t need to have that reset method, the driver will close close or timeout connections on it’s own. You can just keep a static reference to these single line statements and avoid the whole connection provider wrapper.

var normalClient = new AerospikeClient(new ClientPolicy(), new Host(hostname, 3000));

var asynClient = new AsyncClient(new AsyncClientPolicy(), new Host(hostname, 3000));

#5

You can also checkout the official C# driver with demo code here: https://github.com/aerospike/aerospike-client-csharp

Clone a copy of the repo and look through the various sample codes, it includes a demo runner app that you can use to test your cluster with.