一,Redis哨兵模式配置
1,下载Redis,然后解压复制5个文件夹分别如下命名。
2,哨兵模式配置
(1)修改主节点Redis-6379中redis.windows.conf配置文件如下
(2)修改从节点Redis-6380中redis.windows.conf配置文件如下
(3)配置哨兵,在哨兵文件夹下添加Sentinel.conf配置文件
a,哨兵Redis-26379配置如下
其他哨兵节点修改26379端口即可。
二,Redis帮助类封装(StackExchange.Redis)
项目文件结构如下:
1,RedisHelper.cs

1 using Microsoft.Extensions.Configuration; 2 using StackExchange.Redis; 3 using System; 4 using System.Collections.Generic; 5 using System.IO; 6 using System.Linq; 7 using System.Runtime.Serialization.Formatters.Binary; 8 using System.Threading.Tasks; 9 10 namespace MS.Quality.Component.Cache.Redis 11 { 12 /// <summary> 13 /// Redis 助手 14 /// </summary> 15 public class RedisHelper 16 { 17 /// <summary> 18 /// 连接字符串 19 /// </summary> 20 private static readonly string ConnectionString; 21 22 /// <summary> 23 /// redis 连接对象 24 /// </summary> 25 private static IConnectionMultiplexer _connMultiplexer; 26 27 /// <summary> 28 /// 默认的 Key 值(用来当作 RedisKey 的前缀) 29 /// </summary> 30 private static readonly string DefaultKey; 31 32 /// <summary> 33 /// 锁 34 /// </summary> 35 private static readonly object Locker = new object(); 36 37 /// <summary> 38 /// 数据库 39 /// </summary> 40 private readonly IDatabase _db; 41 42 /// <summary> 43 /// 获取 Redis 连接对象 44 /// </summary> 45 /// <returns></returns> 46 public IConnectionMultiplexer GetConnectionRedisMultiplexer() 47 { 48 if ((_connMultiplexer == null) || !_connMultiplexer.IsConnected) 49 { 50 lock (Locker) 51 { 52 if ((_connMultiplexer == null) || !_connMultiplexer.IsConnected) 53 _connMultiplexer = ConnectionMultiplexer.Connect(ConnectionString); 54 } 55 } 56 57 return _connMultiplexer; 58 } 59 60 #region 其它 61 62 public ITransaction GetTransaction() 63 { 64 return _db.CreateTransaction(); 65 } 66 67 #endregion 其它 68 69 #region 构造函数 70 71 static RedisHelper() 72 { 73 var builder = new ConfigurationBuilder() 74 .SetBasePath(Directory.GetCurrentDirectory()) 75 .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true); 76 IConfigurationRoot configuration = builder.Build(); 77 if (configuration.GetSection("Redis:Sentinel").Exists()) 78 { 79 ConfigurationOptions sentinelOptions = new ConfigurationOptions(); 80 var IpArray = configuration.GetSection("Redis:Sentinel").GetChildren(); 81 foreach (var item in IpArray) 82 { 83 sentinelOptions.EndPoints.Add(item.Value); 84 } 85 sentinelOptions.TieBreaker = ""; 86 sentinelOptions.CommandMap = CommandMap.Sentinel; 87 sentinelOptions.AbortOnConnectFail = true; 88 // Connect! 89 ConnectionMultiplexer sentinelConnection = ConnectionMultiplexer.Connect(sentinelOptions); 90 91 // Get a connection to the master 92 ConfigurationOptions redisServiceOptions = new ConfigurationOptions(); 93 redisServiceOptions.ServiceName = configuration.GetSection("Redis:ServiceName").Value; //master名称 94 redisServiceOptions.Password = configuration.GetSection("Redis:Password").Value; //master访问密码 95 redisServiceOptions.AbortOnConnectFail = true; 96 redisServiceOptions.AllowAdmin = true; 97 _connMultiplexer = sentinelConnection.GetSentinelMasterConnection(redisServiceOptions); 98 } 99 else 100 { 101 ConnectionString = configuration.GetSection("Redis:ConnectionStrings").Value; 102 _connMultiplexer = ConnectionMultiplexer.Connect(ConnectionString); 103 } 104 DefaultKey = configuration.GetSection("Redis:DefaultKey").Value; 105 106 AddRegisterEvent(); 107 } 108 109 public RedisHelper(int db = -1) 110 { 111 _db = _connMultiplexer.GetDatabase(db); 112 } 113 114 #endregion 构造函数 115 116 #region String 操作 117 118 /// <summary> 119 /// 设置 key 并保存字符串(如果 key 已存在,则覆盖值) 120 /// </summary> 121 /// <param name="redisKey"></param> 122 /// <param name="redisValue"></param> 123 /// <param name="expiry"></param> 124 /// <returns></returns> 125 public bool StringSet(string redisKey, string redisValue, TimeSpan? expiry = null) 126 { 127 redisKey = AddKeyPrefix(redisKey); 128 return _db.StringSet(redisKey, redisValue, expiry); 129 } 130 131 /// <summary> 132 /// 保存多个 Key-value 133 /// </summary> 134 /// <param name="keyValuePairs"></param> 135 /// <returns></returns> 136 public bool StringSet(IEnumerable<KeyValuePair<RedisKey, RedisValue>> keyValuePairs) 137 { 138 keyValuePairs = 139 keyValuePairs.Select(x => new KeyValuePair<RedisKey, RedisValue>(AddKeyPrefix(x.Key), x.Value)); 140 return _db.StringSet(keyValuePairs.ToArray()); 141 } 142 143 /// <summary> 144 /// 获取字符串 145 /// </summary> 146 /// <param name="redisKey"></param> 147 /// <param name="expiry"></param> 148 /// <returns></returns> 149 public string StringGet(string redisKey, TimeSpan? expiry = null) 150 { 151 redisKey = AddKeyPrefix(redisKey); 152 return _db.StringGet(redisKey); 153 } 154 155 /// <summary> 156 /// 存储一个对象(该对象会被序列化保存) 157 /// </summary> 158 /// <param name="redisKey"></param> 159 /// <param name="redisValue"></param> 160 /// <param name="expiry"></param> 161 /// <returns></returns> 162 public bool StringSet<T>(string redisKey, T redisValue, TimeSpan? expiry = null) 163 { 164 redisKey = AddKeyPrefix(redisKey); 165 var json = Serialize(redisValue); 166 return _db.StringSet(redisKey, json, expiry); 167 } 168 169 /// <summary> 170 /// 获取一个对象(会进行反序列化) 171 /// </summary> 172 /// <param name="redisKey"></param> 173 /// <param name="expiry"></param> 174 /// <returns></returns> 175 public T StringGet<T>(string redisKey, TimeSpan? expiry = null) 176 { 177 redisKey = AddKeyPrefix(redisKey); 178 return Deserialize<T>(_db.StringGet(redisKey)); 179 } 180 181 #region async 182 183 /// <summary> 184 /// 保存一个字符串值 185 /// </summary> 186 /// <param name="redisKey"></param> 187 /// <param name="redisValue"></param> 188 /// <param name="expiry"></param> 189 /// <returns></returns> 190 public async Task<bool> StringSetAsync(string redisKey, string redisValue, TimeSpan? expiry = null) 191 { 192 redisKey = AddKeyPrefix(redisKey); 193 return await _db.StringSetAsync(redisKey, redisValue, expiry); 194 } 195 196 /// <summary> 197 /// 保存一组字符串值 198 /// </summary> 199 /// <param name="keyValuePairs"></param> 200 /// <returns></returns> 201 public async Task<bool> StringSetAsync(IEnumerable<KeyValuePair<RedisKey, RedisValue>> keyValuePairs) 202 { 203 keyValuePairs = 204 keyValuePairs.Select(x => new KeyValuePair<RedisKey, RedisValue>(AddKeyPrefix(x.Key), x.Value)); 205 return await _db.StringSetAsync(keyValuePairs.ToArray()); 206 } 207 208 /// <summary> 209 /// 获取单个值 210 /// </summary> 211 /// <param name="redisKey"></param> 212 /// <param name="redisValue"></param> 213 /// <param name="expiry"></param> 214 /// <returns></returns> 215 public async Task<string> StringGetAsync(string redisKey, string redisValue, TimeSpan? expiry = null) 216 { 217 redisKey = AddKeyPrefix(redisKey); 218 return await _db.StringGetAsync(redisKey); 219 } 220 221 /// <summary> 222 /// 存储一个对象(该对象会被序列化保存) 223 /// </summary> 224 /// <param name="redisKey"></param> 225 /// <param name="redisValue"></param> 226 /// <param name="expiry"></param> 227 /// <returns></returns> 228 public async Task<bool> StringSetAsync<T>(string redisKey, T redisValue, TimeSpan? expiry = null) 229 { 230 redisKey = AddKeyPrefix(redisKey); 231 var json = Serialize(redisValue); 232 return await _db.StringSetAsync(redisKey, json, expiry); 233 } 234 235 /// <summary> 236 /// 获取一个对象(会进行反序列化) 237 /// </summary> 238 /// <param name="redisKey"></param> 239 /// <param name="expiry"></param> 240 /// <returns></returns> 241 public async Task<T> StringGetAsync<T>(string redisKey, TimeSpan? expiry = null) 242 { 243 redisKey = AddKeyPrefix(redisKey); 244 return Deserialize<T>(await _db.StringGetAsync(redisKey)); 245 } 246 247 #endregion async 248 249 #endregion String 操作 250 251 #region Hash 操作 252 253 /// <summary> 254 /// 判断该字段是否存在 hash 中 255 /// </summary> 256 /// <param name="redisKey"></param> 257 /// <param name="hashField"></param> 258 /// <returns></returns> 259 public bool HashExists(string redisKey, string hashField) 260 { 261 redisKey = AddKeyPrefix(redisKey); 262 return _db.HashExists(redisKey, hashField); 263 } 264 265 /// <summary> 266 /// 从 hash 中移除指定字段 267 /// </summary> 268 /// <param name="redisKey"></param> 269 /// <param name="hashField"></param> 270 /// <returns></returns> 271 public bool HashDelete(string redisKey, string hashField) 272 { 273 redisKey = AddKeyPrefix(redisKey); 274 return _db.HashDelete(redisKey, hashField); 275 } 276 277 /// <summary> 278 /// 从 hash 中移除指定字段 279 /// </summary> 280 /// <param name="redisKey"></param> 281 /// <param name="hashField"></param> 282 /// <returns></returns> 283 public long HashDelete(string redisKey, IEnumerable<RedisValue> hashField) 284 { 285 redisKey = AddKeyPrefix(redisKey); 286 return _db.HashDelete(redisKey, hashField.ToArray()); 287 } 288 289 /// <summary> 290 /// 在 hash 设定值 291 /// </summary> 292 /// <param name="redisKey"></param> 293 /// <param name="hashField"></param> 294 /// <param name="value"></param> 295 /// <returns></returns> 296 public bool HashSet(string redisKey, string hashField, string value) 297 { 298 redisKey = AddKeyPrefix(redisKey); 299 return _db.HashSet(redisKey, hashField, value); 300 } 301 302 /// <summary> 303 /// 在 hash 中设定值 304 /// </summary> 305 /// <param name="redisKey"></param> 306 /// <param name="hashFields"></param> 307 public void HashSet(string redisKey, IEnumerable<HashEntry> hashFields) 308 { 309 redisKey = AddKeyPrefix(redisKey); 310 _db.HashSet(redisKey, hashFields.ToArray()); 311 } 312 313 /// <summary> 314 /// 在 hash 中获取值 315 /// </summary> 316 /// <param name="redisKey"></param> 317 /// <param name="hashField"></param> 318 /// <returns></returns> 319 public RedisValue HashGet(string redisKey, string hashField) 320 { 321 redisKey = AddKeyPrefix(redisKey); 322 return _db.HashGet(redisKey, hashField); 323 } 324 325 /// <summary> 326 /// 在 hash 中获取值 327 /// </summary> 328 /// <param name="redisKey"></param> 329 /// <param name="hashField"></param> 330 /// <param name="value"></param> 331 /// <returns></returns> 332 public RedisValue[] HashGet(string redisKey, RedisValue[] hashField, string value) 333 { 334 redisKey = AddKeyPrefix(redisKey); 335 return _db.HashGet(redisKey, hashField); 336 } 337 338 /// <summary> 339 /// 从 hash 返回所有的字段值 340 /// </summary> 341 /// <param name="redisKey"></param> 342 /// <returns></returns> 343 public IEnumerable<RedisValue> HashKeys(string redisKey) 344 { 345 redisKey = AddKeyPrefix(redisKey); 346 return _db.HashKeys(redisKey); 347 } 348 349 /// <summary> 350 /// 返回 hash 中的所有值 351 /// </summary> 352 /// <param name="redisKey"></param> 353 /// <returns></returns> 354 public RedisValue[] HashValues(string redisKey) 355 { 356 redisKey = AddKeyPrefix(redisKey); 357 return _db.HashValues(redisKey); 358 } 359 360 /// <summary> 361 /// 在 hash 设定值(序列化) 362 /// </summary> 363 /// <param name="redisKey"></param> 364 /// <param name="hashField"></param> 365 /// <param name="value"></param> 366 /// <returns></returns> 367 public bool HashSet<T>(string redisKey, string hashField, T value) 368 { 369 redisKey = AddKeyPrefix(redisKey); 370 var json = Serialize(value); 371 return _db.HashSet(redisKey, hashField, json); 372 } 373 374 /// <summary> 375 /// 在 hash 中获取值(反序列化) 376 /// </summary> 377 /// <param name="redisKey"></param> 378 /// <param name="hashField"></param> 379 /// <returns></returns> 380 public T HashGet<T>(string redisKey, string hashField) 381 { 382 redisKey = AddKeyPrefix(redisKey); 383 return Deserialize<T>(_db.HashGet(redisKey, hashField)); 384 } 385 386 #region async 387 388 /// <summary> 389 /// 判断该字段是否存在 hash 中 390 /// </summary> 391 /// <param name="redisKey"></param> 392 /// <param name="hashField"></param> 393 /// <returns></returns> 394 public async Task<bool> HashExistsAsync(string redisKey, string hashField) 395 { 396 redisKey = AddKeyPrefix(redisKey); 397 return await _db.HashExistsAsync(redisKey, hashField); 398 } 399 400 /// <summary> 401 /// 从 hash 中移除指定字段 402 /// </summary> 403 /// <param name="redisKey"></param> 404 /// <param name="hashField"></param> 405 /// <returns></returns> 406 public async Task<bool> HashDeleteAsync(string redisKey, string hashField) 407 { 408 redisKey = AddKeyPrefix(redisKey); 409 return await _db.HashDeleteAsync(redisKey, hashField); 410 } 411 412 /// <summary> 413 /// 从 hash 中移除指定字段 414 /// </summary> 415 /// <param name="redisKey"></param> 416 /// <param name="hashField"></param> 417 /// <returns></returns> 418 public async Task<long> HashDeleteAsync(string redisKey, IEnumerable<RedisValue> hashField) 419 { 420 redisKey = AddKeyPrefix(redisKey); 421 return await _db.HashDeleteAsync(redisKey, hashField.ToArray()); 422 } 423 424 /// <summary> 425 /// 在 hash 设定值 426 /// </summary> 427 /// <param name="redisKey"></param> 428 /// <param name="hashField"></param> 429 /// <param name="value"></param> 430 /// <returns></returns> 431 public async Task<bool> HashSetAsync(string redisKey, string hashField, string value) 432 { 433 redisKey = AddKeyPrefix(redisKey); 434 return await _db.HashSetAsync(redisKey, hashField, value); 435 } 436 437 /// <summary> 438 /// 在 hash 中设定值 439 /// </summary> 440 /// <param name="redisKey"></param> 441 /// <param name="hashFields"></param> 442 public async Task HashSetAsync(string redisKey, IEnumerable<HashEntry> hashFields) 443 { 444 redisKey = AddKeyPrefix(redisKey); 445 await _db.HashSetAsync(redisKey, hashFields.ToArray()); 446 } 447 448 /// <summary> 449 /// 在 hash 中获取值 450 /// </summary> 451 /// <param name="redisKey"></param> 452 /// <param name="hashField"></param> 453 /// <returns></returns> 454 public async Task<RedisValue> HashGetAsync(string redisKey, string hashField) 455 { 456 redisKey = AddKeyPrefix(redisKey); 457 return await _db.HashGetAsync(redisKey, hashField); 458 } 459 460 /// <summary> 461 /// 在 hash 中获取值 462 /// </summary> 463 /// <param name="redisKey"></param> 464 /// <param name="hashField"></param> 465 /// <param name="value"></param> 466 /// <returns></returns> 467 public async Task<IEnumerable<RedisValue>> HashGetAsync(string redisKey, RedisValue[] hashField, string value) 468 { 469 redisKey = AddKeyPrefix(redisKey); 470 return await _db.HashGetAsync(redisKey, hashField); 471 } 472 473 /// <summary> 474 /// 从 hash 返回所有的字段值 475 /// </summary> 476 /// <param name="redisKey"></param> 477 /// <returns></returns> 478 public async Task<IEnumerable<RedisValue>> HashKeysAsync(string redisKey) 479 { 480 redisKey = AddKeyPrefix(redisKey); 481 return await _db.HashKeysAsync(redisKey); 482 } 483 484 /// <summary> 485 /// 返回 hash 中的所有值 486 /// </summary> 487 /// <param name="redisKey"></param> 488 /// <returns></returns> 489 public async Task<IEnumerable<RedisValue>> HashValuesAsync(string redisKey) 490 { 491 redisKey = AddKeyPrefix(redisKey); 492 return await _db.HashValuesAsync(redisKey); 493 } 494 495 /// <summary> 496 /// 在 hash 设定值(序列化) 497 /// </summary> 498 /// <param name="redisKey"></param> 499 /// <param name="hashField"></param> 500 /// <param name="value"></param> 501 /// <returns></returns> 502 public async Task<bool> HashSetAsync<T>(string redisKey, string hashField, T value) 503 { 504 redisKey = AddKeyPrefix(redisKey); 505 var json = Serialize(value); 506 return await _db.HashSetAsync(redisKey, hashField, json); 507 } 508 509 /// <summary> 510 /// 在 hash 中获取值(反序列化) 511 /// </summary> 512 /// <param name="redisKey"></param> 513 /// <param name="hashField"></param> 514 /// <returns></returns> 515 public async Task<T> HashGetAsync<T>(string redisKey, string hashField) 516 { 517 redisKey = AddKeyPrefix(redisKey); 518 return Deserialize<T>(await _db.HashGetAsync(redisKey, hashField)); 519 } 520 521 #endregion async 522 523 /// <summary> 524 /// 在 hash 中获取值(反序列化) 525 /// </summary> 526 /// <param name="redisKey"></param> 527 /// <param name="hashField"></param> 528 /// <returns></returns> 529 public HashEntry[] HashGetAll(string redisKey) 530 { 531 redisKey = AddKeyPrefix(redisKey); 532 return _db.HashGetAll(redisKey); 533 } 534 535 #endregion Hash 操作 536 537 #region List 操作 538 539 /// <summary> 540 /// 移除并返回存储在该键列表的第一个元素 541 /// </summary> 542 /// <param name="redisKey"></param> 543 /// <returns></returns> 544 public string ListLeftPop(string redisKey) 545 { 546 redisKey = AddKeyPrefix(redisKey); 547 return _db.ListLeftPop(redisKey); 548 } 549 550 /// <summary> 551 /// 移除并返回存储在该键列表的最后一个元素 552 /// </summary> 553 /// <param name="redisKey"></param> 554 /// <returns></returns> 555 public string ListRightPop(string redisKey) 556 { 557 redisKey = AddKeyPrefix(redisKey); 558 return _db.ListRightPop(redisKey); 559 } 560 561 /// <summary> 562 /// 移除列表指定键上与该值相同的元素 563 /// </summary> 564 /// <param name="redisKey"></param> 565 /// <param name="redisValue"></param> 566 /// <returns></returns> 567 public long ListRemove(string redisKey, string redisValue) 568 { 569 redisKey = AddKeyPrefix(redisKey); 570 return _db.ListRemove(redisKey, redisValue); 571 } 572 573 /// <summary> 574 /// 在列表尾部插入值。如果键不存在,先创建再插入值 575 /// </summary> 576 /// <param name="redisKey"></param> 577 /// <param name="redisValue"></param> 578 /// <returns></returns> 579 public long ListRightPush(string redisKey, string redisValue) 580 { 581 redisKey = AddKeyPrefix(redisKey); 582 return _db.ListRightPush(redisKey, redisValue); 583 } 584 585 /// <summary> 586 /// 在列表头部插入值。如果键不存在,先创建再插入值 587 /// </summary> 588 /// <param name="redisKey"></param> 589 /// <param name="redisValue"></param> 590 /// <returns></returns> 591 public long ListLeftPush(string redisKey, string redisValue) 592 { 593 redisKey = AddKeyPrefix(redisKey); 594 return _db.ListLeftPush(redisKey, redisValue); 595 } 596 597 /// <summary> 598 /// 返回列表上该键的长度,如果不存在,返回 0 599 /// </summary> 600 /// <param name="redisKey"></param> 601 /// <returns></returns> 602 public long ListLength(string redisKey) 603 { 604 redisKey = AddKeyPrefix(redisKey); 605 return _db.ListLength(redisKey); 606 } 607 608 /// <summary> 609 /// 返回在该列表上键所对应的元素 610 /// </summary> 611 /// <param name="redisKey"></param> 612 /// <returns></returns> 613 public IEnumerable<RedisValue> ListRange(string redisKey) 614 { 615 redisKey = AddKeyPrefix(redisKey); 616 return _db.ListRange(redisKey); 617 } 618 619 /// <summary> 620 /// 移除并返回存储在该键列表的第一个元素 621 /// </summary> 622 /// <param name="redisKey"></param> 623 /// <returns></returns> 624 public T ListLeftPop<T>(string redisKey) 625 { 626 redisKey = AddKeyPrefix(redisKey); 627 return Deserialize<T>(_db.ListLeftPop(redisKey)); 628 } 629 630 /// <summary> 631 /// 移除并返回存储在该键列表的最后一个元素 632 /// </summary> 633 /// <param name="redisKey"></param> 634 /// <returns></returns> 635 public T ListRightPop<T>(string redisKey) 636 { 637 redisKey = AddKeyPrefix(redisKey); 638 return Deserialize<T>(_db.ListRightPop(redisKey)); 639 } 640 641 /// <summary> 642 /// 在列表尾部插入值。如果键不存在,先创建再插入值 643 /// </summary> 644 /// <param name="redisKey"></param> 645 /// <param name="redisValue"></param> 646 /// <returns></returns> 647 public long ListRightPush<T>(string redisKey, T redisValue) 648 { 649 redisKey = AddKeyPrefix(redisKey); 650 return _db.ListRightPush(redisKey, Serialize(redisValue)); 651 } 652 653 /// <summary> 654 /// 在列表头部插入值。如果键不存在,先创建再插入值 655 /// </summary> 656 /// <param name="redisKey"></param> 657 /// <param name="redisValue"></param> 658 /// <returns></returns> 659 public long ListLeftPush<T>(string redisKey, T redisValue) 660 { 661 redisKey = AddKeyPrefix(redisKey); 662 return _db.ListLeftPush(redisKey, Serialize(redisValue)); 663 } 664 665 #region List-async 666 667 /// <summary> 668 /// 移除并返回存储在该键列表的第一个元素 669 /// </summary> 670 /// <param name="redisKey"></param> 671 /// <returns></returns> 672 public async Task<string> ListLeftPopAsync(string redisKey) 673 { 674 redisKey = AddKeyPrefix(redisKey); 675 return await _db.ListLeftPopAsync(redisKey); 676 } 677 678 /// <summary> 679 /// 移除并返回存储在该键列表的最后一个元素 680 /// </summary> 681 /// <param name="redisKey"></param> 682 /// <returns></returns> 683 public async Task<string> ListRightPopAsync(string redisKey) 684 { 685 redisKey = AddKeyPrefix(redisKey); 686 return await _db.ListRightPopAsync(redisKey); 687 } 688 689 /// <summary> 690 /// 移除列表指定键上与该值相同的元素 691 /// </summary> 692 /// <param name="redisKey"></param> 693 /// <param name="redisValue"></param> 694 /// <returns></returns> 695 public async Task<long> ListRemoveAsync(string redisKey, string redisValue) 696 { 697 redisKey = AddKeyPrefix(redisKey); 698 return await _db.ListRemoveAsync(redisKey, redisValue); 699 } 700 701 /// <summary> 702 /// 在列表尾部插入值。如果键不存在,先创建再插入值 703 /// </summary> 704 /// <param name="redisKey"></param> 705 /// <param name="redisValue"></param> 706 /// <returns></returns> 707 public async Task<long> ListRightPushAsync(string redisKey, string redisValue) 708 { 709 redisKey = AddKeyPrefix(redisKey); 710 return await _db.ListRightPushAsync(redisKey, redisValue); 711 } 712 713 /// <summary> 714 /// 在列表头部插入值。如果键不存在,先创建再插入值 715 /// </summary> 716 /// <param name="redisKey"></param> 717 /// <param name="redisValue"></param> 718 /// <returns></returns> 719 public async Task<long> ListLeftPushAsync(string redisKey, string redisValue) 720 { 721 redisKey = AddKeyPrefix(redisKey); 722 return await _db.ListLeftPushAsync(redisKey, redisValue); 723 } 724 725 /// <summary> 726 /// 返回列表上该键的长度,如果不存在,返回 0 727 /// </summary> 728 /// <param name="redisKey"></param> 729 /// <returns></returns> 730 public async Task<long> ListLengthAsync(string redisKey) 731 { 732 redisKey = AddKeyPrefix(redisKey); 733 return await _db.ListLengthAsync(redisKey); 734 } 735 736 /// <summary> 737 /// 返回在该列表上键所对应的元素 738 /// </summary> 739 /// <param name="redisKey"></param> 740 /// <returns></returns> 741 public async Task<IEnumerable<RedisValue>> ListRangeAsync(string redisKey) 742 { 743 redisKey = AddKeyPrefix(redisKey); 744 return await _db.ListRangeAsync(redisKey); 745 } 746 747 /// <summary> 748 /// 移除并返回存储在该键列表的第一个元素 749 /// </summary> 750 /// <param name="redisKey"></param> 751 /// <returns></returns> 752 public async Task<T> ListLeftPopAsync<T>(string redisKey) 753 { 754 redisKey = AddKeyPrefix(redisKey); 755 return Deserialize<T>(await _db.ListLeftPopAsync(redisKey)); 756 } 757 758 /// <summary> 759 /// 移除并返回存储在该键列表的最后一个元素 760 /// </summary> 761 /// <param name="redisKey"></param> 762 /// <returns></returns> 763 public async Task<T> ListRightPopAsync<T>(string redisKey) 764 { 765 redisKey = AddKeyPrefix(redisKey); 766 return Deserialize<T>(await _db.ListRightPopAsync(redisKey)); 767 } 768 769 /// <summary> 770 /// 在列表尾部插入值。如果键不存在,先创建再插入值 771 /// </summary> 772 /// <param name="redisKey"></param> 773 /// <param name="redisValue"></param> 774 /// <returns></returns> 775 public async Task<long> ListRightPushAsync<T>(string redisKey, T redisValue) 776 { 777 redisKey = AddKeyPrefix(redisKey); 778 return await _db.ListRightPushAsync(redisKey, Serialize(redisValue)); 779 } 780 781 /// <summary> 782 /// 在列表头部插入值。如果键不存在,先创建再插入值 783 /// </summary> 784 /// <param name="redisKey"></param> 785 /// <param name="redisValue"></param> 786 /// <returns></returns> 787 public async Task<long> ListLeftPushAsync<T>(string redisKey, T redisValue) 788 { 789 redisKey = AddKeyPrefix(redisKey); 790 return await _db.ListLeftPushAsync(redisKey, Serialize(redisValue)); 791 } 792 793 #endregion List-async 794 795 #endregion List 操作 796 797 #region SortedSet 操作 798 799 /// <summary> 800 /// SortedSet 新增 801 /// </summary> 802 /// <param name="redisKey"></param> 803 /// <param name="member"></param> 804 /// <param name="score"></param> 805 /// <returns></returns> 806 public bool SortedSetAdd(string redisKey, string member, double score) 807 { 808 redisKey = AddKeyPrefix(redisKey); 809 return _db.SortedSetAdd(redisKey, member, score); 810 } 811 812 /// <summary> 813 /// 在有序集合中返回指定范围的元素,默认情况下从低到高。 814 /// </summary> 815 /// <param name="redisKey"></param> 816 /// <returns></returns> 817 public IEnumerable<RedisValue> SortedSetRangeByRank(string redisKey) 818 { 819 redisKey = AddKeyPrefix(redisKey); 820 return _db.SortedSetRangeByRank(redisKey); 821 } 822 823 /// <summary> 824 /// 返回有序集合的元素个数 825 /// </summary> 826 /// <param name="redisKey"></param> 827 /// <returns></returns> 828 public long SortedSetLength(string redisKey) 829 { 830 redisKey = AddKeyPrefix(redisKey); 831 return _db.SortedSetLength(redisKey); 832 } 833 834 /// <summary> 835 /// 返回有序集合的元素个数 836 /// </summary> 837 /// <param name="redisKey"></param> 838 /// <param name="memebr"></param> 839 /// <returns></returns> 840 public bool SortedSetLength(string redisKey, string memebr) 841 { 842 redisKey = AddKeyPrefix(redisKey); 843 return _db.SortedSetRemove(redisKey, memebr); 844 } 845 846 /// <summary> 847 /// SortedSet 新增 848 /// </summary> 849 /// <param name="redisKey"></param> 850 /// <param name="member"></param> 851 /// <param name="score"></param> 852 /// <returns></returns> 853 public bool SortedSetAdd<T>(string redisKey, T member, double score) 854 { 855 redisKey = AddKeyPrefix(redisKey); 856 var json = Serialize(member); 857 858 return _db.SortedSetAdd(redisKey, json, score); 859 } 860 861 #region SortedSet-Async 862 863 /// <summary> 864 /// SortedSet 新增 865 /// </summary> 866 /// <param name="redisKey"></param> 867 /// <param name="member"></param> 868 /// <param name="score"></param> 869 /// <returns></returns> 870 public async Task<bool> SortedSetAddAsync(string redisKey, string member, double score) 871 { 872 redisKey = AddKeyPrefix(redisKey); 873 return await _db.SortedSetAddAsync(redisKey, member, score); 874 } 875 876 /// <summary> 877 /// 在有序集合中返回指定范围的元素,默认情况下从低到高。 878 /// </summary> 879 /// <param name="redisKey"></param> 880 /// <returns></returns> 881 public async Task<IEnumerable<RedisValue>> SortedSetRangeByRankAsync(string redisKey) 882 { 883 redisKey = AddKeyPrefix(redisKey); 884 return await _db.SortedSetRangeByRankAsync(redisKey); 885 } 886 887 /// <summary> 888 /// 返回有序集合的元素个数 889 /// </summary> 890 /// <param name="redisKey"></param> 891 /// <returns></returns> 892 public async Task<long> SortedSetLengthAsync(string redisKey) 893 { 894 redisKey = AddKeyPrefix(redisKey); 895 return await _db.SortedSetLengthAsync(redisKey); 896 } 897 898 /// <summary> 899 /// 返回有序集合的元素个数 900 /// </summary> 901 /// <param name="redisKey"></param> 902 /// <param name="memebr"></param> 903 /// <returns></returns> 904 public async Task<bool> SortedSetRemoveAsync(string redisKey, string memebr) 905 { 906 redisKey = AddKeyPrefix(redisKey); 907 return await _db.SortedSetRemoveAsync(redisKey, memebr); 908 } 909 910 /// <summary> 911 /// SortedSet 新增 912 /// </summary> 913 /// <param name="redisKey"></param> 914 /// <param name="member"></param> 915 /// <param name="score"></param> 916 /// <returns></returns> 917 public async Task<bool> SortedSetAddAsync<T>(string redisKey, T member, double score) 918 { 919 redisKey = AddKeyPrefix(redisKey); 920 var json = Serialize(member); 921 922 return await _db.SortedSetAddAsync(redisKey, json, score); 923 } 924 925 #endregion SortedSet-Async 926 927 #endregion SortedSet 操作 928 929 #region key 操作 930 931 /// <summary> 932 /// 移除指定 Key 933 /// </summary> 934 /// <param name="redisKey"></param> 935 /// <returns></returns> 936 public bool KeyDelete(string redisKey) 937 { 938 redisKey = AddKeyPrefix(redisKey); 939 return _db.KeyDelete(redisKey); 940 } 941 942 /// <summary> 943 /// 移除指定 Key 944 /// </summary> 945 /// <param name="redisKeys"></param> 946 /// <returns></returns> 947 public long KeyDelete(IEnumerable<string> redisKeys) 948 { 949 var keys = redisKeys.Select(x => (RedisKey)AddKeyPrefix(x)); 950 return _db.KeyDelete(keys.ToArray()); 951 } 952 953 /// <summary> 954 /// 校验 Key 是否存在 955 /// </summary> 956 /// <param name="redisKey"></param> 957 /// <returns></returns> 958 public bool KeyExists(string redisKey) 959 { 960 redisKey = AddKeyPrefix(redisKey); 961 return _db.KeyExists(redisKey); 962 } 963 964 /// <summary> 965 /// 重命名 Key 966 /// </summary> 967 /// <param name="redisKey"></param> 968 /// <param name="redisNewKey"></param> 969 /// <returns></returns> 970 public bool KeyRename(string redisKey, string redisNewKey) 971 { 972 redisKey = AddKeyPrefix(redisKey); 973 return _db.KeyRename(redisKey, redisNewKey); 974 } 975 976 /// <summary> 977 /// 设置 Key 的时间 978 /// </summary> 979 /// <param name="redisKey"></param> 980 /// <param name="expiry"></param> 981 /// <returns></returns> 982 public bool KeyExpire(string redisKey, TimeSpan? expiry) 983 { 984 redisKey = AddKeyPrefix(redisKey); 985 return _db.KeyExpire(redisKey, expiry); 986 } 987 988 /// <summary> 989 /// Get all keys by wildcard 990 /// </summary> 991 /// <param name="pattern"></param> 992 /// <returns></returns> 993 public List<string> Keys(string pattern) 994 { 995 //var endPoint = _connMultiplexer.GetEndPoints()[0]; 996 //IServer _server = _connMultiplexer.GetServer(endPoint); //默认一个服务器 997 //var keys = _server.Keys(database: _db.Database, pattern: pattern); //StackExchange.Redis 会根据redis版本决定用keys还是 scan 998 //return keys; 999 pattern = AddKeyPrefix(pattern); 1000 var redisResult = _db.ScriptEvaluate(LuaScript.Prepare( 1001 " local res=redis.call('KEYS',@keypattern) " + 1002 " return res "), new { @keypattern = pattern }); 1003 if (redisResult == null) return null; 1004 1005 var keys = (string[])redisResult;//Morningstar.Appointment.Dev:CSM:WDA-07171 1006 var list = new List<string>(); 1007 foreach (var item in keys) 1008 { 1009 list.Add(item.Split(DefaultKey + ":")[1]); 1010 } 1011 return list; 1012 } 1013 1014 #region key-async 1015 1016 /// <summary> 1017 /// 移除指定 Key 1018 /// </summary> 1019 /// <param name="redisKey"></param> 1020 /// <returns></returns> 1021 public async Task<bool> KeyDeleteAsync(string redisKey) 1022 { 1023 redisKey = AddKeyPrefix(redisKey); 1024 return await _db.KeyDeleteAsync(redisKey); 1025 } 1026 1027 /// <summary> 1028 /// 移除指定 Key 1029 /// </summary> 1030 /// <param name="redisKeys"></param> 1031 /// <returns></returns> 1032 public async Task<long> KeyDeleteAsync(IEnumerable<string> redisKeys) 1033 { 1034 var keys = redisKeys.Select(x => (RedisKey)AddKeyPrefix(x)); 1035 return await _db.KeyDeleteAsync(keys.ToArray()); 1036 } 1037 1038 /// <summary> 1039 /// 校验 Key 是否存在 1040 /// </summary> 1041 /// <param name="redisKey"></param> 1042 /// <returns></returns> 1043 public async Task<bool> KeyExistsAsync(string redisKey) 1044 { 1045 redisKey = AddKeyPrefix(redisKey); 1046 return await _db.KeyExistsAsync(redisKey); 1047 } 1048 1049 /// <summary> 1050 /// 重命名 Key 1051 /// </summary> 1052 /// <param name="redisKey"></param> 1053 /// <param name="redisNewKey"></param> 1054 /// <returns></returns> 1055 public async Task<bool> KeyRenameAsync(string redisKey, string redisNewKey) 1056 { 1057 redisKey = AddKeyPrefix(redisKey); 1058 return await _db.KeyRenameAsync(redisKey, redisNewKey); 1059 } 1060 1061 /// <summary> 1062 /// 设置 Key 的时间 1063 /// </summary> 1064 /// <param name="redisKey"></param> 1065 /// <param name="expiry"></param> 1066 /// <returns></returns> 1067 public async Task<bool> KeyExpireAsync(string redisKey, TimeSpan? expiry) 1068 { 1069 redisKey = AddKeyPrefix(redisKey); 1070 return await _db.KeyExpireAsync(redisKey, expiry); 1071 } 1072 1073 #endregion key-async 1074 1075 #endregion key 操作 1076 1077 #region 发布订阅 1078 1079 /// <summary> 1080 /// 订阅 1081 /// </summary> 1082 /// <param name="channel"></param> 1083 /// <param name="handle"></param> 1084 public void Subscribe(RedisChannel channel, Action<RedisChannel, RedisValue> handle) 1085 { 1086 var sub = _connMultiplexer.GetSubscriber(); 1087 sub.Subscribe(channel, handle); 1088 } 1089 1090 /// <summary> 1091 /// 发布 1092 /// </summary> 1093 /// <param name="channel"></param> 1094 /// <param name="message"></param> 1095 /// <returns></returns> 1096 public long Publish(RedisChannel channel, RedisValue message) 1097 { 1098 var sub = _connMultiplexer.GetSubscriber(); 1099 return sub.Publish(channel, message); 1100 } 1101 1102 /// <summary> 1103 /// 发布(使用序列化) 1104 /// </summary> 1105 /// <typeparam name="T"></typeparam> 1106 /// <param name="channel"></param> 1107 /// <param name="message"></param> 1108 /// <returns></returns> 1109 public long Publish<T>(RedisChannel channel, T message) 1110 { 1111 var sub = _connMultiplexer.GetSubscriber(); 1112 return sub.Publish(channel, Serialize(message)); 1113 } 1114 1115 #region 发布订阅-async 1116 1117 /// <summary> 1118 /// 订阅 1119 /// </summary> 1120 /// <param name="channel"></param> 1121 /// <param name="handle"></param> 1122 public async Task SubscribeAsync(RedisChannel channel, Action<RedisChannel, RedisValue> handle) 1123 { 1124 var sub = _connMultiplexer.GetSubscriber(); 1125 await sub.SubscribeAsync(channel, handle); 1126 } 1127 1128 /// <summary> 1129 /// 发布 1130 /// </summary> 1131 /// <param name="channel"></param> 1132 /// <param name="message"></param> 1133 /// <returns></returns> 1134 public async Task<long> PublishAsync(RedisChannel channel, RedisValue message) 1135 { 1136 var sub = _connMultiplexer.GetSubscriber(); 1137 return await sub.PublishAsync(channel, message); 1138 } 1139 1140 /// <summary> 1141 /// 发布(使用序列化) 1142 /// </summary> 1143 /// <typeparam name="T"></typeparam> 1144 /// <param name="channel"></param> 1145 /// <param name="message"></param> 1146 /// <returns></returns> 1147 public async Task<long> PublishAsync<T>(RedisChannel channel, T message) 1148 { 1149 var sub = _connMultiplexer.GetSubscriber(); 1150 return await sub.PublishAsync(channel, Serialize(message)); 1151 } 1152 1153 #endregion 发布订阅-async 1154 1155 #endregion 发布订阅 1156 1157 #region private method 1158 1159 /// <summary> 1160 /// 添加 Key 的前缀 1161 /// </summary> 1162 /// <param name="key"></param> 1163 /// <returns></returns> 1164 private static string AddKeyPrefix(string key) 1165 { 1166 return $"{DefaultKey}:{key}"; 1167 } 1168 1169 #region 注册事件 1170 1171 /// <summary> 1172 /// 添加注册事件 1173 /// </summary> 1174 private static void AddRegisterEvent() 1175 { 1176 _connMultiplexer.ConnectionRestored += ConnMultiplexer_ConnectionRestored; 1177 _connMultiplexer.ConnectionFailed += ConnMultiplexer_ConnectionFailed; 1178 _connMultiplexer.ErrorMessage += ConnMultiplexer_ErrorMessage; 1179 _connMultiplexer.ConfigurationChanged += ConnMultiplexer_ConfigurationChanged; 1180 _connMultiplexer.HashSlotMoved += ConnMultiplexer_HashSlotMoved; 1181 _connMultiplexer.InternalError += ConnMultiplexer_InternalError; 1182 _connMultiplexer.ConfigurationChangedBroadcast += ConnMultiplexer_ConfigurationChangedBroadcast; 1183 } 1184 1185 /// <summary> 1186 /// 重新配置广播时(通常意味着主从同步更改) 1187 /// </summary> 1188 /// <param name="sender"></param> 1189 /// <param name="e"></param> 1190 private static void ConnMultiplexer_ConfigurationChangedBroadcast(object sender, EndPointEventArgs e) 1191 { 1192 Console.WriteLine($"{nameof(ConnMultiplexer_ConfigurationChangedBroadcast)}: {e.EndPoint}"); 1193 } 1194 1195 /// <summary> 1196 /// 发生内部错误时(主要用于调试) 1197 /// </summary> 1198 /// <param name="sender"></param> 1199 /// <param name="e"></param> 1200 private static void ConnMultiplexer_InternalError(object sender, InternalErrorEventArgs e) 1201 { 1202 Console.WriteLine($"{nameof(ConnMultiplexer_InternalError)}: {e.Exception}"); 1203 } 1204 1205 /// <summary> 1206 /// 更改集群时 1207 /// </summary> 1208 /// <param name="sender"></param> 1209 /// <param name="e"></param> 1210 private static void ConnMultiplexer_HashSlotMoved(object sender, HashSlotMovedEventArgs e) 1211 { 1212 Console.WriteLine( 1213 $"{nameof(ConnMultiplexer_HashSlotMoved)}: {nameof(e.OldEndPoint)}-{e.OldEndPoint} To {nameof(e.NewEndPoint)}-{e.NewEndPoint}, "); 1214 } 1215 1216 /// <summary> 1217 /// 配置更改时 1218 /// </summary> 1219 /// <param name="sender"></param> 1220 /// <param name="e"></param> 1221 private static void ConnMultiplexer_ConfigurationChanged(object sender, EndPointEventArgs e) 1222 { 1223 Console.WriteLine($"{nameof(ConnMultiplexer_ConfigurationChanged)}: {e.EndPoint}"); 1224 } 1225 1226 /// <summary> 1227 /// 发生错误时 1228 /// </summary> 1229 /// <param name="sender"></param> 1230 /// <param name="e"></param> 1231 private static void ConnMultiplexer_ErrorMessage(object sender, RedisErrorEventArgs e) 1232 { 1233 Console.WriteLine($"{nameof(ConnMultiplexer_ErrorMessage)}: {e.Message}"); 1234 } 1235 1236 /// <summary> 1237 /// 物理连接失败时 1238 /// </summary> 1239 /// <param name="sender"></param> 1240 /// <param name="e"></param> 1241 private static void ConnMultiplexer_ConnectionFailed(object sender, ConnectionFailedEventArgs e) 1242 { 1243 Console.WriteLine($"{nameof(ConnMultiplexer_ConnectionFailed)}: {e.Exception}"); 1244 } 1245 1246 /// <summary> 1247 /// 建立物理连接时 1248 /// </summary> 1249 /// <param name="sender"></param> 1250 /// <param name="e"></param> 1251 private static void ConnMultiplexer_ConnectionRestored(object sender, ConnectionFailedEventArgs e) 1252 { 1253 Console.WriteLine($"{nameof(ConnMultiplexer_ConnectionRestored)}: {e.Exception}"); 1254 } 1255 1256 #endregion 注册事件 1257 1258 /// <summary> 1259 /// 序列化 1260 /// </summary> 1261 /// <param name="obj"></param> 1262 /// <returns></returns> 1263 private static byte[] Serialize(object obj) 1264 { 1265 if (obj == null) 1266 return null; 1267 1268 var binaryFormatter = new BinaryFormatter(); 1269 using (var memoryStream = new MemoryStream()) 1270 { 1271 binaryFormatter.Serialize(memoryStream, obj); 1272 var data = memoryStream.ToArray(); 1273 return data; 1274 } 1275 } 1276 1277 /// <summary> 1278 /// 反序列化 1279 /// </summary> 1280 /// <typeparam name="T"></typeparam> 1281 /// <param name="data"></param> 1282 /// <returns></returns> 1283 private static T Deserialize<T>(byte[] data) 1284 { 1285 if (data == null) 1286 return default(T); 1287 1288 var binaryFormatter = new BinaryFormatter(); 1289 using (var memoryStream = new MemoryStream(data)) 1290 { 1291 var result = (T)binaryFormatter.Deserialize(memoryStream); 1292 return result; 1293 } 1294 } 1295 1296 #endregion private method 1297 } 1298 }
2,appsettings.json

1 { 2 "Redis": { 3 "ConnectionStrings": "127.0.0.1:6379,password=ms.corpqa.interviewscheduling", 4 "DefaultKey": "Morningstar.InterviewScheduling.Dev", 5 "ServiceName": "mymaster", 6 "Password": "ms.corpqa.interviewscheduling", 7 "Sentinel": [ 8 "127.0.0.1:26379", 9 "127.0.0.1:26380", 10 "127.0.0.1:26381" 11 ] 12 }, 13 "ExpireDays": 7, //the unit is day 14 "HttpProxyConfig": { 15 "UseProxy": "true", 16 "ProxyHost": "172.28.104.174", 17 "ProxyPort": "8080" 18 } 19 }
注:StackExchange.Redis请使用最新版本,以上代码使用的是2.2.4版本。
三,.NET Core 项目中使用
四,Windows上安装Redis服务

1 redis-server --service-install redis.windows.conf --server-name redis-6379 --loglevel verbose 2 最后的参数 --loglevel verbose表示记录日志等级 3 4 卸载服务:redis-server --service-uninstall 5 6 开启服务:redis-server --service-start 7 8 停止服务:redis-server --service-stop 9 10 重命名服务:redis-server --service-name name 11 12 13 以下将会安装并启动三个不同的Redis实例作服务: 14 15 redis-server --service-install --service-name redisService1 --port 10001 16 17 redis-server --service-start --service-name redisService1 18 19 redis-server --service-install --service-name redisService2 --port 10002 20 21 redis-server --service-start --service-name redisService2 22 23 redis-server --service-install --service-name redisService3 --port 10003 24 25 redis-server --service-start --service-name redisService3