Servicestack. redis is the C # client recommended by the redis official website (download here). There are also many users. Recently, I also used it in my project. I checked on the Internet about three methods for using this client: creating a connection, using a connection pool and using a persistent connection each time I access the client (see here ). In my first use, I encapsulated a redishelper class (in my version 3.9.32.0). Each time I access a new redisclient, I run out of dispose.
public class RedisHelper : IDisposable { public const string DefaultHost = "localhost"; public const int DefaultPort = 6379; #region Field private IRedisClient _redis; private PooledRedisClientManager _prcm; #endregion public RedisHelper() { } public RedisHelper(string host, int port) { _redis = new RedisClient(host, port); } public RedisHelper(string host, int port, int db) { _redis = new RedisClient(host, port); _redis.Db = db; } private bool m_disposed = false; public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if (!m_disposed) { if (disposing) { _redis.Dispose(); } m_disposed = true; } } ~RedisHelper() { Dispose(false); }}
However, in the actual test process, the error "every socket address is usually only allowed to be used once" occurs about 500 of the concurrency. It is strange that every time I run out of redisclient, I dispose it, it is reasonable to say that the connection has been released. Check the following lines of code in the source code redisnativeclient. CS:
protected virtual void Dispose(bool disposing) { if (ClientManager != null) { ClientManager.DisposeClient(this); return; } if (disposing) { //dispose un managed resources DisposeConnection(); } } internal void DisposeConnection() { if (IsDisposed) return; IsDisposed = true; if (socket == null) return; try { Quit(); } catch (Exception ex) { log.Error("Error when trying to Quit()", ex); } finally { SafeConnectionClose(); } }
The final call should be to first send a quit command to redis and then execute the safeconnectionclose () method:
private void SafeConnectionClose() { try { // workaround for a .net bug: http://support.microsoft.com/kb/821625 if (Bstream != null) Bstream.Close(); } catch { } try { if (socket != null) socket.Close(); } catch { } Bstream = null; socket = null; }
This method is to first disable bstream (bufferedstream inherited from stream). Here, to solve a. net bug (see here), The tcpclient closing method will not close the basic TCP connection, and then close the socket. Normally, there will be no problems I encountered, and I doubt it is because.. net bug caused by servicestack. redis does not solve this bug or it has not been completely solved in some environments. You have time to study the bug.
In any case, since the above method does not work, I will consider the alternative method. This time I used the connection pool for simplicity and verification (I suspect that 500 of the pressure is too high, but it is not very high:
private static PooledRedisClientManager CreateManager(RedisConfig config) { //192.168.32.13:6379;db=1 //PooledRedisClientManager prcm = new PooledRedisClientManager(new List<string> { "192.168.71.64:6380" }, new List<string> { "192.168.71.64:6380" }, // new RedisClientManagerConfig // { // MaxWritePoolSize = 150, // MaxReadPoolSize = 150, // AutoStart = true // }); PooledRedisClientManager prcm = new PooledRedisClientManager(config.Db, config.Host); prcm.ConnectTimeout = config.ConnectTimeout; prcm.PoolTimeOut = config.PoolTimeOut; prcm.SocketSendTimeout = config.SocketSendTimeout; prcm.SocketReceiveTimeout = config.SocketReceiveTimeout; return prcm; } public static PooledRedisClientManager GetPooledRedisClientManager(string connectionString) { lock (_syncObj) { if (!pools.ContainsKey(connectionString)) { pools.Add(connectionString, CreateManager(GetRedisConfig(connectionString))); } else if (pools[connectionString] == null) { pools[connectionString] = CreateManager(GetRedisConfig(connectionString)); } return pools[connectionString]; } }
The above "each socket address is usually only allowed once" does not appear, but there is another strange problem: "No more data ", I used a tool to test and found that continuous access to redis is not a problem, but a few seconds later, the access will cause no more data errors, tracking the source code:
int c = SafeReadByte(); if (c == -1) throw CreateResponseError("No more data");private int SafeReadByte(){return Bstream.ReadByte();}
This error indicates that the data cannot be read from the stream (see here ). But I cannot figure out why. Because it is going to be online, I did not go into details. Next I tried the persistent connection in the third method:
protected static RedisClient Redis = new RedisClient("10.0.4.227", 6379);
But the error is even more strange (it is true that every socket address is usually only allowed to use this error once). At that time, the error message was too hasty and was not recorded, it seems that I remember the problem of "force-disabling connections". I began to suspect that this was a problem. Some people complained about redis on the Internet (here ). But I should have looked at this brother's question differently from mine. Besides, redis is such a "bull" and I suspect that others have previously suspected themselves, so I suspected that I had a bug in my code, but I had no clue after checking it several times. At last, I re-installed redis at the prompt of my colleagues (previously installed by testers ), the result was tested again using the persistent connection method above, but there is still a problem. It seems that there are too many connections and there is no release problem (it's too careless and there is no record ), is there a problem with the LoadRunner test script ?? The time was too tight. I tried again with the connection pool method above, and it turned out to be a miracle. Hookay ~ The result is too big to be clear, and the time is too hasty. It is also strange that I am too careless to keep the information in the middle, and there are too many influencing factors to properly control, make sure you have time to reproduce it.