My setup:
Everything works great but I wonder if it is possible for read operations to always try to use the redis node that is locally available first. This would enhance performance quite a bit because there would be fewer hops for all read operations.
As far as I see one can prioritize slaves over masters für specific commands via the Command Flags property. But is there a way to prioritize specific endpoints?
PS:
Used DLL: [email protected]
Redis Server Version: 3.2.100
EDIT:
Here is my connection code. The reason why I did not use the recommended Lazy getter is because I wanted to Connect/Reconnect on Failure of one of the nodes, which works very well with my solution.
internal class RedisConnector
{
private readonly ConfigurationOptions _currentConfiguration;
internal ConnectionMultiplexer Connection;
internal RedisCacheStore Store;
internal RedisConnector(ConfigurationOptions configuration)
{
_currentConfiguration = configuration;
Connect();
}
internal IDatabase Database
=> Connection.GetDatabase(RedisCacheConfiguration.Instance.Connection.DatabaseId);
internal IServer Server => Connection.GetServer(Database.IdentifyEndpoint());
private void Connect()
{
Connection = ConnectionMultiplexer.Connect(_currentConfiguration);
if (Connection == null || !Connection.IsConnected)
throw new CacheNotAvailableException();
Connection.ConnectionFailed += OnConnectionFailed;
Connection.ConnectionRestored += OnConnectionRestored;
Store = new RedisCacheStore(Database);
}
private void Reconnect()
{
if (Connection != null && !Connection.IsConnected)
Connection.Dispose();
Connect();
}
private void OnConnectionFailed(object sender, ConnectionFailedEventArgs args)
{
lock (_currentConfiguration)
{
if (_currentConfiguration.EndPoints.Contains(args.EndPoint))
{
_currentConfiguration.EndPoints.Remove(args.EndPoint);
Reconnect();
}
}
}
private void OnConnectionRestored(object sender, ConnectionFailedEventArgs args)
{
lock (_currentConfiguration)
{
if (!_currentConfiguration.EndPoints.Contains(args.EndPoint))
{
_currentConfiguration.EndPoints.Add(args.EndPoint);
Reconnect();
}
}
}
}
in this case.
Let say you have this case, 3VM with 3 apps & 3 redis instances.
The best option for APP runningin VM1 is to use Redis in VM1.
The best option for APP runningin VM2 is to use Redis in VM2.
The best option for APP runningin VM3 is to use Redis in VM3.
You can implements some rules like so :
private static Lazy<ConfigurationOptions> configOptions
= new Lazy<ConfigurationOptions>(() =>
{
var configOptions = new ConfigurationOptions();
configOptions.EndPoints.Add("x.x.x.1:6379");
configOptions.EndPoints.Add("x.x.x.2:6379");
configOptions.EndPoints.Add("x.x.x.3:6379");
configOptions.ClientName = "LeakyRedisConnection";
configOptions.ConnectTimeout = 100000;
configOptions.SyncTimeout = 100000;
return configOptions;
});
private static string getIP()
{
var host = Dns.GetHostEntry(Dns.GetHostName());
foreach (var ip in host.AddressList)
{
if (ip.AddressFamily == AddressFamily.InterNetwork)
{
return ip.ToString();
}
}
throw new Exception("ip not found!");
}
private static Lazy<ConfigurationOptions> getOptionsForIp(string myip)
{
var configOptions = new ConfigurationOptions();
configOptions.EndPoints.Add(myip);
configOptions.ClientName = "LeakyRedisConnectionDirectVM";
configOptions.ConnectTimeout = 100000;
configOptions.SyncTimeout = 100000;
return configOptions;
});
private static ConnectionMultiplexer conn;
private static ConnectionMultiplexer LeakyConn
{
get
{
if (conn == null || !conn.IsConnected){
string myIP = getIP();
conn = ConnectionMultiplexer.Connect(getOptionsForIp(myIP).Value);
if(conn == null || !conn.IsConnected){
conn = ConnectionMultiplexer.Connect(configOptions.Value);
}
}
return conn;
}
}
How to use this code:
var db = LeakyConn.GetDatabase();
db.StringSet(key, i);
db.StringGet(key);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With