參考文檔:
https://blog.csdn.net/smj20170417/article/details/79928228
https://www.jianshu.com/p/0b3be884d2f5
Redis鏈接字符串可以提出來放到 Config文件當中:
<connectionStrings> <add name="Connection_Redis" connectionString="127.0.0.1:6379,127.0.0.1:6380,127.0.0.1:6381,127.0.0.1:6382,password=123456,abortConnect=false" /> </connectionStrings>
當有多個Redis實例時,可以設置鏈接多個實例,中間用逗號分隔即可(比如:使用Redis集群)。
1 public class RedisCacheHelper 2 { 3 private readonly Logger _log = LogManager.GetCurrentClassLogger(); 4 5 /// <summary> 6 /// 連接字符串 7 /// </summary> 8 private static string _connectionString; 9 10 /// <summary> 11 /// redis 連接對象 12 /// </summary> 13 private static IConnectionMultiplexer _connMultiplexer; 14 15 /// <summary> 16 /// 實例化對象 17 /// </summary> 18 private static RedisCacheHelper _cacheHelper; 19 /// <summary> 20 /// 實例 21 /// </summary> 22 private static RedisCacheHelper _instance; 23 24 /// <summary> 25 /// 鎖 26 /// </summary> 27 private static readonly object Locker = new object(); 28 29 /// <summary> 30 /// 數據庫 31 /// </summary> 32 private IDatabase _db; 33 34 35 /// <summary> 36 /// 默認鏈接實例 37 /// </summary> 38 private RedisCacheHelper() 39 { 40 _connectionString = ConfigurationManager.ConnectionStrings["Connection_Redis"].ConnectionString; 41 _connMultiplexer = ConnectionMultiplexer.Connect(_connectionString); 42 //添加注冊事件 43 AddRegisterEvent(); 44 } 45 46 /// <summary> 47 /// 獲取 Redis 連接對象 48 /// </summary> 49 private IConnectionMultiplexer Connnection 50 { 51 get 52 { 53 if (_connMultiplexer == null || !_connMultiplexer.IsConnected) 54 { 55 lock (Locker) 56 { 57 if (_connMultiplexer == null || !_connMultiplexer.IsConnected) 58 { 59 _connMultiplexer = ConnectionMultiplexer.Connect(_connectionString); 60 } 61 } 62 } 63 return _connMultiplexer; 64 } 65 } 66 67 /// <summary> 68 /// 獲取指定db,默認不指定 69 /// </summary> 70 /// <param name="db"></param> 71 /// <returns></returns> 72 private IDatabase GetDatabase(int db = -1) 73 { 74 return Connnection.GetDatabase(db); 75 } 76 77 /// <summary> 78 /// 調用實例,通過該實例調用Redis 79 /// </summary> 80 public static RedisCacheHelper Instance 81 { 82 get 83 { 84 if (_cacheHelper != null) return _cacheHelper; 85 lock (Locker) 86 { 87 if (_cacheHelper != null) return _cacheHelper; 88 _cacheHelper = new RedisCacheHelper(); 89 } 90 return _cacheHelper; 91 } 92 } 93 94 #region 注冊事件 95 96 /// <summary> 97 /// 添加注冊事件 98 /// </summary> 99 private void AddRegisterEvent() 100 { 101 _connMultiplexer.ConnectionRestored += ConnMultiplexer_ConnectionRestored; 102 _connMultiplexer.ConnectionFailed += ConnMultiplexer_ConnectionFailed; 103 _connMultiplexer.ErrorMessage += ConnMultiplexer_ErrorMessage; 104 _connMultiplexer.ConfigurationChanged += ConnMultiplexer_ConfigurationChanged; 105 _connMultiplexer.HashSlotMoved += ConnMultiplexer_HashSlotMoved; 106 _connMultiplexer.InternalError += ConnMultiplexer_InternalError; 107 _connMultiplexer.ConfigurationChangedBroadcast += ConnMultiplexer_ConfigurationChangedBroadcast; 108 } 109 110 /// <summary> 111 /// 重新配置廣播時(通常意味着主從同步更改) 112 /// </summary> 113 /// <param name="sender"></param> 114 /// <param name="e"></param> 115 private void ConnMultiplexer_ConfigurationChangedBroadcast(object sender, EndPointEventArgs e) 116 { 117 _log.Info($"{nameof(ConnMultiplexer_ConfigurationChangedBroadcast)}: {e.EndPoint}"); 118 } 119 120 /// <summary> 121 /// 發生內部錯誤時(主要用於調試) 122 /// </summary> 123 /// <param name="sender"></param> 124 /// <param name="e"></param> 125 private void ConnMultiplexer_InternalError(object sender, InternalErrorEventArgs e) 126 { 127 _log.Error($"{nameof(ConnMultiplexer_InternalError)}: {e.Exception}"); 128 } 129 130 /// <summary> 131 /// 更改集群時 132 /// </summary> 133 /// <param name="sender"></param> 134 /// <param name="e"></param> 135 private void ConnMultiplexer_HashSlotMoved(object sender, HashSlotMovedEventArgs e) 136 { 137 _log.Info( 138 $"{nameof(ConnMultiplexer_HashSlotMoved)}: {nameof(e.OldEndPoint)}-{e.OldEndPoint} To {nameof(e.NewEndPoint)}-{e.NewEndPoint}"); 139 } 140 141 /// <summary> 142 /// 配置更改時 143 /// </summary> 144 /// <param name="sender"></param> 145 /// <param name="e"></param> 146 private void ConnMultiplexer_ConfigurationChanged(object sender, EndPointEventArgs e) 147 { 148 _log.Info($"{nameof(ConnMultiplexer_ConfigurationChanged)}: {e.EndPoint}"); 149 } 150 151 /// <summary> 152 /// 發生錯誤時 153 /// </summary> 154 /// <param name="sender"></param> 155 /// <param name="e"></param> 156 private void ConnMultiplexer_ErrorMessage(object sender, RedisErrorEventArgs e) 157 { 158 _log.Error($"{nameof(ConnMultiplexer_ErrorMessage)}: {e.Message}"); 159 } 160 161 /// <summary> 162 /// 物理連接失敗時 163 /// </summary> 164 /// <param name="sender"></param> 165 /// <param name="e"></param> 166 private void ConnMultiplexer_ConnectionFailed(object sender, ConnectionFailedEventArgs e) 167 { 168 _log.Fatal($"{nameof(ConnMultiplexer_ConnectionFailed)}: {e.Exception}"); 169 } 170 171 /// <summary> 172 /// 建立物理連接時 173 /// </summary> 174 /// <param name="sender"></param> 175 /// <param name="e"></param> 176 private void ConnMultiplexer_ConnectionRestored(object sender, ConnectionFailedEventArgs e) 177 { 178 _log.Info($"{nameof(ConnMultiplexer_ConnectionRestored)}: {e.Exception}"); 179 } 180 181 #endregion 182 }
以上Redis鏈接就配置好了,使用方式如下:首先在把集群中的主從服務都開啟,3主、3從
然后在代碼中進行操作驗證,向緩存中插入一條數據,然后循環讀寫數據,循環的時候手動任意關閉Redis服務當中的 1~2個 服務器
1 while (true) 2 { 3 //設置age 4 RedisCacheHelper.Instance.Set("age", "10", new TimeSpan(0, 5, 0)); 5 6 //獲取age 7 var getage = RedisCacheHelper.Instance.Get("age"); 8 Console.WriteLine(DateTime.Now.ToString("HH:mm:ss.fff") + ":" + getage); 9 10 Thread.Sleep(1000); // 等待1s 11 }
成功將緩存存入到服務器當中,運行效果如下:
此時查看Redis集群,發現主從實例都有數據了,接下來我們把其中任意1個 Redis實例關掉 (上邊運行的循環代碼程序不要關閉)
發現程序正常運行:
但是上邊的步驟,我經過多次測試,在任意關閉某個實例的時候,偶爾會報如下錯誤:集群掛了
我們把寫的方法注釋掉,只保留讀取的代碼,同樣會偶爾報異常。
但是大部分情況下,關掉其中一個實例,程序都正常運行: