C#客户端Redis服务器的分布式缓存

开发 后端 分布式 Redis
在这篇文章中,我想介绍我知道的一种最紧凑的安装和配置Redis服务器的方式。另外,我想简短地概述一下在.NET / C#客户端下Redis hash(哈希类型)和list(链表)的使用。

介绍

在这篇文章中,我想介绍我知道的一种最紧凑的安装和配置Redis服务器的方式。另外,我想简短地概述一下在.NET / C#客户端下Redis hash(哈希类型)和list(链表)的使用。

在这篇文章主要讲到:

  • 安装Redis服务器(附完整的应用程序文件设置

  • Redis服务器保护(配置身份验证)

  • 配置服务器复制

  • 从C#应用程序访问缓存

  • 使用Redis ASP.NET会话状态

  • Redis 集合(Set)、列表(List)和事务处理用法示例

  • 说明附加的源(Redis Funq LoC MVC项目:举例)

  • 缓存的优化思路

背景

Redis是最快也是功能最丰富的内存Key-Value数据存储系统之一。

缺点

  • 没有本地数据缓存(如在Azure缓存同步本地数据缓存)

  • 没有完全集群化的支持(不过,可能今年年底会实现)

优点

  • 易于配置

  • 使用简单

  • 高性能

  • 支持不同的数据类型(如hash(哈希类型)、list(链表)、set(集合)、sorted set(有序集))

  • ASP.NET会话集成

  • Web UI用于浏览缓存内容

下面我将简单说明如何在服务器上安装和配置Redis,并用C#使用它。

Redis的安装

https://github.com/dmajkic/redis/downloads(win32 win64直接链接)下载二进制文件,解包档案到应用程序目录(如C:\Program Files\Redis)

下载从https://github.com/kcherenkov/redis-windows-service/downloads编译的Redis服务,然后复制到程序文件夹(如C:\Program Files\Redis)。如果配置文件丢失,也可以下载复制到应用程序目录。有效的Redis配置文件的范例在https://raw.github.com/antirez/redis/2.6/redis.conf

Redis应用程序的完整文件也可以从压缩文件(x64)得到。

当你拥有了全套的应用程序文件(如下图所示),

redis application folder conten

导航到应用程序目录,然后运行以下命令:

sc create %name% binpath= "\"%binpath%\" %configpath%" start= "auto" DisplayName= "Redis"

其中:

  • %name%——服务实例的名称,例如:redis-instance;

  • %binpath%——到项目exe文件的路径,例如:C:\Program Files\Redis\RedisService_1.1.exe;

  • %configpath%——到Redis配置文件的路径,例如:C:\Program Files\Redis\redis.conf;

举例:

sc create Redis start= auto DisplayName= Redis binpath= "\"C:\Program Files\Redis\RedisService_1.1.exe\
" \"C:\Program Files\Redis\redis.conf\""

即应该是这样的:

请确保有足够的权限启动该服务。安装完毕后,请检查该服务是否创建成功,当前是否正在运行:

或者,你可以使用安装程序(我没试过):https://github.com/rgl/redis/downloads

Redis服务器保护:密码,IP过滤

保护Redis服务器的主要方式是使用Windows防火墙或活跃的网络连接属性设置IP过滤。此外,还可以使用Redis密码设置额外保护。这需要用下面的方式更新Redis配置文件(redis.conf):

首先,找到这行:

# requirepass foobared

删除开头的#符号,用新密码替换foobared:

requirepass foobared

然后,重新启动Redis Windows服务!

当具体使用客户端的时候,使用带密码的构造函数:

RedisClient client = new RedisClient(serverHost, port, redisPassword);

Redis服务器复制(主—从配置)

Redis支持主从同步,即,每次主服务器修改,从服务器得到通知,并自动同步。大多复制用于读取(但不能写)扩展和数据冗余和服务器故障转移。设 置两个Redis实例(在相同或不同服务器上的两个服务),然后配置其中之一作为从站。为了让Redis服务器实例是另一台服务器的从属,可以这样更改配 置文件:

找到以下代码:

# slaveof <masterip> <masterport>

替换为:

slaveof 192.168.1.1 6379

(可以自定义指定主服务器的真实IP和端口)。如果主服务器配置为需要密码(验证),可以如下所示改变redis.conf,找到这一行代码:

# masterauth <master-password>

删除开头的#符号,用主服务器的密码替换<master-password>,即:

masterauth mastpassword

现在这个Redis实例可以被用来作为主服务器的只读同步副本。

用C#代码使用Redis缓存

用C#代码使用Redis运行Manage NuGet包插件,找到ServiceStack.Redis包,并进行安装。

直接从实例化客户端使用Set/Get方法示例:

 

string host = "localhost"
string elementKey = "testKeyRedis"
 
using (RedisClient redisClient = new RedisClient(host)) 

      if (redisClient.Get<string>(elementKey) == null
      { 
           // adding delay to see the difference 
           Thread.Sleep(5000); 
           // save value in cache 
           redisClient.Set(elementKey, "some cached value"); 
      } 
      // get value from the cache by key 
      message = "Item value is: " + redisClient.Get<string>("some cached value"); 

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.

类型化实体集更有意思和更实用,这是因为它们操作的是确切类型的对象。在下面的代码示例中,有两个类分别定义为Phone和Person——phone的主人。每个phone实例引用它的主人。下面的代码演示我们如何通过标准添加、删除和发现缓存项:

 

public class Phone 

   public int Id { get; set; } 
   public string Model { get; set; } 
   public string Manufacturer { get; set; } 
   public Person Owner { get; set; } 

 
public class Person 

    public int Id { get; set; } 
    public string Name { get; set; } 
    public string Surname { get; set; } 
    public int Age { get; set; } 
    public string Profession { get; set; } 

 
using (RedisClient redisClient = new RedisClient(host)) 

     IRedisTypedClient<phone> phones = redisClient.As<phone>(); 
     Phone phoneFive = phones.GetValue("5"); 
     if (phoneFive == null
     { 
          // make a small delay 
          Thread.Sleep(5000); 
          // creating a new Phone entry 
          phoneFive = new Phone 
          { 
               Id = 5
               Manufacturer = "Motorolla"
               Model = "xxxxx"
               Owner = new Person 
               { 
                    Id = 1
                    Age = 90
                    Name = "OldOne"
                    Profession = "sportsmen"
                    Surname = "OldManSurname" 
               } 
          }; 
          // adding Entry to the typed entity set 
          phones.SetEntry(phoneFive.Id.ToString(), phoneFive); 
     } 
     message = "Phone model is " + phoneFive.Manufacturer; 
     message += "Phone Owner Name is: " + phoneFive.Owner.Name; 

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.

在上面的例子中,我们实例化了输入端IRedisTypedClient,它与缓存对象的特定类型——Phone类型一起工作。

Redis ASP.NET会话状态

要用Redis提供商配置ASP.NET会话状态,添加新文件到你的Web项目,命名为RedisSessionStateProvider.cs,可以从https://github.com/chadman/redis-service-provider/raw/master/RedisProvider/SessionProvider/RedisSessionProvider.cs复制代码,然后添加或更改配置文件中的以下部分(sessionState标签已经内置于system.web标签),或者你也可以下载附加来源和复制代码。

<sessionstate timeout="1" mode="Custom" 
customprovider="RedisSessionStateProvider" cookieless="false"
      <providers> 
        <add name="RedisSessionStateProvider" writeexceptionstoeventlog="false" 
        type="RedisProvider.SessionProvider.CustomServiceProvider" 
        server="localhost" port="6379" password="pasword"
      </add> </providers> 
</sessionstate> 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.

注意,此密码是可以选择的,看服务器是否需要认证。它必须被真实的值替换或删除,如果Redis服务器不需要身份验证,那么服务器属性和端口得由具体的数值代替(默认端口为6379)。然后在项目中,你才可以使用会话状态:

 

// in the Global.asax 
public class MvcApplication1 : System.Web.HttpApplication 

    protected void Application_Start() 
    { 
        //.... 
    } 
 
    protected void Session_Start() 
    { 
        Session["testRedisSession"] = "Message from the redis ression"
    } 

 
在Home controller(主控制器): 
 
public class HomeController : Controller 

    public ActionResult Index() 
    { 
       //... 
       ViewBag.Message = Session["testRedisSession"]; 
       return View(); 
    } 
//... 

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.

结果:

ASP.NET输出缓存提供者,并且Redis可以用类似的方式进行配置。

Redis Set(集合)和List(列表)

主要要注意的是,Redis列表实现IList<T>,而Redis集合实现ICollection<T>。下面来说说如何使用它们。

当需要区分相同类型的不同分类对象时,使用列表。例如,我们有“mostSelling(热销手机)”和“oldCollection(回收手机)”两个列表:

 

string host = "localhost"
using (var redisClient = new RedisClient(host)) 

    //Create a 'strongly-typed' API that makes all Redis Value operations to apply against Phones 
    IRedisTypedClient<phone> redis = redisClient.As<phone>(); 
 
    IRedisList<phone> mostSelling = redis.Lists["urn:phones:mostselling"]; 
    IRedisList<phone> oldCollection = redis.Lists["urn:phones:oldcollection"]; 
 
    Person phonesOwner = new Person 
        { 
            Id = 7
            Age = 90
            Name = "OldOne"
            Profession = "sportsmen"
            Surname = "OldManSurname" 
        }; 
 
    // adding new items to the list 
    mostSelling.Add(new Phone 
            { 
                Id = 5
                Manufacturer = "Sony"
                Model = "768564564566"
                Owner = phonesOwner 
            }); 
 
    oldCollection.Add(new Phone 
            { 
                Id = 8
                Manufacturer = "Motorolla"
                Model = "324557546754"
                Owner = phonesOwner 
            }); 
 
    var upgradedPhone  = new Phone 
    { 
        Id = 3
        Manufacturer = "LG"
        Model = "634563456"
        Owner = phonesOwner 
    }; 
 
    mostSelling.Add(upgradedPhone); 
 
    // remove item from the list 
    oldCollection.Remove(upgradedPhone); 
 
    // find objects in the cache 
    IEnumerable<phone> LGPhones = mostSelling.Where(ph => ph.Manufacturer == "LG"); 
 
    // find specific 
    Phone singleElement = mostSelling.FirstOrDefault(ph => ph.Id == 8); 
 
    //reset sequence and delete all lists 
    redis.SetSequence(0); 
    redisClient.Remove("urn:phones:mostselling"); 
    redisClient.Remove("urn:phones:oldcollection"); 

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.

当需要存储相关的数据集和收集统计信息,例如answer -> queustion给答案或问题投票时,Redis集合就非常好使。假设我们有很多的问题(queustion)和答案(answer ),需要将它们存储在缓存中。使用Redis,我们可以这么做:

 

/// <summary> 
/// Gets or sets the Redis Manager. The built-in IoC used with ServiceStack autowires this property. 
/// </summary> 
IRedisClientsManager RedisManager { get; set; } 
/// <summary> 
/// Delete question by performing compensating actions to 
/// StoreQuestion() to keep the datastore in a consistent state 
/// </summary> 
/// <param name="questionId"> 
public void DeleteQuestion(long questionId) 

    using (var redis = RedisManager.GetClient()) 
    { 
        var redisQuestions = redis.As<question>(); 
 
        var question = redisQuestions.GetById(questionId); 
        if (question == nullreturn
 
        //decrement score in tags list 
        question.Tags.ForEach(tag => redis.IncrementItemInSortedSet("urn:tags", tag, -1)); 
 
        //remove all related answers 
        redisQuestions.DeleteRelatedEntities<answer>(questionId); 
 
        //remove this question from user index 
        redis.RemoveItemFromSet("urn:user>q:" + question.UserId, questionId.ToString()); 
 
        //remove tag => questions index for each tag 
        question.Tags.ForEach("urn:tags>q:" + tag.ToLower(), questionId.ToString())); 
 
        redisQuestions.DeleteById(questionId); 
    } 

 
public void StoreQuestion(Question question) 

    using (var redis = RedisManager.GetClient()) 
    { 
        var redisQuestions = redis.As<question>(); 
 
        if (question.Tags == null) question.Tags = new List<string>(); 
        if (question.Id == default(long)) 
        { 
            question.Id = redisQuestions.GetNextSequence(); 
            question.CreatedDate = DateTime.UtcNow; 
 
            //Increment the popularity for each new question tag 
            question.Tags.ForEach(tag => redis.IncrementItemInSortedSet("urn:tags", tag, 1)); 
        } 
 
        redisQuestions.Store(question); 
        redisQuestions.AddToRecentsList(question); 
        redis.AddItemToSet("urn:user>q:" + question.UserId, question.Id.ToString()); 
 
        //Usage of tags - Populate tag => questions index for each tag 
        question.Tags.ForEach(tag => redis.AddItemToSet 
        ("urn:tags>q:" + tag.ToLower(), question.Id.ToString())); 
    } 

 
/// <summary> 
/// Delete Answer by performing compensating actions to 
/// StoreAnswer() to keep the datastore in a consistent state 
/// </summary> 
/// <param name="questionId"> 
/// <param name="answerId"> 
public void DeleteAnswer(long questionId, long answerId) 

    using (var redis = RedisManager.GetClient()) 
    { 
        var answer = redis.As<question>().GetRelatedEntities<answer> 
        (questionId).FirstOrDefault(x => x.Id == answerId); 
        if (answer == nullreturn
 
        redis.As<question>().DeleteRelatedEntity<answer>(questionId, answerId); 
 
        //remove user => answer index 
        redis.RemoveItemFromSet("urn:user>a:" + answer.UserId, answerId.ToString()); 
    } 

 
public void StoreAnswer(Answer answer) 

    using (var redis = RedisManager.GetClient()) 
    { 
        if (answer.Id == default(long)) 
        { 
            answer.Id = redis.As<answer>().GetNextSequence(); 
            answer.CreatedDate = DateTime.UtcNow; 
        } 
 
        //Store as a 'Related Answer' to the parent Question 
        redis.As<question>().StoreRelatedEntities(answer.QuestionId, answer); 
        //Populate user => answer index 
        redis.AddItemToSet("urn:user>a:" + answer.UserId, answer.Id.ToString()); 
    } 

 
public List<answer> GetAnswersForQuestion(long questionId) 

    using (var redis = RedisManager.GetClient()) 
    { 
        return redis.As<question>().GetRelatedEntities<answer>(questionId); 
    } 

 
public void VoteQuestionUp(long userId, long questionId) 

    //Populate Question => User and User => Question set indexes in a single transaction 
    RedisManager.ExecTrans(trans => 
    { 
        //Register upvote against question and remove any downvotes if any 
        trans.QueueCommand(redis => 
        redis.AddItemToSet("urn:q>user+:" + questionId, userId.ToString())); 
        trans.QueueCommand(redis => 
        redis.RemoveItemFromSet("urn:q>user-:" + questionId, userId.ToString())); 
 
        //Register upvote against user and remove any downvotes if any 
        trans.QueueCommand(redis => 
        redis.AddItemToSet("urn:user>q+:" + userId, questionId.ToString())); 
        trans.QueueCommand(redis => 
        redis.RemoveItemFromSet("urn:user>q-:" + userId, questionId.ToString())); 
    }); 

 
public void VoteQuestionDown(long userId, long questionId) 

    //Populate Question => User and User => Question set indexes in a single transaction 
    RedisManager.ExecTrans(trans => 
    { 
        //Register downvote against question and remove any upvotes if any 
        trans.QueueCommand(redis => 
        redis.AddItemToSet("urn:q>user-:" + questionId, userId.ToString())); 
        trans.QueueCommand(redis => 
        redis.RemoveItemFromSet("urn:q>user+:" + questionId, userId.ToString())); 
 
        //Register downvote against user and remove any upvotes if any 
        trans.QueueCommand(redis => 
        redis.AddItemToSet"urn:user>q-:" + userId, questionId.ToString())); 
        trans.QueueCommand(redis => 
        redis.RemoveItemFromSet("urn:user>q+:" + userId, questionId.ToString())); 
    }); 

 
public void VoteAnswerUp(long userId, long answerId) 

    //Populate Question => User and User => Question set indexes in a single transaction 
    RedisManager.ExecTrans(trans => 
    { 
        //Register upvote against answer and remove any downvotes if any 
        trans.QueueCommand(redis => 
        redis.AddItemToSet("urn:a>user+:" + answerId, userId.ToString())); 
        trans.QueueCommand(redis => 
        redis.RemoveItemFromSet("urn:a>user-:" + answerId, userId.ToString())); 
 
        //Register upvote against user and remove any downvotes if any 
        trans.QueueCommand(redis => 
        redis.AddItemToSet("urn:user>a+:" + userId, answerId.ToString())); 
        trans.QueueCommand(redis => 
        redis.RemoveItemFromSet("urn:user>a-:" + userId, answerId.ToString())); 
    }); 

 
public void VoteAnswerDown(long userId, long answerId) 

    //Populate Question => User and User => Question set indexes in a single transaction 
    RedisManager.ExecTrans(trans => 
    { 
        //Register downvote against answer and remove any upvotes if any 
        trans.QueueCommand(redis => 
        redis.AddItemToSet("urn:a>user-:" + answerId, userId.ToString())); 
        trans.QueueCommand(redis => 
        redis.RemoveItemFromSet("urn:a>user+:" + answerId, userId.ToString())); 
 
        //Register downvote against user and remove any upvotes if any 
        trans.QueueCommand(redis => 
        redis.AddItemToSet("urn:user>a-:" + userId, answerId.ToString())); 
        trans.QueueCommand(redis => 
        redis.RemoveItemFromSet("urn:user>a+:" + userId, answerId.ToString())); 
    }); 

 
public QuestionResult GetQuestion(long questionId) 

    var question = RedisManager.ExecAs<question> 
    (redisQuestions => redisQuestions.GetById(questionId)); 
    if (question == nullreturn null
 
    var result = ToQuestionResults(new[] { question })[0]; 
    var answers = GetAnswersForQuestion(questionId); 
    var uniqueUserIds = answers.ConvertAll(x => x.UserId).ToHashSet(); 
    var usersMap = GetUsersByIds(uniqueUserIds).ToDictionary(x => x.Id); 
 
    result.Answers = answers.ConvertAll(answer => 
        new AnswerResult { Answer = answer, User = usersMap[answer.UserId] }); 
 
    return result; 

 
public List<user> GetUsersByIds(IEnumerable<long> userIds) 

    return RedisManager.ExecAs<user>(redisUsers => redisUsers.GetByIds(userIds)).ToList(); 

 
public QuestionStat GetQuestionStats(long questionId) 

    using (var redis = RedisManager.GetReadOnlyClient()) 
    { 
        var result = new QuestionStat 
        { 
            VotesUpCount = redis.GetSetCount("urn:q>user+:" +questionId), 
            VotesDownCount = redis.GetSetCount("urn:q>user-:" + questionId) 
        }; 
        result.VotesTotal = result.VotesUpCount - result.VotesDownCount; 
        return result; 
    } 

 
public List<tag> GetTagsByPopularity(int skip, int take) 

    using (var redis = RedisManager.GetReadOnlyClient()) 
    { 
        var tagEntries = redis.GetRangeWithScoresFromSortedSetDesc("urn:tags", skip, take); 
        var tags = tagEntries.ConvertAll(kvp => new Tag { Name = kvp.Key, Score = (int)kvp.Value }); 
        return tags; 
    } 

 
public SiteStats GetSiteStats() 

    using (var redis = RedisManager.GetClient()) 
    { 
        return new SiteStats 
        { 
            QuestionsCount = redis.As<question>().TypeIdsSet.Count, 
            AnswersCount = redis.As<answer>().TypeIdsSet.Count, 
            TopTags = GetTagsByPopularity(010
        }; 
    } 

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.
  • 97.
  • 98.
  • 99.
  • 100.
  • 101.
  • 102.
  • 103.
  • 104.
  • 105.
  • 106.
  • 107.
  • 108.
  • 109.
  • 110.
  • 111.
  • 112.
  • 113.
  • 114.
  • 115.
  • 116.
  • 117.
  • 118.
  • 119.
  • 120.
  • 121.
  • 122.
  • 123.
  • 124.
  • 125.
  • 126.
  • 127.
  • 128.
  • 129.
  • 130.
  • 131.
  • 132.
  • 133.
  • 134.
  • 135.
  • 136.
  • 137.
  • 138.
  • 139.
  • 140.
  • 141.
  • 142.
  • 143.
  • 144.
  • 145.
  • 146.
  • 147.
  • 148.
  • 149.
  • 150.
  • 151.
  • 152.
  • 153.
  • 154.
  • 155.
  • 156.
  • 157.
  • 158.
  • 159.
  • 160.
  • 161.
  • 162.
  • 163.
  • 164.
  • 165.
  • 166.
  • 167.
  • 168.
  • 169.
  • 170.
  • 171.
  • 172.
  • 173.
  • 174.
  • 175.
  • 176.
  • 177.
  • 178.
  • 179.
  • 180.
  • 181.
  • 182.
  • 183.
  • 184.
  • 185.
  • 186.
  • 187.
  • 188.
  • 189.
  • 190.
  • 191.
  • 192.
  • 193.
  • 194.
  • 195.
  • 196.
  • 197.
  • 198.
  • 199.
  • 200.
  • 201.
  • 202.
  • 203.
  • 204.
  • 205.
  • 206.
  • 207.
  • 208.
  • 209.
  • 210.
  • 211.
  • 212.
  • 213.
  • 214.
  • 215.
  • 216.
  • 217.
  • 218.
  • 219.
  • 220.
  • 221.
  • 222.
  • 223.
  • 224.
  • 225.
  • 226.
  • 227.
  • 228.
  • 229.
  • 230.
  • 231.
  • 232.
  • 233.
  • 234.
  • 235.
  • 236.
  • 237.
  • 238.
  • 239.
  • 240.

附加资源说明

项目中引用的一些包在packages.config文件中配置。

Funq IoC的相关配置,以及注册类型和当前控制器目录,在Global.asax文件中配置。

基于IoC的缓存使用以及Global.asax可以打开以下URL:http://localhost:37447/Question/GetQuestions?tag=test 查看。

你可以将tag字段设置成test3,test1,test2等。

Redis缓存配置——在web config文件(<system.web><sessionState>节点)以及RedisSessionStateProvider.cs文件中。

在MVC项目中有很多待办事项,因此,如果你想改进/继续,请更新,并上传。

如果有人能提供使用Redis(以及Funq IOC)缓存的MVC应用程序示例,本人将不胜感激。Funq IOC已经配置,使用示例已经在Question controller中。

注:部分取样于“ServiceStack.Examples-master”解决方案。

结论。优化应用程序缓存以及快速本地缓存

由于Redis并不在本地存储(也不在本地复制)数据,那么通过在本地缓存区存储一些轻量级或用户依赖的对象(跳过序列化字符串和客户端—服务端数据转换)来优化性能是有意义的。例如,在Web应用中,对于轻量级的对象使用’System.Runtime.Caching.ObjectCache‘ 会更好——用户依赖,并且应用程序时常要用。否则,当经常性地需要使用该对象时,就必须在分布式Redis缓存中存储大量容积的内容。用户依赖的对象举例——个人资料信息,个性化信息 。常用对象——本地化数据,不同用户之间的共享信息,等等。

下载源代码(Redis Funq LoC MVC 4版本)

链接

如何运行Redis服务:

https://github.com/kcherenkov/redis-windows-service

文档:

http://redis.io/documentation

.NET / C#示例:

https://github.com/ServiceStack/ServiceStack.Examples

关于如何用C#在Windows上使用Redis的好建议:

http://maxivak.com/getting-started-with-redis-and-asp-net-mvc-under-windows/:

http://www.piotrwalat.net/using-redis-with-asp-net-web-api/

关于Redis:

https://github.com/ServiceStack/ServiceStack.Redis

Azure缓存

http://kotugoroshko.blogspot.ae/2013/07/windows-azure-caching-integration.html

许可证

这篇文章,以及任何相关的源代码和文件,依据The Code Project Open License (CPOL)。

译文链接:http://www.codeceo.com/article/distributed-caching-redis-server.html
英文原文:Distributed Caching using Redis Server with .NET/C# Client

 

责任编辑:王雪燕 来源: 码农网
相关推荐

2011-11-30 14:21:19

Java分布式缓存

2015-09-21 09:20:11

C#Couchbase使用

2024-12-02 09:19:44

2012-02-28 10:30:56

C#.NET

2020-03-12 19:00:48

Ceph分布式存储

2009-08-21 15:59:22

服务端与客户端通信

2009-08-18 12:51:19

服务器+客户端

2009-08-21 16:14:52

服务端与客户端通信

2017-03-13 14:02:10

分布式聊天服务器

2011-06-09 10:51:26

Qt 服务器 客户端

2009-08-21 15:36:41

服务端与客户端

2009-08-21 15:54:40

服务端与客户端

2019-02-18 11:16:12

Redis分布式缓存

2014-01-17 15:23:55

Nagios

2010-06-09 14:39:58

2009-08-06 17:12:13

C# WebServi

2018-11-07 09:23:21

服务器分布式机器学习

2018-12-18 10:47:37

2018-07-17 09:59:10

PythonUDP服务器

2019-03-27 08:43:17

Nginx负载均衡服务器
点赞
收藏

51CTO技术栈公众号