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

本文涉及的产品
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
简介:

介绍

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

 
  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 == nullreturn
  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 == nullreturn
  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 == nullreturn 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(010
  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缓存中存储大量容积的内容。用户依赖的对象举例——个人资料信息,个性化信息 。常用对象——本地化数据,不同用户之间的共享信息,等等。


作者:小峰

来源:51CTO

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
5天前
|
消息中间件 缓存 NoSQL
Redis经典问题:缓存雪崩
本文介绍了Redis缓存雪崩问题及其解决方案。缓存雪崩是指大量缓存同一时间失效,导致请求涌入数据库,可能造成系统崩溃。解决方法包括:1) 使用Redis主从复制和哨兵机制提高高可用性;2) 结合本地ehcache缓存和Hystrix限流降级策略;3) 设置随机过期时间避免同一时刻大量缓存失效;4) 使用缓存标记策略,在标记失效时更新数据缓存;5) 实施多级缓存策略,如一级缓存失效时由二级缓存更新;6) 通过第三方插件如RocketMQ自动更新缓存。这些策略有助于保障系统的稳定运行。
136 1
|
8天前
|
存储 消息中间件 缓存
Redis缓存技术详解
【5月更文挑战第6天】Redis是一款高性能内存数据结构存储系统,常用于缓存、消息队列、分布式锁等场景。其特点包括速度快(全内存存储)、丰富数据类型、持久化、发布/订阅、主从复制和分布式锁。优化策略包括选择合适数据类型、设置过期时间、使用Pipeline、开启持久化、监控调优及使用集群。通过这些手段,Redis能为系统提供高效稳定的服务。
|
3天前
|
缓存 NoSQL 安全
Redis经典问题:缓存击穿
本文探讨了高并发系统中Redis缓存击穿的问题及其解决方案。缓存击穿指大量请求同一未缓存数据,导致数据库压力过大。为解决此问题,可以采取以下策略:1) 热点数据永不过期,启动时加载并定期异步刷新;2) 写操作加互斥锁,保证并发安全并设置查询失败返回默认值;3) 预期热点数据直接加缓存,系统启动时加载并设定合理过期时间;4) 手动操作热点数据上下线,通过界面控制缓存刷新。这些方法能有效增强系统稳定性和响应速度。
59 0
|
4天前
|
缓存 NoSQL 应用服务中间件
Redis多级缓存
Redis多级缓存
8 0
|
4天前
|
缓存 NoSQL 关系型数据库
Redis 缓存 一致性
Redis 缓存 一致性
7 0
|
4天前
|
缓存 监控 NoSQL
Redis经典问题:缓存穿透
本文介绍了缓存穿透问题在分布式系统和缓存应用中的严重性,当请求的数据在缓存和数据库都不存在时,可能导致数据库崩溃。为解决此问题,提出了五种策略:接口层增加校验、缓存空值、使用布隆过滤器、数据库查询优化和加强监控报警机制。通过这些方法,可以有效缓解缓存穿透对系统稳定性的影响。
84 3
|
5天前
|
缓存 NoSQL 搜索推荐
Redis缓存雪崩穿透等解决方案
本文讨论了缓存使用中可能出现的问题及其解决方案。首先,缓存穿透是指查询数据库中不存在的数据,导致请求频繁到达数据库。解决方法包括数据校验、缓存空值和使用BloomFilter。其次,缓存击穿是大量请求同一失效缓存项,可采取监控、限流或加锁策略。再者,缓存雪崩是大量缓存同时失效,引发数据库压力。应对措施是避免同一失效时间,分散缓存过期。接着,文章介绍了Spring Boot中Redis缓存的配置,包括缓存null值以防止穿透,并展示了自定义缓存过期时间的实现,以避免雪崩效应。最后,提供了在`application.yml`中配置不同缓存项的个性化过期时间的方法。
|
14天前
|
存储 缓存 NoSQL
【Go语言专栏】Go语言中的Redis操作与缓存应用
【4月更文挑战第30天】本文探讨了在Go语言中使用Redis进行操作和缓存应用的方法。文章介绍了Redis作为高性能键值存储系统,用于提升应用性能。推荐使用`go-redis/redis`库,示例代码展示了连接、设置、获取和删除键值对的基本操作。文章还详细阐述了缓存应用的步骤及常见缓存策略,包括缓存穿透、缓存击穿和缓存雪崩的解决方案。利用Redis和合适策略可有效优化应用性能。
|
17天前
|
存储 缓存 NoSQL
Redis多级缓存指南:从前端到后端全方位优化!
本文探讨了现代互联网应用中,多级缓存的重要性,特别是Redis在缓存中间件的角色。多级缓存能提升数据访问速度、系统稳定性和可扩展性,减少数据库压力,并允许灵活的缓存策略。浏览器本地内存缓存和磁盘缓存分别优化了短期数据和静态资源的存储,而服务端本地内存缓存和网络内存缓存(如Redis)则提供了高速访问和分布式系统的解决方案。服务器本地磁盘缓存因I/O性能瓶颈和复杂管理而不推荐用于缓存,强调了内存和网络缓存的优越性。
132 47
|
9天前
|
缓存 监控 NoSQL
Redis缓存雪崩及应对策略
缓存雪崩是分布式系统中一个常见但危险的问题,可以通过合理的缓存策略和系统设计来降低发生的概率。采用多层次的缓存架构、缓存预热、合理的缓存失效时间等措施,都可以有效应对缓存雪崩,提高系统的稳定性和性能。在实际应用中,及时发现并解决潜在的缓存雪崩问题,是保障系统可用性的关键一环。
39 14