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     /// 
  13     /// 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 }
RedisHelper.cs

   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 redisService3
Redis服务安装相关命令