Windows下Redis哨兵模式配置以及在.NetCore中使用StackExchange.Redis连接哨兵
一,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 ///RedisHelper.cs13 /// Redis 助手 14 /// 15 public class RedisHelper 16 { 17 /// 18 /// 连接字符串 19 /// 20 private static readonly string ConnectionString; 21 22 /// 23 /// redis 连接对象 24 /// 25 private static IConnectionMultiplexer _connMultiplexer; 26 27 /// 28 /// 默认的 Key 值(用来当作 RedisKey 的前缀) 29 /// 30 private static readonly string DefaultKey; 31 32 /// 33 /// 锁 34 /// 35 private static readonly object Locker = new object(); 36 37 /// 38 /// 数据库 39 /// 40 private readonly IDatabase _db; 41 42 /// 43 /// 获取 Redis 连接对象 44 /// 45 /// 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 /// 119 /// 设置 key 并保存字符串(如果 key 已存在,则覆盖值) 120 /// 121 /// 122 /// 123 /// 124 /// 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 /// 132 /// 保存多个 Key-value 133 /// 134 /// 135 /// 136 public bool StringSet(IEnumerable > keyValuePairs) 137 { 138 keyValuePairs = 139 keyValuePairs.Select(x => new KeyValuePair (AddKeyPrefix(x.Key), x.Value)); 140 return _db.StringSet(keyValuePairs.ToArray()); 141 } 142 143 /// 144 /// 获取字符串 145 /// 146 /// 147 /// 148 /// 149 public string StringGet(string redisKey, TimeSpan? expiry = null) 150 { 151 redisKey = AddKeyPrefix(redisKey); 152 return _db.StringGet(redisKey); 153 } 154 155 /// 156 /// 存储一个对象(该对象会被序列化保存) 157 /// 158 /// 159 /// 160 /// 161 /// 162 public bool StringSet (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 /// 170 /// 获取一个对象(会进行反序列化) 171 /// 172 /// 173 /// 174 /// 175 public T StringGet (string redisKey, TimeSpan? expiry = null) 176 { 177 redisKey = AddKeyPrefix(redisKey); 178 return Deserialize (_db.StringGet(redisKey)); 179 } 180 181 #region async 182 183 /// 184 /// 保存一个字符串值 185 /// 186 /// 187 /// 188 /// 189 /// 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 /// 197 /// 保存一组字符串值 198 /// 199 /// 200 /// 201 public async Task<bool> StringSetAsync(IEnumerable > keyValuePairs) 202 { 203 keyValuePairs = 204 keyValuePairs.Select(x => new KeyValuePair (AddKeyPrefix(x.Key), x.Value)); 205 return await _db.StringSetAsync(keyValuePairs.ToArray()); 206 } 207 208 /// 209 /// 获取单个值 210 /// 211 /// 212 /// 213 /// 214 /// 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 /// 222 /// 存储一个对象(该对象会被序列化保存) 223 /// 224 /// 225 /// 226 /// 227 /// 228 public async Task<bool> StringSetAsync (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 /// 236 /// 获取一个对象(会进行反序列化) 237 /// 238 /// 239 /// 240 /// 241 public async Task StringGetAsync (string redisKey, TimeSpan? expiry = null) 242 { 243 redisKey = AddKeyPrefix(redisKey); 244 return Deserialize (await _db.StringGetAsync(redisKey)); 245 } 246 247 #endregion async 248 249 #endregion String 操作 250 251 #region Hash 操作 252 253 /// 254 /// 判断该字段是否存在 hash 中 255 /// 256 /// 257 /// 258 /// 259 public bool HashExists(string redisKey, string hashField) 260 { 261 redisKey = AddKeyPrefix(redisKey); 262 return _db.HashExists(redisKey, hashField); 263 } 264 265 /// 266 /// 从 hash 中移除指定字段 267 /// 268 /// 269 /// 270 /// 271 public bool HashDelete(string redisKey, string hashField) 272 { 273 redisKey = AddKeyPrefix(redisKey); 274 return _db.HashDelete(redisKey, hashField); 275 } 276 277 /// 278 /// 从 hash 中移除指定字段 279 /// 280 /// 281 /// 282 /// 283 public long HashDelete(string redisKey, IEnumerable hashField) 284 { 285 redisKey = AddKeyPrefix(redisKey); 286 return _db.HashDelete(redisKey, hashField.ToArray()); 287 } 288 289 /// 290 /// 在 hash 设定值 291 /// 292 /// 293 /// 294 /// 295 /// 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 /// 303 /// 在 hash 中设定值 304 /// 305 /// 306 /// 307 public void HashSet(string redisKey, IEnumerable hashFields) 308 { 309 redisKey = AddKeyPrefix(redisKey); 310 _db.HashSet(redisKey, hashFields.ToArray()); 311 } 312 313 /// 314 /// 在 hash 中获取值 315 /// 316 /// 317 /// 318 /// 319 public RedisValue HashGet(string redisKey, string hashField) 320 { 321 redisKey = AddKeyPrefix(redisKey); 322 return _db.HashGet(redisKey, hashField); 323 } 324 325 /// 326 /// 在 hash 中获取值 327 /// 328 /// 329 /// 330 /// 331 /// 332 public RedisValue[] HashGet(string redisKey, RedisValue[] hashField, string value) 333 { 334 redisKey = AddKeyPrefix(redisKey); 335 return _db.HashGet(redisKey, hashField); 336 } 337 338 /// 339 /// 从 hash 返回所有的字段值 340 /// 341 /// 342 /// 343 public IEnumerable HashKeys(string redisKey) 344 { 345 redisKey = AddKeyPrefix(redisKey); 346 return _db.HashKeys(redisKey); 347 } 348 349 /// 350 /// 返回 hash 中的所有值 351 /// 352 /// 353 /// 354 public RedisValue[] HashValues(string redisKey) 355 { 356 redisKey = AddKeyPrefix(redisKey); 357 return _db.HashValues(redisKey); 358 } 359 360 /// 361 /// 在 hash 设定值(序列化) 362 /// 363 /// 364 /// 365 /// 366 /// 367 public bool HashSet (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 /// 375 /// 在 hash 中获取值(反序列化) 376 /// 377 /// 378 /// 379 /// 380 public T HashGet (string redisKey, string hashField) 381 { 382 redisKey = AddKeyPrefix(redisKey); 383 return Deserialize (_db.HashGet(redisKey, hashField)); 384 } 385 386 #region async 387 388 /// 389 /// 判断该字段是否存在 hash 中 390 /// 391 /// 392 /// 393 /// 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 /// 401 /// 从 hash 中移除指定字段 402 /// 403 /// 404 /// 405 /// 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 /// 413 /// 从 hash 中移除指定字段 414 /// 415 /// 416 /// 417 /// 418 public async Task<long> HashDeleteAsync(string redisKey, IEnumerable hashField) 419 { 420 redisKey = AddKeyPrefix(redisKey); 421 return await _db.HashDeleteAsync(redisKey, hashField.ToArray()); 422 } 423 424 /// 425 /// 在 hash 设定值 426 /// 427 /// 428 /// 429 /// 430 /// 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 /// 438 /// 在 hash 中设定值 439 /// 440 /// 441 /// 442 public async Task HashSetAsync(string redisKey, IEnumerable hashFields) 443 { 444 redisKey = AddKeyPrefix(redisKey); 445 await _db.HashSetAsync(redisKey, hashFields.ToArray()); 446 } 447 448 /// 449 /// 在 hash 中获取值 450 /// 451 /// 452 /// 453 /// 454 public async Task HashGetAsync(string redisKey, string hashField) 455 { 456 redisKey = AddKeyPrefix(redisKey); 457 return await _db.HashGetAsync(redisKey, hashField); 458 } 459 460 /// 461 /// 在 hash 中获取值 462 /// 463 /// 464 /// 465 /// 466 /// 467 public async Task > HashGetAsync(string redisKey, RedisValue[] hashField, string value) 468 { 469 redisKey = AddKeyPrefix(redisKey); 470 return await _db.HashGetAsync(redisKey, hashField); 471 } 472 473 /// 474 /// 从 hash 返回所有的字段值 475 /// 476 /// 477 /// 478 public async Task > HashKeysAsync(string redisKey) 479 { 480 redisKey = AddKeyPrefix(redisKey); 481 return await _db.HashKeysAsync(redisKey); 482 } 483 484 /// 485 /// 返回 hash 中的所有值 486 /// 487 /// 488 /// 489 public async Task > HashValuesAsync(string redisKey) 490 { 491 redisKey = AddKeyPrefix(redisKey); 492 return await _db.HashValuesAsync(redisKey); 493 } 494 495 /// 496 /// 在 hash 设定值(序列化) 497 /// 498 /// 499 /// 500 /// 501 /// 502 public async Task<bool> HashSetAsync (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 /// 510 /// 在 hash 中获取值(反序列化) 511 /// 512 /// 513 /// 514 /// 515 public async Task HashGetAsync (string redisKey, string hashField) 516 { 517 redisKey = AddKeyPrefix(redisKey); 518 return Deserialize (await _db.HashGetAsync(redisKey, hashField)); 519 } 520 521 #endregion async 522 523 /// 524 /// 在 hash 中获取值(反序列化) 525 /// 526 /// 527 /// 528 /// 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 /// 540 /// 移除并返回存储在该键列表的第一个元素 541 /// 542 /// 543 /// 544 public string ListLeftPop(string redisKey) 545 { 546 redisKey = AddKeyPrefix(redisKey); 547 return _db.ListLeftPop(redisKey); 548 } 549 550 /// 551 /// 移除并返回存储在该键列表的最后一个元素 552 /// 553 /// 554 /// 555 public string ListRightPop(string redisKey) 556 { 557 redisKey = AddKeyPrefix(redisKey); 558 return _db.ListRightPop(redisKey); 559 } 560 561 /// 562 /// 移除列表指定键上与该值相同的元素 563 /// 564 /// 565 /// 566 /// 567 public long ListRemove(string redisKey, string redisValue) 568 { 569 redisKey = AddKeyPrefix(redisKey); 570 return _db.ListRemove(redisKey, redisValue); 571 } 572 573 /// 574 /// 在列表尾部插入值。如果键不存在,先创建再插入值 575 /// 576 /// 577 /// 578 /// 579 public long ListRightPush(string redisKey, string redisValue) 580 { 581 redisKey = AddKeyPrefix(redisKey); 582 return _db.ListRightPush(redisKey, redisValue); 583 } 584 585 /// 586 /// 在列表头部插入值。如果键不存在,先创建再插入值 587 /// 588 /// 589 /// 590 /// 591 public long ListLeftPush(string redisKey, string redisValue) 592 { 593 redisKey = AddKeyPrefix(redisKey); 594 return _db.ListLeftPush(redisKey, redisValue); 595 } 596 597 /// 598 /// 返回列表上该键的长度,如果不存在,返回 0 599 /// 600 /// 601 /// 602 public long ListLength(string redisKey) 603 { 604 redisKey = AddKeyPrefix(redisKey); 605 return _db.ListLength(redisKey); 606 } 607 608 /// 609 /// 返回在该列表上键所对应的元素 610 /// 611 /// 612 /// 613 public IEnumerable ListRange(string redisKey) 614 { 615 redisKey = AddKeyPrefix(redisKey); 616 return _db.ListRange(redisKey); 617 } 618 619 /// 620 /// 移除并返回存储在该键列表的第一个元素 621 /// 622 /// 623 /// 624 public T ListLeftPop (string redisKey) 625 { 626 redisKey = AddKeyPrefix(redisKey); 627 return Deserialize (_db.ListLeftPop(redisKey)); 628 } 629 630 /// 631 /// 移除并返回存储在该键列表的最后一个元素 632 /// 633 /// 634 /// 635 public T ListRightPop (string redisKey) 636 { 637 redisKey = AddKeyPrefix(redisKey); 638 return Deserialize (_db.ListRightPop(redisKey)); 639 } 640 641 /// 642 /// 在列表尾部插入值。如果键不存在,先创建再插入值 643 /// 644 /// 645 /// 646 /// 647 public long ListRightPush (string redisKey, T redisValue) 648 { 649 redisKey = AddKeyPrefix(redisKey); 650 return _db.ListRightPush(redisKey, Serialize(redisValue)); 651 } 652 653 /// 654 /// 在列表头部插入值。如果键不存在,先创建再插入值 655 /// 656 /// 657 /// 658 /// 659 public long ListLeftPush (string redisKey, T redisValue) 660 { 661 redisKey = AddKeyPrefix(redisKey); 662 return _db.ListLeftPush(redisKey, Serialize(redisValue)); 663 } 664 665 #region List-async 666 667 /// 668 /// 移除并返回存储在该键列表的第一个元素 669 /// 670 /// 671 /// 672 public async Task<string> ListLeftPopAsync(string redisKey) 673 { 674 redisKey = AddKeyPrefix(redisKey); 675 return await _db.ListLeftPopAsync(redisKey); 676 } 677 678 /// 679 /// 移除并返回存储在该键列表的最后一个元素 680 /// 681 /// 682 /// 683 public async Task<string> ListRightPopAsync(string redisKey) 684 { 685 redisKey = AddKeyPrefix(redisKey); 686 return await _db.ListRightPopAsync(redisKey); 687 } 688 689 /// 690 /// 移除列表指定键上与该值相同的元素 691 /// 692 /// 693 /// 694 /// 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 /// 702 /// 在列表尾部插入值。如果键不存在,先创建再插入值 703 /// 704 /// 705 /// 706 /// 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 /// 714 /// 在列表头部插入值。如果键不存在,先创建再插入值 715 /// 716 /// 717 /// 718 /// 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 /// 726 /// 返回列表上该键的长度,如果不存在,返回 0 727 /// 728 /// 729 /// 730 public async Task<long> ListLengthAsync(string redisKey) 731 { 732 redisKey = AddKeyPrefix(redisKey); 733 return await _db.ListLengthAsync(redisKey); 734 } 735 736 /// 737 /// 返回在该列表上键所对应的元素 738 /// 739 /// 740 /// 741 public async Task > ListRangeAsync(string redisKey) 742 { 743 redisKey = AddKeyPrefix(redisKey); 744 return await _db.ListRangeAsync(redisKey); 745 } 746 747 /// 748 /// 移除并返回存储在该键列表的第一个元素 749 /// 750 /// 751 /// 752 public async Task ListLeftPopAsync (string redisKey) 753 { 754 redisKey = AddKeyPrefix(redisKey); 755 return Deserialize (await _db.ListLeftPopAsync(redisKey)); 756 } 757 758 /// 759 /// 移除并返回存储在该键列表的最后一个元素 760 /// 761 /// 762 /// 763 public async Task ListRightPopAsync (string redisKey) 764 { 765 redisKey = AddKeyPrefix(redisKey); 766 return Deserialize (await _db.ListRightPopAsync(redisKey)); 767 } 768 769 /// 770 /// 在列表尾部插入值。如果键不存在,先创建再插入值 771 /// 772 /// 773 /// 774 /// 775 public async Task<long> ListRightPushAsync (string redisKey, T redisValue) 776 { 777 redisKey = AddKeyPrefix(redisKey); 778 return await _db.ListRightPushAsync(redisKey, Serialize(redisValue)); 779 } 780 781 /// 782 /// 在列表头部插入值。如果键不存在,先创建再插入值 783 /// 784 /// 785 /// 786 /// 787 public async Task<long> ListLeftPushAsync (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 /// 800 /// SortedSet 新增 801 /// 802 /// 803 /// 804 /// 805 /// 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 /// 813 /// 在有序集合中返回指定范围的元素,默认情况下从低到高。 814 /// 815 /// 816 /// 817 public IEnumerable SortedSetRangeByRank(string redisKey) 818 { 819 redisKey = AddKeyPrefix(redisKey); 820 return _db.SortedSetRangeByRank(redisKey); 821 } 822 823 /// 824 /// 返回有序集合的元素个数 825 /// 826 /// 827 /// 828 public long SortedSetLength(string redisKey) 829 { 830 redisKey = AddKeyPrefix(redisKey); 831 return _db.SortedSetLength(redisKey); 832 } 833 834 /// 835 /// 返回有序集合的元素个数 836 /// 837 /// 838 /// 839 /// 840 public bool SortedSetLength(string redisKey, string memebr) 841 { 842 redisKey = AddKeyPrefix(redisKey); 843 return _db.SortedSetRemove(redisKey, memebr); 844 } 845 846 /// 847 /// SortedSet 新增 848 /// 849 /// 850 /// 851 /// 852 /// 853 public bool SortedSetAdd (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 /// 864 /// SortedSet 新增 865 /// 866 /// 867 /// 868 /// 869 /// 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 /// 877 /// 在有序集合中返回指定范围的元素,默认情况下从低到高。 878 /// 879 /// 880 /// 881 public async Task > SortedSetRangeByRankAsync(string redisKey) 882 { 883 redisKey = AddKeyPrefix(redisKey); 884 return await _db.SortedSetRangeByRankAsync(redisKey); 885 } 886 887 /// 888 /// 返回有序集合的元素个数 889 /// 890 /// 891 /// 892 public async Task<long> SortedSetLengthAsync(string redisKey) 893 { 894 redisKey = AddKeyPrefix(redisKey); 895 return await _db.SortedSetLengthAsync(redisKey); 896 } 897 898 /// 899 /// 返回有序集合的元素个数 900 /// 901 /// 902 /// 903 /// 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 /// 911 /// SortedSet 新增 912 /// 913 /// 914 /// 915 /// 916 /// 917 public async Task<bool> SortedSetAddAsync (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 /// 932 /// 移除指定 Key 933 /// 934 /// 935 /// 936 public bool KeyDelete(string redisKey) 937 { 938 redisKey = AddKeyPrefix(redisKey); 939 return _db.KeyDelete(redisKey); 940 } 941 942 /// 943 /// 移除指定 Key 944 /// 945 /// 946 /// 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 /// 954 /// 校验 Key 是否存在 955 /// 956 /// 957 /// 958 public bool KeyExists(string redisKey) 959 { 960 redisKey = AddKeyPrefix(redisKey); 961 return _db.KeyExists(redisKey); 962 } 963 964 /// 965 /// 重命名 Key 966 /// 967 /// 968 /// 969 /// 970 public bool KeyRename(string redisKey, string redisNewKey) 971 { 972 redisKey = AddKeyPrefix(redisKey); 973 return _db.KeyRename(redisKey, redisNewKey); 974 } 975 976 /// 977 /// 设置 Key 的时间 978 /// 979 /// 980 /// 981 /// 982 public bool KeyExpire(string redisKey, TimeSpan? expiry) 983 { 984 redisKey = AddKeyPrefix(redisKey); 985 return _db.KeyExpire(redisKey, expiry); 986 } 987 988 /// 989 /// Get all keys by wildcard 990 /// 991 /// 992 /// 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 /// 1017 /// 移除指定 Key 1018 /// 1019 /// 1020 /// 1021 public async Task<bool> KeyDeleteAsync(string redisKey) 1022 { 1023 redisKey = AddKeyPrefix(redisKey); 1024 return await _db.KeyDeleteAsync(redisKey); 1025 } 1026 1027 /// 1028 /// 移除指定 Key 1029 /// 1030 /// 1031 /// 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 /// 1039 /// 校验 Key 是否存在 1040 /// 1041 /// 1042 /// 1043 public async Task<bool> KeyExistsAsync(string redisKey) 1044 { 1045 redisKey = AddKeyPrefix(redisKey); 1046 return await _db.KeyExistsAsync(redisKey); 1047 } 1048 1049 /// 1050 /// 重命名 Key 1051 /// 1052 /// 1053 /// 1054 /// 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 /// 1062 /// 设置 Key 的时间 1063 /// 1064 /// 1065 /// 1066 /// 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 /// 1080 /// 订阅 1081 /// 1082 /// 1083 /// 1084 public void Subscribe(RedisChannel channel, Action handle) 1085 { 1086 var sub = _connMultiplexer.GetSubscriber(); 1087 sub.Subscribe(channel, handle); 1088 } 1089 1090 /// 1091 /// 发布 1092 /// 1093 /// 1094 /// 1095 /// 1096 public long Publish(RedisChannel channel, RedisValue message) 1097 { 1098 var sub = _connMultiplexer.GetSubscriber(); 1099 return sub.Publish(channel, message); 1100 } 1101 1102 /// 1103 /// 发布(使用序列化) 1104 /// 1105 /// 1106 /// 1107 /// 1108 /// 1109 public long Publish (RedisChannel channel, T message) 1110 { 1111 var sub = _connMultiplexer.GetSubscriber(); 1112 return sub.Publish(channel, Serialize(message)); 1113 } 1114 1115 #region 发布订阅-async 1116 1117 /// 1118 /// 订阅 1119 /// 1120 /// 1121 /// 1122 public async Task SubscribeAsync(RedisChannel channel, Action handle) 1123 { 1124 var sub = _connMultiplexer.GetSubscriber(); 1125 await sub.SubscribeAsync(channel, handle); 1126 } 1127 1128 /// 1129 /// 发布 1130 /// 1131 /// 1132 /// 1133 /// 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 /// 1141 /// 发布(使用序列化) 1142 /// 1143 /// 1144 /// 1145 /// 1146 /// 1147 public async Task<long> PublishAsync (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 /// 1160 /// 添加 Key 的前缀 1161 /// 1162 /// 1163 /// 1164 private static string AddKeyPrefix(string key) 1165 { 1166 return $"{DefaultKey}:{key}"; 1167 } 1168 1169 #region 注册事件 1170 1171 /// 1172 /// 添加注册事件 1173 /// 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 /// 1186 /// 重新配置广播时(通常意味着主从同步更改) 1187 /// 1188 /// 1189 /// 1190 private static void ConnMultiplexer_ConfigurationChangedBroadcast(object sender, EndPointEventArgs e) 1191 { 1192 Console.WriteLine($"{nameof(ConnMultiplexer_ConfigurationChangedBroadcast)}: {e.EndPoint}"); 1193 } 1194 1195 /// 1196 /// 发生内部错误时(主要用于调试) 1197 /// 1198 /// 1199 /// 1200 private static void ConnMultiplexer_InternalError(object sender, InternalErrorEventArgs e) 1201 { 1202 Console.WriteLine($"{nameof(ConnMultiplexer_InternalError)}: {e.Exception}"); 1203 } 1204 1205 /// 1206 /// 更改集群时 1207 /// 1208 /// 1209 /// 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 /// 1217 /// 配置更改时 1218 /// 1219 /// 1220 /// 1221 private static void ConnMultiplexer_ConfigurationChanged(object sender, EndPointEventArgs e) 1222 { 1223 Console.WriteLine($"{nameof(ConnMultiplexer_ConfigurationChanged)}: {e.EndPoint}"); 1224 } 1225 1226 /// 1227 /// 发生错误时 1228 /// 1229 /// 1230 /// 1231 private static void ConnMultiplexer_ErrorMessage(object sender, RedisErrorEventArgs e) 1232 { 1233 Console.WriteLine($"{nameof(ConnMultiplexer_ErrorMessage)}: {e.Message}"); 1234 } 1235 1236 /// 1237 /// 物理连接失败时 1238 /// 1239 /// 1240 /// 1241 private static void ConnMultiplexer_ConnectionFailed(object sender, ConnectionFailedEventArgs e) 1242 { 1243 Console.WriteLine($"{nameof(ConnMultiplexer_ConnectionFailed)}: {e.Exception}"); 1244 } 1245 1246 /// 1247 /// 建立物理连接时 1248 /// 1249 /// 1250 /// 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 /// 1259 /// 序列化 1260 /// 1261 /// 1262 /// 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 /// 1278 /// 反序列化 1279 /// 1280 /// 1281 /// 1282 /// 1283 private static T Deserialize (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 }appsettings.json
注: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 redisService3Redis服务安装相关命令