• C#实用技能篇


    Redis配置文件详解

    如果不指定配置文件,redis也可以启动,此时,redis使用默认的内置配置。不过在正式环境,常常通过配置文件【通常叫redis.conf】来配置redis。

    redis.conf配置格式如下:

     
    1. keyword argument1 argument2 ... argumentN  


    redis.conf配置参数:

    1)daemonize on|yes

    redis默认不是以守护进程的方式运行,可以通过该配置项修改,使用yes时,启用守护进程

    2)pidfile /var/run/redis_6379.pid

    redis以守护进程方式运行时,系统默认会把pid写入/var/run/redis.pid,可以通过pidfile指定pid文件

    3)port 6379

    redis默认监听6379端口,可以通过port指定redis要监听的端口

    4)bind 127.0.0.1

    绑定主机地址

    5)unixsocket /tmp/redis.sock

    指定redis监听的unix socket 路径

    6)timeout 300

    当客户端闲置多长时间,关闭连接,单位秒

    7)loglevel verbose|debug|notice|warning

    指定日志记录级别,默认是verbose

    8)logfile /var/log/redis_6379.log

    日志记录文件,默认是标准输出stdout,如果redis以守护进程方式运行,logfile 配置为stdout时,logs将要输出到/dev/null

    9)syslog-enabled no|yes

    当配置为yes时,日志输出到系统日志,默认是no

    10)syslog-ident redis

    指定syslog的标示符

    11)syslog-facility local0

    指定syslog设备(facility),必须是user或则local0到local7

    12)databases 16

    设置redis中数据库的个数,默认数据库是DB 0,可以通过select <dbid>,选择使用的数据库。dbis大于等于0,小于等于databases -1 【这里是16-1】

    13)save <seconds> <changes>

    指定多长时间内,有多少次更新操作时,将数据同步到数据库文件,可以多个条件配合,系统默认配置如下:

    [plain] view plain copy
     
    1. save 900 1 #900秒 1个修改  
    2. save 300 10 #300秒 10个更新  
    3. save 60 10000<span style="white-space:pre"> </span>#60秒 10000个更新  

    注意,如果不持久化【不把数据写入磁盘】,注释掉save即可。 

    14)rdbcompression yes|no

    数据dump到数据文件时,系统是否压缩string对象数据,系统默认是yes。如果为了节省cpu,可以设置为no,此时数据文件比用LZF压缩时要大
    15)dbfilename dump.rdb

    指定数据库文件名,默认是dump.rdb

    16)dir /var/lib/redis/6379

    指定本地数据库存放目录

    17)slaveof <masterip> <masterport>

    当本机是slave服务时,设置master服务的ip和端口

    18)masterauth <master-password>

    当master服务设置了密码时,slave服务连接master的密码。如果配置不对,slave服务请求将被拒绝

    19)slave-serve-stale-data yes|no

    当slave和master之间的连接断开或slave正在于master同步时,如果有slave请求,当slave-serve-stale-data配置为yes时,slave可以相应客户端请求;当为no时,slave将要响应错误,默认是yes

    20)requirepass foobared

    设置redis连接密码

    21)maxclients 128

    设置同一时间客户端最大连接数,默认是无限制。如果设置maxclients 0 时,表示不限制

    22)maxmemory <bytes>

    指定redis最大内存限制,redis在启动时,会把数据加载到内存中,达到最大内存后,redis会先清除已到期或将过期的key,仍然到达最大内存设置,将无法再进行写入操作,但仍然可以进行读操作

    23)maxmemory-policy volatile-lru|allkeys-lru|volatile-random|allkeys->random|volatile-ttl|noeviction

    当redis使用内存达到最大时,使用哪种策略移除内存中数据

    24)appendonly no|yes

    指定是否在每次更新操作后进行日志记录,默认配置是no,即在采用异步方式把数据写入到磁盘,如果不开启,可能会在断电时导致部分数据丢失

    25)appendfilename appendonly.aof

    指定更新日志文件名【aof日志】,默认为appendonly.aof

    26)appendfsync everysec|no|aways

    指定更新日志条件,no表示等操作系统进行数据缓存同步到磁盘的aof文件(快)always表示每次更新操作后手动调用fsync将数据写到磁盘的aof文件(慢,安全)

    everysec,表示每秒同步一次(拆中,默认值)

    27)slowlog-log-slower-than 10000

    配置记录慢日志的条件,单位是微妙,当是负值时,关闭慢日志记录,当是0时,记录所有操作

    28)slowlog-max-len 1024

    配置记录慢查询的最大条数

    29)hash-max-zipmap-entries 512

    配置最大元素数,当超过该配置数据时,redis采用特殊hash算法

    30)hash-max-zipmap-value 64

    配置最大元素值,当草果配置值时,采用特殊hash算法

    31)activerehashing yes

    指定是否激活充值hash,默认开启

    可以通过下面命令使用配置文件redis.conf启动redis服务

    Redis安装管理

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

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

    作者:小峰来源:码农网|2015-08-17 09:48

     

    介绍

    在这篇文章中,我想介绍我知道的一种最紧凑的安装和配置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 FilesRedis)

    下载从https://github.com/kcherenkov/redis-windows-service/downloads编译的Redis服务,然后复制到程序文件夹(如C:Program FilesRedis)。如果配置文件丢失,也可以下载复制到应用程序目录。有效的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 FilesRedisRedisService_1.1.exe;

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

    举例:

    sc create Redis start= auto DisplayName= Redis binpath= ""C:Program FilesRedisRedisService_1.1.exe
    " "C:Program FilesRedis edis.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方法示例:

    1. string host = "localhost"; 
    2. string elementKey = "testKeyRedis"; 
    3.  
    4. using (RedisClient redisClient = new RedisClient(host)) 
    5.       if (redisClient.Get<string>(elementKey) == null) 
    6.       { 
    7.            // adding delay to see the difference 
    8.            Thread.Sleep(5000); 
    9.            // save value in cache 
    10.            redisClient.Set(elementKey, "some cached value"); 
    11.       } 
    12.       // get value from the cache by key 
    13.       message = "Item value is: " + redisClient.Get<string>("some cached value"); 

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

    1. public class Phone 
    2.    public int Id { get; set; } 
    3.    public string Model { get; set; } 
    4.    public string Manufacturer { get; set; } 
    5.    public Person Owner { get; set; } 
    6.  
    7. public class Person 
    8.     public int Id { get; set; } 
    9.     public string Name { get; set; } 
    10.     public string Surname { get; set; } 
    11.     public int Age { get; set; } 
    12.     public string Profession { get; set; } 
    13.  
    14. using (RedisClient redisClient = new RedisClient(host)) 
    15.      IRedisTypedClient<phone> phones = redisClient.As<phone>(); 
    16.      Phone phoneFive = phones.GetValue("5"); 
    17.      if (phoneFive == null) 
    18.      { 
    19.           // make a small delay 
    20.           Thread.Sleep(5000); 
    21.           // creating a new Phone entry 
    22.           phoneFive = new Phone 
    23.           { 
    24.                Id = 5, 
    25.                Manufacturer = "Motorolla", 
    26.                Model = "xxxxx", 
    27.                Owner = new Person 
    28.                { 
    29.                     Id = 1, 
    30.                     Age = 90, 
    31.                     Name = "OldOne", 
    32.                     Profession = "sportsmen", 
    33.                     Surname = "OldManSurname" 
    34.                } 
    35.           }; 
    36.           // adding Entry to the typed entity set 
    37.           phones.SetEntry(phoneFive.Id.ToString(), phoneFive); 
    38.      } 
    39.      message = "Phone model is " + phoneFive.Manufacturer; 
    40.      message += "Phone Owner Name is: " + phoneFive.Owner.Name; 

    在上面的例子中,我们实例化了输入端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标签),或者你也可以下载附加来源和复制代码。

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

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

    1. // in the Global.asax 
    2. public class MvcApplication1 : System.Web.HttpApplication 
    3.     protected void Application_Start() 
    4.     { 
    5.         //.... 
    6.     } 
    7.  
    8.     protected void Session_Start() 
    9.     { 
    10.         Session["testRedisSession"] = "Message from the redis ression"; 
    11.     } 
    12.  
    13. 在Home controller(主控制器): 
    14.  
    15. public class HomeController : Controller 
    16.     public ActionResult Index() 
    17.     { 
    18.        //... 
    19.        ViewBag.Message = Session["testRedisSession"]; 
    20.        return View(); 
    21.     } 
    22. //... 

    结果:

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

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

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

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

    1. string host = "localhost"; 
    2. using (var redisClient = new RedisClient(host)) 
    3.     //Create a 'strongly-typed' API that makes all Redis Value operations to apply against Phones 
    4.     IRedisTypedClient<phone> redis = redisClient.As<phone>(); 
    5.  
    6.     IRedisList<phone> mostSelling = redis.Lists["urn:phones:mostselling"]; 
    7.     IRedisList<phone> oldCollection = redis.Lists["urn:phones:oldcollection"]; 
    8.  
    9.     Person phonesOwner = new Person 
    10.         { 
    11.             Id = 7, 
    12.             Age = 90, 
    13.             Name = "OldOne", 
    14.             Profession = "sportsmen", 
    15.             Surname = "OldManSurname" 
    16.         }; 
    17.  
    18.     // adding new items to the list 
    19.     mostSelling.Add(new Phone 
    20.             { 
    21.                 Id = 5, 
    22.                 Manufacturer = "Sony", 
    23.                 Model = "768564564566", 
    24.                 Owner = phonesOwner 
    25.             }); 
    26.  
    27.     oldCollection.Add(new Phone 
    28.             { 
    29.                 Id = 8, 
    30.                 Manufacturer = "Motorolla", 
    31.                 Model = "324557546754", 
    32.                 Owner = phonesOwner 
    33.             }); 
    34.  
    35.     var upgradedPhone  = new Phone 
    36.     { 
    37.         Id = 3, 
    38.         Manufacturer = "LG", 
    39.         Model = "634563456", 
    40.         Owner = phonesOwner 
    41.     }; 
    42.  
    43.     mostSelling.Add(upgradedPhone); 
    44.  
    45.     // remove item from the list 
    46.     oldCollection.Remove(upgradedPhone); 
    47.  
    48.     // find objects in the cache 
    49.     IEnumerable<phone> LGPhones = mostSelling.Where(ph => ph.Manufacturer == "LG"); 
    50.  
    51.     // find specific 
    52.     Phone singleElement = mostSelling.FirstOrDefault(ph => ph.Id == 8); 
    53.  
    54.     //reset sequence and delete all lists 
    55.     redis.SetSequence(0); 
    56.     redisClient.Remove("urn:phones:mostselling"); 
    57.     redisClient.Remove("urn:phones:oldcollection"); 

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

    1. /// <summary> 
    2. /// Gets or sets the Redis Manager. The built-in IoC used with ServiceStack autowires this property. 
    3. /// </summary> 
    4. IRedisClientsManager RedisManager { get; set; } 
    5. /// <summary> 
    6. /// Delete question by performing compensating actions to 
    7. /// StoreQuestion() to keep the datastore in a consistent state 
    8. /// </summary> 
    9. /// <param name="questionId"> 
    10. public void DeleteQuestion(long questionId) 
    11.     using (var redis = RedisManager.GetClient()) 
    12.     { 
    13.         var redisQuestions = redis.As<question>(); 
    14.  
    15.         var question = redisQuestions.GetById(questionId); 
    16.         if (question == null) return; 
    17.  
    18.         //decrement score in tags list 
    19.         question.Tags.ForEach(tag => redis.IncrementItemInSortedSet("urn:tags", tag, -1)); 
    20.  
    21.         //remove all related answers 
    22.         redisQuestions.DeleteRelatedEntities<answer>(questionId); 
    23.  
    24.         //remove this question from user index 
    25.         redis.RemoveItemFromSet("urn:user>q:" + question.UserId, questionId.ToString()); 
    26.  
    27.         //remove tag => questions index for each tag 
    28.         question.Tags.ForEach("urn:tags>q:" + tag.ToLower(), questionId.ToString())); 
    29.  
    30.         redisQuestions.DeleteById(questionId); 
    31.     } 
    32.  
    33. public void StoreQuestion(Question question) 
    34.     using (var redis = RedisManager.GetClient()) 
    35.     { 
    36.         var redisQuestions = redis.As<question>(); 
    37.  
    38.         if (question.Tags == null) question.Tags = new List<string>(); 
    39.         if (question.Id == default(long)) 
    40.         { 
    41.             question.Id = redisQuestions.GetNextSequence(); 
    42.             question.CreatedDate = DateTime.UtcNow; 
    43.  
    44.             //Increment the popularity for each new question tag 
    45.             question.Tags.ForEach(tag => redis.IncrementItemInSortedSet("urn:tags", tag, 1)); 
    46.         } 
    47.  
    48.         redisQuestions.Store(question); 
    49.         redisQuestions.AddToRecentsList(question); 
    50.         redis.AddItemToSet("urn:user>q:" + question.UserId, question.Id.ToString()); 
    51.  
    52.         //Usage of tags - Populate tag => questions index for each tag 
    53.         question.Tags.ForEach(tag => redis.AddItemToSet 
    54.         ("urn:tags>q:" + tag.ToLower(), question.Id.ToString())); 
    55.     } 
    56.  
    57. /// <summary> 
    58. /// Delete Answer by performing compensating actions to 
    59. /// StoreAnswer() to keep the datastore in a consistent state 
    60. /// </summary> 
    61. /// <param name="questionId"> 
    62. /// <param name="answerId"> 
    63. public void DeleteAnswer(long questionId, long answerId) 
    64.     using (var redis = RedisManager.GetClient()) 
    65.     { 
    66.         var answer = redis.As<question>().GetRelatedEntities<answer> 
    67.         (questionId).FirstOrDefault(x => x.Id == answerId); 
    68.         if (answer == null) return; 
    69.  
    70.         redis.As<question>().DeleteRelatedEntity<answer>(questionId, answerId); 
    71.  
    72.         //remove user => answer index 
    73.         redis.RemoveItemFromSet("urn:user>a:" + answer.UserId, answerId.ToString()); 
    74.     } 
    75.  
    76. public void StoreAnswer(Answer answer) 
    77.     using (var redis = RedisManager.GetClient()) 
    78.     { 
    79.         if (answer.Id == default(long)) 
    80.         { 
    81.             answer.Id = redis.As<answer>().GetNextSequence(); 
    82.             answer.CreatedDate = DateTime.UtcNow; 
    83.         } 
    84.  
    85.         //Store as a 'Related Answer' to the parent Question 
    86.         redis.As<question>().StoreRelatedEntities(answer.QuestionId, answer); 
    87.         //Populate user => answer index 
    88.         redis.AddItemToSet("urn:user>a:" + answer.UserId, answer.Id.ToString()); 
    89.     } 
    90.  
    91. public List<answer> GetAnswersForQuestion(long questionId) 
    92.     using (var redis = RedisManager.GetClient()) 
    93.     { 
    94.         return redis.As<question>().GetRelatedEntities<answer>(questionId); 
    95.     } 
    96.  
    97. public void VoteQuestionUp(long userId, long questionId) 
    98.     //Populate Question => User and User => Question set indexes in a single transaction 
    99.     RedisManager.ExecTrans(trans => 
    100.     { 
    101.         //Register upvote against question and remove any downvotes if any 
    102.         trans.QueueCommand(redis => 
    103.         redis.AddItemToSet("urn:q>user+:" + questionId, userId.ToString())); 
    104.         trans.QueueCommand(redis => 
    105.         redis.RemoveItemFromSet("urn:q>user-:" + questionId, userId.ToString())); 
    106.  
    107.         //Register upvote against user and remove any downvotes if any 
    108.         trans.QueueCommand(redis => 
    109.         redis.AddItemToSet("urn:user>q+:" + userId, questionId.ToString())); 
    110.         trans.QueueCommand(redis => 
    111.         redis.RemoveItemFromSet("urn:user>q-:" + userId, questionId.ToString())); 
    112.     }); 
    113.  
    114. public void VoteQuestionDown(long userId, long questionId) 
    115.     //Populate Question => User and User => Question set indexes in a single transaction 
    116.     RedisManager.ExecTrans(trans => 
    117.     { 
    118.         //Register downvote against question and remove any upvotes if any 
    119.         trans.QueueCommand(redis => 
    120.         redis.AddItemToSet("urn:q>user-:" + questionId, userId.ToString())); 
    121.         trans.QueueCommand(redis => 
    122.         redis.RemoveItemFromSet("urn:q>user+:" + questionId, userId.ToString())); 
    123.  
    124.         //Register downvote against user and remove any upvotes if any 
    125.         trans.QueueCommand(redis => 
    126.         redis.AddItemToSet"urn:user>q-:" + userId, questionId.ToString())); 
    127.         trans.QueueCommand(redis => 
    128.         redis.RemoveItemFromSet("urn:user>q+:" + userId, questionId.ToString())); 
    129.     }); 
    130.  
    131. public void VoteAnswerUp(long userId, long answerId) 
    132.     //Populate Question => User and User => Question set indexes in a single transaction 
    133.     RedisManager.ExecTrans(trans => 
    134.     { 
    135.         //Register upvote against answer and remove any downvotes if any 
    136.         trans.QueueCommand(redis => 
    137.         redis.AddItemToSet("urn:a>user+:" + answerId, userId.ToString())); 
    138.         trans.QueueCommand(redis => 
    139.         redis.RemoveItemFromSet("urn:a>user-:" + answerId, userId.ToString())); 
    140.  
    141.         //Register upvote against user and remove any downvotes if any 
    142.         trans.QueueCommand(redis => 
    143.         redis.AddItemToSet("urn:user>a+:" + userId, answerId.ToString())); 
    144.         trans.QueueCommand(redis => 
    145.         redis.RemoveItemFromSet("urn:user>a-:" + userId, answerId.ToString())); 
    146.     }); 
    147.  
    148. public void VoteAnswerDown(long userId, long answerId) 
    149.     //Populate Question => User and User => Question set indexes in a single transaction 
    150.     RedisManager.ExecTrans(trans => 
    151.     { 
    152.         //Register downvote against answer and remove any upvotes if any 
    153.         trans.QueueCommand(redis => 
    154.         redis.AddItemToSet("urn:a>user-:" + answerId, userId.ToString())); 
    155.         trans.QueueCommand(redis => 
    156.         redis.RemoveItemFromSet("urn:a>user+:" + answerId, userId.ToString())); 
    157.  
    158.         //Register downvote against user and remove any upvotes if any 
    159.         trans.QueueCommand(redis => 
    160.         redis.AddItemToSet("urn:user>a-:" + userId, answerId.ToString())); 
    161.         trans.QueueCommand(redis => 
    162.         redis.RemoveItemFromSet("urn:user>a+:" + userId, answerId.ToString())); 
    163.     }); 
    164.  
    165. public QuestionResult GetQuestion(long questionId) 
    166.     var question = RedisManager.ExecAs<question> 
    167.     (redisQuestions => redisQuestions.GetById(questionId)); 
    168.     if (question == null) return null; 
    169.  
    170.     var result = ToQuestionResults(new[] { question })[0]; 
    171.     var answers = GetAnswersForQuestion(questionId); 
    172.     var uniqueUserIds = answers.ConvertAll(x => x.UserId).ToHashSet(); 
    173.     var usersMap = GetUsersByIds(uniqueUserIds).ToDictionary(x => x.Id); 
    174.  
    175.     result.Answers = answers.ConvertAll(answer => 
    176.         new AnswerResult { Answer = answer, User = usersMap[answer.UserId] }); 
    177.  
    178.     return result; 
    179.  
    180. public List<user> GetUsersByIds(IEnumerable<long> userIds) 
    181.     return RedisManager.ExecAs<user>(redisUsers => redisUsers.GetByIds(userIds)).ToList(); 
    182.  
    183. public QuestionStat GetQuestionStats(long questionId) 
    184.     using (var redis = RedisManager.GetReadOnlyClient()) 
    185.     { 
    186.         var result = new QuestionStat 
    187.         { 
    188.             VotesUpCount = redis.GetSetCount("urn:q>user+:" +questionId), 
    189.             VotesDownCount = redis.GetSetCount("urn:q>user-:" + questionId) 
    190.         }; 
    191.         result.VotesTotal = result.VotesUpCount - result.VotesDownCount; 
    192.         return result; 
    193.     } 
    194.  
    195. public List<tag> GetTagsByPopularity(int skip, int take) 
    196.     using (var redis = RedisManager.GetReadOnlyClient()) 
    197.     { 
    198.         var tagEntries = redis.GetRangeWithScoresFromSortedSetDesc("urn:tags", skip, take); 
    199.         var tags = tagEntries.ConvertAll(kvp => new Tag { Name = kvp.Key, Score = (int)kvp.Value }); 
    200.         return tags; 
    201.     } 
    202.  
    203. public SiteStats GetSiteStats() 
    204.     using (var redis = RedisManager.GetClient()) 
    205.     { 
    206.         return new SiteStats 
    207.         { 
    208.             QuestionsCount = redis.As<question>().TypeIdsSet.Count, 
    209.             AnswersCount = redis.As<answer>().TypeIdsSet.Count, 
    210.             TopTags = GetTagsByPopularity(0, 10) 
    211.         }; 
    212.     } 

    附加资源说明

    项目中引用的一些包在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

    园内博客简单安装Redis方法

    windows下安装redis

    1、redis简介
    redis是一个key-value存储系统。和Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和hashs(哈希类型)。这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。在此基础上,redis支持各种不同方式的排序。与memcached一样,为了保证效率,数据都是缓存在内存中。区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步。

    Redis 是一个高性能的key-value数据库。 redis的出现,很大程度补偿了memcached这类key/value存储的不足,在部分场合可以对关系数据库起到很好的补充作用。它提供了Python,Ruby,Erlang,PHP客户端,使用很方便。

    2、windows下安装redis
    下载地址https://github.com/dmajkic/redis/downloads。下载到的Redis支持32bit和64bit。根据自己实际情况选择,我选择32bit。把32bit文件内容拷贝到需要安装的目录下,比如:D:dev edis-2.4.5。

    打开一个cmd窗口,使用cd命令切换到指定目录(D:dev edis-2.4.5)运行 redis-server.exe redis.conf 。运行以后出现如下界面。

    这就说明Redis服务端已经安装成功。

    重新打开一个cmd窗口,使用cd命令切换到指定目录(D:dev edis-2.4.5)运行 redis-cli.exe -h 127.0.0.1 -p 6379 -a 123456,其中 127.0.0.1是本地ip,6379是redis服务端的默认端口,123456是redis密码。运行成功如下图所示。
    这样,Redis windows环境下搭建已经完成,是不是很简单。

    这样,Redis windows环境下搭建已经完成,是不是很简单。

    环境已经搭建好,总得测试下吧。比如:存储一个key为test,value为hello word的字符串,然后获取key值。

    正确输出 hell word,测试成功!

  • 相关阅读:
    008. redis 主从复制原理、断点续传、无磁盘化复制、过期 key 处理
    007.redis replication 以及 master 持久化对主从架构的安全意义
    006. redis 如何通过读写分离来承载读请求 QPS 超过 10 万 +?
    005.在项目中部署 redis 企业级数据备份方案以及各种踩坑的数据恢复容灾演练
    人月神话---向进度落后的项目中增加人手,只会使进度更加落后
    人月神话---空泛的估算
    人月神话---不为系统测试安排足够的时间简直就是一场灾难
    人月神话---成本的确随开发产品的人数和时间的不同,有着很大的变化,进度却不是如此
    springmvc其他类获取request记得web.xml
    gson转换问题
  • 原文地址:https://www.cnblogs.com/workstation-liunianguowang/p/5681944.html
Copyright © 2020-2023  润新知