当前位置:

首页 > 编程开发 > 如何使用redis实现分布式缓存

如何使用redis实现分布式缓存

Redis Assistant
Redis Assistant

Redis Assistant 是一款为Redis设计的高效可视化管理与监控工具,提供多种操作模式,高效处理服务器数据。日常使用里的持续防护和信息管理会更突出,适合把安全控制放进长期使用流程中的场景。

立即下载
¥19
Windows/macOS/Linux 2026-08-22
正版软件 Windows macOS软件 Linux 数据库管理工具

分布式缓存描述:分布式缓存重点是在分布式上,相信大家接触过的分布式有很多中,像分布式开发,分布式部署,分布式锁、事物、系统等有很多。使我们对分布式本身就有一个很明确的认识,分布式就是有多个应用程序组成,可能分布在不同的服务器上,最终都是在为web端提供服务。分布式缓存有以下几点优点:所有的Web服务器上的缓存数据都是相同的,不会因为应用程序不同,服务器的不同导致缓存数据的不一样。缓存的是独立的不受Web服务器的重新启动或被删除添加的影响,也就是说这些Web的改变不到导致缓存数据的改变。传统的单体应用架构因

本文目录

    如何使用redis实现分布式缓存

    分布式缓存描述:

    分布式缓存重点是在分布式上,相信大家接触过的分布式有很多中,像分布式开发,分布式部署,分布式锁、事物、系统 等有很多。使我们对分布式本身就有一个很明确的认识,分布式就是有多个应用程序组成,可能分布在不同的服务器上,最终都是在为web端提供服务。
    分布式缓存有以下几点优点:

    1. 所有的Web服务器上的缓存数据都是相同的,不会因为应用程序不同,服务器的不同导致缓存数据的不一样。

    2. 缓存的是独立的不受Web服务器的重新启动或被删除添加的影响,也就是说这些Web的改变不到导致缓存数据的改变。

    传统的单体应用架构因为用户的访问量的不高,缓存的存在大多数都是存储用户的信息,以及一些页面,大多数的操作都是直接和DB进行读写交互,这种架构简单,也称为简单架构,
    传统的OA项目比如ERP,SCM,CRM等系统因为用户量不大也是因为大多数公司业务的原因,单体应用架构还是很常用的架构,但是有些系统随着用户量的增加,业务的扩张扩展,导致DB的瓶颈的出现。

    以下我所了解到的关于这种情况的处理有以下两种

    (1):当用户访问量不大,但是读写的数据量很大的时候,我们一般采取的是,对DB进行读写分离、一主多从、对硬件进行升级的方式来解决DB瓶颈的问题。
      这样的缺点也同样纯在:

    1、用户量大的时候怎么办?,
    2、对于性能的提升有限,
    3、性价比不高。提升一点性能就需要花费很多代价,(打个比方,现在的I/O吞吐量是0.9的需要提升到1.0,我们在增加机器配置的情况下这个价格确实很可观的)

    (2):当用户访问量也增加的时候,我们就需要引入缓存了来解决了,一张图描述缓存的大致的作用。

    如何使用redis实现分布式缓存

    缓存主要针对的是不经常发生改变的并且访问量很大的数据,DB数据库可以理解为只作为数据固化的或者只用来读取经常发生改变的数据,上图中我没有画SET的操作,就是想特意说明一下,缓存的存在可以作为一个临时的数据库,我们可以通过定时的任务的方式去同步缓存和数据库中的数据,这样做的好处是可以转移数据库的压力到缓存中。

    缓存的出现解决了数据库压力的问题,但是当以下情况发生的时候,缓存就不在起到作用了,缓存穿透、缓存击穿、缓存雪崩这三种情况。

    缓存穿透:我们的程序中用缓存的时候一般采取的是先去缓存中查询我们想要的缓存数据,如果缓存中不存在我们想要的数据的话,缓存就失去了做用(缓存失效)我们就是需要伸手向DB库去要数据,这个时候这种动作过多数据库就崩溃了,这种情况需要我们去预防了。比如说:我们向缓存获取一个用户信息,但是故意去输入一个缓存中不存在的用户信息,这样就避过了缓存,把压力重新转移到数据上面了。对于这种问题我们可以采取,把第一次访问的数据进行缓存,因为缓存查不到用户信息,数据库也查询不到用户信息,这个时候避免重复的访问我们把这个请求缓存起来,把压力重新转向缓存中,有人会有疑问了,当访问的参数有上万个都是不重复的参数并且都是可以躲避缓存的怎么办,我们同样把数据存起来设置一个较短过期时间清理缓存。

    缓存击穿:事情是这样的,对于一些设置了过期时间的缓存KEY,在过期的时候,程序被高并发的访问了(缓存失效),这个时候使用互斥锁来解决问题,

    互斥锁原理:通俗的描述就是,一万个用户访问了,但是只有一个用户可以拿到访问数据库的权限,当这个用户拿到这个权限之后重新创建缓存,这个时候剩下的访问者因为没有拿到权限,就原地等待着去访问缓存。

    永不过期:有人就会想了,我不设置过期时间不就行了吗?可以,但是这样做也是有缺点的,我们需要定期的取更新缓存,这个时候缓存中的数据比较延迟。

    缓存雪崩:是指多种缓存设置了同一时间过期,这个时候大批量的数据访问来了,(缓存失效)数据库DB的压力又上来了。解决方法在设置过期时间的时候在过期时间的基础上增加一个随机数尽可能的保证缓存不会大面积的同事失效。

    项目准备

    1、首先安装Redis
    2、然后下载安装:客户端工具:RedisDesktopManager(方便管理)
    3、在我们的项目Nuget中 引用 Microsoft.Extensions.Caching.Redis

    为此我们新建一个ASP.NET Core MVC项目,在项目Startup类的ConfigureServices方法中先注册Redis服务:

    public void ConfigureServices(IServiceCollection services)
    {
        //将Redis分布式缓存服务添加到服务中
        services.AddDistributedRedisCache(options =>
        {
            //用于连接Redis的配置  Configuration.GetConnectionString("RedisConnectionString")读取配置信息的串
            options.Configuration = "localhost";// Configuration.GetConnectionString("RedisConnectionString");
            //Redis实例名DemoInstance
            options.InstanceName = "DemoInstance";
        });
        services.AddMvc();
    }

    也可以在上面注册Redis服务的时候,指定Redis服务器的IP地址、端口号和登录密码:

    public void ConfigureServices(IServiceCollection services)
    {
        //将Redis分布式缓存服务添加到服务中
        services.AddDistributedRedisCache(options =>
        {
            //用于连接Redis的配置  Configuration.GetConnectionString("RedisConnectionString")读取配置信息的串
            options.Configuration = "192.168.1.105:6380,password=1qaz@WSX3edc$RFV";//指定Redis服务器的IP地址、端口号和登录密码
            //Redis实例名DemoInstance
            options.InstanceName = "DemoInstance";
        });
        services.AddMvc();
    }

    后面我们会解释上面options.InstanceName设置的Redis实例名DemoInstance是用来做什么的

    此外还可以在services.AddDistributedRedisCache方法中指定Redis服务器的超时时间,如果调用后面介绍的IDistributedCache接口中的方法,对Redis服务器进行的操作超时了,会抛出RedisConnectionException和RedisTimeoutException异常,所以下面我们在注册Redis服务的时候,指定了三个超时时间:

    public void ConfigureServices(IServiceCollection services)
    {
        //将Redis分布式缓存服务添加到服务中
        services.AddDistributedRedisCache(options =>
        {
            options.ConfigurationOptions = new StackExchange.Redis.ConfigurationOptions()
            {
                Password = "1qaz@WSX3edc$RFV",
                ConnectTimeout = 5000,//设置建立连接到Redis服务器的超时时间为5000毫秒
                SyncTimeout = 5000,//设置对Redis服务器进行同步操作的超时时间为5000毫秒
                ResponseTimeout = 5000//设置对Redis服务器进行操作的响应超时时间为5000毫秒
            };
    
            options.ConfigurationOptions.EndPoints.Add("192.168.1.105:6380");
            options.InstanceName = "DemoInstance";
        });
        services.AddMvc();
    }

    其中ConnectTimeout是建立连接到Redis服务器的超时时间,而SyncTimeout和ResponseTimeout是对Redis服务器进行数据操作的超时时间。注意上面我们使用了options.ConfigurationOptions属性来设置Redis服务器的IP地址、端口号和登录密码

    IDistributedCache 接口

    在项目中引用:using Microsoft.Extensions.Caching.Distributed; 使用IDistributedCache

    IDistributedCache接口包含同步和异步方法。 接口允许在分布式缓存实现中添加、检索和删除项。 IDistributedCache接口包含以下方法:
    Get、 GetAsync
    采用字符串键并以byte[]形式检索缓存项(如果在缓存中找到)。
    Set、SetAsync
    使用字符串键向缓存添加或更改项(byte[]形式)。
    Refresh、RefreshAsync
    根据键刷新缓存中的项,并重置其可调过期超时值(如果有)。
    Remove、RemoveAsync
    根据键删除缓存项。如果传入Remove方法的键在Redis中不存在,Remove方法不会报错,只是什么都不会发生而已,但是如果传入Remove方法的参数为null,则会抛出异常。

    如上所述,由于IDistributedCache接口的Set和Get方法,是通过byte[]字节数组来向Redis存取数据的,所以从某种意义上来说不是很方便,下面我封装了一个RedisCache类,可以向Redis中存取任何类型的数据。

    其中用到了Json.NET Nuget包,来做Json格式的序列化和反序列化:

    using Microsoft.Extensions.Caching.Distributed;
    using Newtonsoft.Json;
    using System.Text;
    
    namespace AspNetCoreRedis.Assembly
    {
        /// 
        /// RedisCache缓存操作类
        /// 
        public class RedisCache
        {
            protected IDistributedCache cache;
    
            /// 
            /// 通过IDistributedCache来构造RedisCache缓存操作类
            /// 
            /// IDistributedCache对象
            public RedisCache(IDistributedCache cache)
            {
                this.cache = cache;
            }
    
            /// 
            /// 添加或更改Redis的键值,并设置缓存的过期策略
            /// 
            /// 缓存键
            /// 缓存值
            /// 设置Redis缓存的过期策略,可以用其设置缓存的绝对过期时间(AbsoluteExpiration或AbsoluteExpirationRelativeToNow),也可以设置缓存的滑动过期时间(SlidingExpiration)
            public void Set(string key, object value, DistributedCacheEntryOptions distributedCacheEntryOptions)
            {
                //通过Json.NET序列化缓存对象为Json字符串
                //调用JsonConvert.SerializeObject方法时,设置ReferenceLoopHandling属性为ReferenceLoopHandling.Ignore,来避免Json.NET序列化对象时,因为对象的循环引用而抛出异常
                //设置TypeNameHandling属性为TypeNameHandling.All,这样Json.NET序列化对象后的Json字符串中,会包含序列化的类型,这样可以保证Json.NET在反序列化对象时,去读取Json字符串中的序列化类型,从而得到和序列化时相同的对象类型
                var stringObject = JsonConvert.SerializeObject(value, new JsonSerializerSettings()
                {
                    ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
                    TypeNameHandling = TypeNameHandling.All
                });
    
                var bytesObject = Encoding.UTF8.GetBytes(stringObject);//将Json字符串通过UTF-8编码,序列化为字节数组
    
                cache.Set(key, bytesObject, distributedCacheEntryOptions);//将字节数组存入Redis
                Refresh(key);//刷新Redis
            }
    
            /// 
            /// 查询键值是否在Redis中存在
            /// 
            /// 缓存键
            /// true:存在,false:不存在
            public bool Exist(string key)
            {
                var bytesObject = cache.Get(key);//从Redis中获取键值key的字节数组,如果没获取到,那么会返回null
    
                if (bytesObject == null)
                {
                    return false;
                }
    
                return true;
            }
    
            /// 
            /// 从Redis中获取键值
            /// 
            /// 缓存的类型
            /// 缓存键
            /// 是否获取到键值,true:获取到了,false:键值不存在
            /// 缓存的对象
            public T Get(string key, out bool isExisted)
            {
                var bytesObject = cache.Get(key);//从Redis中获取键值key的字节数组,如果没获取到,那么会返回null
    
                if (bytesObject == null)
                {
                    isExisted = false;
                    return default(T);
                }
    
                var stringObject = Encoding.UTF8.GetString(bytesObject);//通过UTF-8编码,将字节数组反序列化为Json字符串
    
                isExisted = true;
    
                //通过Json.NET反序列化Json字符串为对象
                //调用JsonConvert.DeserializeObject方法时,也设置TypeNameHandling属性为TypeNameHandling.All,这样可以保证Json.NET在反序列化对象时,去读取Json字符串中的序列化类型,从而得到和序列化时相同的对象类型
                return JsonConvert.DeserializeObject(stringObject, new JsonSerializerSettings()
                {
                    TypeNameHandling = TypeNameHandling.All
                });
            }
    
            /// 
            /// 从Redis中删除键值,如果键值在Redis中不存在,该方法不会报错,只是什么都不会发生
            /// 
            /// 缓存键
            public void Remove(string key)
            {
                cache.Remove(key);//如果键值在Redis中不存在,IDistributedCache.Remove方法不会报错,但是如果传入的参数key为null,则会抛出异常
            }
    
            /// 
            /// 从Redis中刷新键值
            /// 
            /// 缓存键
            public void Refresh(string key)
            {
                cache.Refresh(key);
            }
        }
    }

    使用测试

    然后我们在ASP.NET Core MVC项目中,新建一个CacheController,然后在其Index方法中来测试RedisCache类的相关方法:

    public class CacheController : Controller
    {
        protected RedisCache redisCache;
    
        //由于我们前面在Startup类的ConfigureServices方法中调用了services.AddDistributedRedisCache来注册Redis服务,所以ASP.NET Core MVC会自动依赖注入下面的IDistributedCache cache参数
        public CacheController(IDistributedCache cache)
        {
            redisCache = new RedisCache(cache);
        }
    
        public IActionResult Index()
        {
            bool isExisted;
            isExisted = redisCache.Exist("abc");//查询键值"abc"是否存在
            redisCache.Remove("abc");//删除不存在的键值"abc",不会报错
    
            string key = "Key01";//定义缓存键"Key01"
            string value = "This is a demo key !";//定义缓存值
    
            redisCache.Set(key, value, new DistributedCacheEntryOptions()
            {
                AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(10)
            });//设置键值"Key01"到Redis,使用绝对过期时间,AbsoluteExpirationRelativeToNow设置为当前系统时间10分钟后过期
    
            //也可以通过AbsoluteExpiration属性来设置绝对过期时间为一个具体的DateTimeOffset时间点
            //redisCache.Set(key, value, new DistributedCacheEntryOptions()
            //{
            //    AbsoluteExpiration = DateTimeOffset.Now.AddMinutes(10)
            //});//设置键值"Key01"到Redis,使用绝对过期时间,AbsoluteExpiration设置为当前系统时间10分钟后过期
    
            var getVaue = redisCache.Get(key, out isExisted);//从Redis获取键值"Key01",可以看到getVaue的值为"This is a demo key !"
    
            value = "This is a demo key again !";//更改缓存值
    
            redisCache.Set(key, value, new DistributedCacheEntryOptions()
            {
                SlidingExpiration = TimeSpan.FromMinutes(10)
            });//将更改后的键值"Key01"再次缓存到Redis,这次使用滑动过期时间,SlidingExpiration设置为10分钟
    
            getVaue = redisCache.Get(key, out isExisted);//再次从Redis获取键值"Key01",可以看到getVaue的值为"This is a demo key again !"
    
            redisCache.Remove(key);//从Redis中删除键值"Key01"
    
            return View();
        }
    }

    前面我们在项目的Startup类ConfigureServices方法中,调用services.AddDistributedRedisCache注册Redis服务的时候,有设置options.InstanceName = "DemoInstance",那么这个InstanceName到底有什么用呢?

    当我们在上面的CacheController中调用Index方法的下面代码后:

    string key = "Key01";//定义缓存键"Key01"
    string value = "This is a demo key !";//定义缓存值
    
    redisCache.Set(key, value, new DistributedCacheEntryOptions()
    {
        AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(10)
    });//设置键值"Key01"到Redis,使用绝对过期时间,AbsoluteExpirationRelativeToNow设置为当前系统时间10分钟后过期

    我们使用redis-cli登录到Redis服务器中,使用Keys *指令查看当前Redis服务中存储的所有键时,可以看到结果如下:

    如何使用redis实现分布式缓存

    可以看到虽然我们代码中向Redis存入的键是"Key01",但是实际上在Redis服务中存储的键是"DemoInstanceKey01",所以实际上真正存入Redis服务中的键是“InstanceName+键”这种组合键,因此我们可以通过设置不同的InstanceName来为不同的Application在Redis中做数据隔离,这就是InstanceName的作用

    本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系bd@zhengruan.com
    作者最新文章
    编程开发
    相关文章 更多
    php72w redis,docker php7安装php-redis
    php72w redis,docker php7安装php-redis

    在Docker环境下为PHP安装Redis扩展:手动编译需下载源码、安装phpize、配置编译并安装,生成redis.so并在php.d目录新建redis.ini加载,重启PHP-FPM;也可直接yum安装php72w-pecl-redis,免手动编译。

    php 如何配置 redis,php 如何设置redis
    php 如何配置 redis,php 如何设置redis

    配置PHP的Redis扩展:先安装Redis服务,从GitHub下载phpredis源码,用phpize编译安装,修改php.ini添加extension=redis.so,重启php-fpm或Apache,通过phpinfo验证并连接Redis。

    c++如何将结构体序列化为Redis兼容的RESP协议格式【深度】
    c++如何将结构体序列化为Redis兼容的RESP协议格式【深度】

    C++结构体无法直接序列化为RESP协议,需手动将字段映射为*N数组嵌套$lenbulkstring形式。整数需转换为字符串并加:前缀,空字符串用$0\r\n,null用$-1\r\n。长度计算需精确到字节数,特别注意二进制安全,同时确保字段顺序与结构体定义一致。

    如何在Golang架构中部署Redict作为高能数据临时存储中转站
    如何在Golang架构中部署Redict作为高能数据临时存储中转站

    Redis作为跨服务临时状态枢纽,需按消息队列、缓存和原子状态三重角色设计。选型用List实现任务分发及延迟重试,Stream用于事件广播与位点回溯。go-redis/v8需配置MinIdleConns、MaxRetries及超时。数据写入应JSON序列化并带type标签、设合理TTL、将关键字段提至顶层。消费通过原子GET+DEL或processedkey

    TP8.0 高并发下库存超卖?Redis 原子递减结合数据库乐观锁控制
    TP8.0 高并发下库存超卖?Redis 原子递减结合数据库乐观锁控制

    在高并发秒杀场景下,利用Redis的减库存原子操作预扣减库存拦截超卖请求,再通过数据库乐观锁(版本号与库存校验)确保最终一致性,异常时回滚Redis库存并借助Lua脚本保证原子性,从而有效防止库存超卖。

    如何在 Go 中利用 go-redis 执行 Lua 脚本优化逻辑
    如何在 Go 中利用 go-redis 执行 Lua 脚本优化逻辑

    在Go中使用go-redis执行Lua脚本可借助原子性解决竞态问题,通过redis.Script封装脚本并自动处理SHA1缓存与重试。需注意KEYS必须为非空切片且所有键在Cluster模式下落在同一slot,ARGV以字符串传入并由tonumber转换。返回值需先检查错误再调用Val(),避免panic。

    TP6.0 基于 Redis SetNX 实现的简单互斥锁机制【并发】
    TP6.0 基于 Redis SetNX 实现的简单互斥锁机制【并发】

    先看一个典型场景:电商秒杀、库存扣减、定时任务重复调度——这些并发冲突在 TP6 应用里屡见不鲜。用 Redis 的 SETNX 做互斥锁,确实是轻量又直接的方案,但“能用”和“稳妥”之间,隔着三层硬功夫:原子加锁、身份校验、合理超时。这三条,差一条就翻车。 很多人第一次上手,直接写 SETNX 加

    TP6.0 如何处理高并发抢购?Redis 原子锁与队列削峰详解【秒杀】
    TP6.0 如何处理高并发抢购?Redis 原子锁与队列削峰详解【秒杀】

    高并发抢购中,Redis的DECR原子操作可安全扣库存;配合think-queue异步削峰,接口仅扣库存和推消息;分布式锁需用SETNXEX加唯一标识,释放时用Lua脚本校验;成功资格后须以数据库事务双写为准,失败时补回Redis库存。

    Golang 实现基于 Redis 的延时任务队列
    Golang 实现基于 Redis 的延时任务队列

    基于Redis的ZSET实现延时队列需解决并发重复消费、失败重试混乱、精度不足及内存爆炸等问题。通过Lua脚本保证取删原子性,使用毫秒级时间戳,对临时错误采用指数退避重试,永久错误记入独立哈希表,并限制最大延迟、定期清理过期任务、使用紧凑序列化格式。

    RedisInsight怎么修改Key的过期时间 Redis操作方法【步骤】
    RedisInsight怎么修改Key的过期时间 Redis操作方法【步骤】

    操作 Redis 的时候,改个 Key 的过期时间其实是个高频场景。特别是做运维排查或者临时调试那会儿,谁也不想反复切命令行窗口、背那些命令参数。好在 RedisInsight 这个图形工具把这事儿做得很顺手——三种方式任选,总有一种合你胃口。 在动手前,先确认一下 Key 当前的 TTL 状态是个

    查看更多
    精品专题 更多
    装机必备
    装机必备

    正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

    Windows
    Windows

    正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

    PDF教程
    PDF教程

    正软商城PDF教程频道提供PDF编辑、转换、合并、拆分、压缩及格式处理方法,同时介绍常用PDF软件和工具的使用技巧。

    Mac软件 更多
    讯飞智作 网页版
    讯飞智作 网页版
    Windows/ macOS/ Linux

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    火山引擎 网页版
    火山引擎 网页版
    Windows/ macOS/ Linux

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    Aperty macOS版
    Aperty macOS版
    macOS

    Aperty 是 Skylum 推出的 AI 人像修图软件,支持自然肤质修饰、瑕疵处理、面部与身体调整、预设及批量同步。

    WINDOWS 更多
    讯飞智作 网页版
    讯飞智作 网页版
    Windows/ macOS/ Linux

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    火山引擎 网页版
    火山引擎 网页版
    Windows/ macOS/ Linux

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    PixTV 网页版
    PixTV 网页版
    Windows

    PixTV 是一款在浏览器中使用的 AI 视觉内容创作平台,提供图片、视频、音频、文字生成、AI 分镜、局部重绘、提示词反推和无限画布等工具,适合短剧、漫剧、广告及社交媒体内容制作。

    即将离开本站
    您即将前往第三方网站,请确认是否继续?