Redis缓存、MemCached和.Net内部缓存的切换使用

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
简介: 接口文件: //IDataCache.cs using System;using System.Collections.Generic;using System.

接口文件:

//IDataCache.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ypsuit.common
{
    public interface IDataCache
    {
        /// <summary>
        /// 获取缓存
        /// </summary>
        /// <typeparam name="T">类型</typeparam>
        /// <param name="key">缓存key</param>
        /// <returns></returns>
        T Get<T>(string key);
        T Get<T>(string key,string depFile);

        /// <summary>
        /// 写入缓存
        /// </summary>
        /// <typeparam name="T">类型</typeparam>
        /// <param name="key">缓存key</param>
        /// <param name="value">缓存值</param>
        /// <returns>返回值,表示:是否写入成功</returns>
        bool Set<T>(string key, T value);

        /// <summary>
        /// 写入缓存,设置过期时间点
        /// </summary>
        /// <typeparam name="T">类型</typeparam>
        /// <param name="key">缓存key</param>
        /// <param name="value">缓存值</param>
        /// <param name="expiresAt">过期时间点</param>
        /// <returns>返回值,表示:是否写入成功</returns>
        bool Set<T>(string key, T value, DateTime expiresAt);

        /// <summary>
        /// 写入缓存,设置过期秒数
        /// </summary>
        /// <typeparam name="T">类型</typeparam>
        /// <param name="key">缓存key</param>
        /// <param name="value">缓存值</param>
        /// <param name="expiresSecond">过期秒数</param>
        /// <returns>返回值,表示:是否写入成功</returns>
        bool Set<T>(string key, T value, int expiresSecond);

        bool Set<T>(string key, T value, string depFile);

        /// <summary>
        /// 删除缓存
        /// </summary>
        /// <param name="key">缓存key</param>
        /// <returns></returns>
        int Delete(string key);

        /// <summary>
        /// 删除多个缓存
        /// </summary>
        /// <param name="keys">缓存key数组</param>
        /// <returns></returns>
        int Delete(string[] keys);
    }
}


//实现文件
//RedisCache.cs

using ServiceStack.Redis;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;

namespace ypsuit.common
{
    /// <summary>
    /// Redis缓存服务器
    /// 服务器和客户端下载:
    ///  https://github.com/MSOpenTech/redis/releases
    ///  https://github.com/ServiceStack/ServiceStack.Redis
    /// </summary>
    public class RedisCache : IDataCache
    {
        private static RedisClient _redis = null;
        public static RedisClient redis
        {
            get
            {
                if (_redis == null) _redis = new RedisClient("192.168.9.128", 6379);//要开启服务器才能连接
                return _redis;
            }
        }

        ~RedisCache()
        {
            //if (_redis != null) _redis.Shutdown();
        }
        
        /// <summary>
        /// 获取缓存
        /// </summary>
        /// <typeparam name="T">类型(对象必须可序列化,否则可以作为object类型取出再类型转换,不然会报错)</typeparam>
        /// <param name="key">缓存key</param>
        /// <returns></returns>
        public T Get<T>(string key)
        {
            return redis.Get<T>(key);
        }
        public T Get<T>(string key, string depFile)
        {
            string timeKey = key + "_time";
            if (redis.Exists(timeKey) > 0 && redis.Exists(key) > 0)
            {
                DateTime obj_time = Get<DateTime>(timeKey);
                T obj_cache = Get<T>(key);
                if (File.Exists(depFile))
                {
                    FileInfo fi = new FileInfo(depFile);
                    if (obj_time != fi.LastWriteTime)
                    {
                        Delete(key);
                        Delete(timeKey);
                        return default(T);
                    }
                    else return obj_cache;
                }
                else
                {
                    throw new Exception("文件(" + depFile + ")不存在!");
                }
            }
            else return default(T);

        }

        public bool Set<T>(string key, T value)
        {
            return redis.Set<T>(key, value);
        }
        public bool Set<T>(string key, T value, DateTime expiresAt)
        {
            return redis.Set<T>(key, value, expiresAt);
        }

        public bool Set<T>(string key, T value, int expiresSecond)
        {
            return redis.Set<T>(key, value, DateTime.Now.AddSeconds(expiresSecond));
        }

        public bool Set<T>(string key, T value, string depFile)
        {
            bool ret1 = redis.Set<T>(key, value);
            if (ret1 && File.Exists(depFile))
            {
                FileInfo fi = new FileInfo(depFile);
                DateTime lastWriteTime = fi.LastWriteTime;
                return redis.Set<DateTime>(key + "_time", lastWriteTime);
            }
            return false;
        }

        public int Delete(string key)
        {
            return redis.Del(key);
        }
        public int Delete(string[] keys)
        {
            return redis.Del(keys);
        }
        public void Dispose()
        {
            if (_redis != null) _redis.Shutdown();//调用Dispose释放memcached客户端连接
        }

    }
}

//实现文件

//MemcachedCache.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Memcached.ClientLibrary;
using System.IO;

namespace ypsuit.common
{
    public class MemcachedCache:IDataCache
    {
        private MemcachedClient _mc =null; 
        protected MemcachedClient mc
        {
            get
            {
                if(_mc==null) _mc=new MemcachedClient();//初始化一个客户端 
                return _mc;
            }
        }
        /// <summary>
        /// 如果默认不是本地服务,可以额外指定memcached服务器地址
        /// </summary>
        public static string[] serverList
        {
            get;
            set;
        }
        private static MemcachedCache _instance = null;
        /// <summary>
        /// 单例实例对象,外部只能通过MemcachedHelper.instance使用memcached
        /// </summary>
        public static MemcachedCache instance
        {
            get
            {
                if (_instance == null)
                {
                    if (serverList != null && serverList.Length > 0)
                        _instance = new MemcachedCache(serverList);
                    else _instance = new MemcachedCache();
                }
                
                return _instance;
            }
        }
        SockIOPool pool;
        private void start(params string[]servers)
        {
            string[] serverlist;
            if (servers == null || servers.Length < 1)
            {
                serverlist = new string[] { "127.0.0.1:11011" }; //服务器列表,可多个
            }
            else
            {
                serverlist=servers;
            }
            pool = SockIOPool.GetInstance();

            //根据实际情况修改下面参数
            pool.SetServers(serverlist);
            pool.InitConnections = 3;
            pool.MinConnections = 3;
            pool.MaxConnections = 5;
            pool.SocketConnectTimeout = 1000;
            pool.SocketTimeout = 3000;
            pool.MaintenanceSleep = 30;
            pool.Failover = true;
            pool.Nagle = false;
            pool.Initialize(); // initialize the pool for memcache servers      
        }
        public MemcachedCache(string[] servers)
        {
            start(servers);
        }
        public MemcachedCache()
        {
            start();
        }
        ~MemcachedCache()
        {
            //if (pool != null) pool.Shutdown();
        }

        public T Get<T>(string key)
        {
            object data = mc.Get(key);
            if (data is T) return (T)data;
            else return default(T);
        }
        public T Get<T>(string key, string depFile)
        {
            string timeKey = key + "_time";
            if (mc.KeyExists(timeKey) && mc.KeyExists(key))
            {
                DateTime obj_time = Get<DateTime>(timeKey);
                T obj_cache = Get<T>(key);
                if (File.Exists(depFile))
                {
                    FileInfo fi = new FileInfo(depFile);
                    if (obj_time != fi.LastWriteTime)
                    {
                        Delete(key);
                        Delete(timeKey);
                        return default(T);
                    }
                    else return obj_cache;
                }
                else
                {
                    throw new Exception("文件(" + depFile + ")不存在!");
                }
            }
            else return default(T);

        }
        public bool Set<T>(string key, T value)
        {
            return mc.Set(key, value);
        }
        public bool Set<T>(string key, T value, DateTime expiresAt)
        {
            return mc.Set(key, value, expiresAt);
        }

        public bool Set<T>(string key, T value, int expiresSecond)
        {
            return mc.Set(key, value, DateTime.Now.AddSeconds(expiresSecond));
        }

        public bool Set<T>(string key, T value, string depFile)
        {
            bool ret1 = mc.Set(key, value);
            if (ret1 && File.Exists(depFile))
            {
                FileInfo fi = new FileInfo(depFile);
                DateTime lastWriteTime = fi.LastWriteTime;
                return mc.Set(key + "_time", lastWriteTime);
            }
            return false;
        }


        public int Delete(string key)
        {
            return mc.Delete(key)?1:0;
        }
        public int Delete(string[] keys)
        {
            int i = 0;
            foreach (var key in keys)
            {
                mc.Delete(key);
                i++;
            }
            return i;
        }
        //在应用程序退出之前,调用Dispose释放memcached客户端连接
        public void Dispose()
        {
            if (pool != null) pool.Shutdown();
        }
    }
}

//实现文件

//RuntimeCache.cs

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.Caching;

namespace ypsuit.common
{
    public class RuntimeCache : IDataCache
    {

        #region 删除缓存
        /// <summary>
        /// 删除缓存
        /// </summary>
        /// <param name="CacheKey">键</param>
        public int Delete(string CacheKey)
        {
            HttpRuntime.Cache.Remove(CacheKey);
            return 1;
        }
        public int Delete(string[] CacheKeys)
        {
            int i = 0;
            foreach (var key in CacheKeys)
            {
                HttpRuntime.Cache.Remove(key);
                i++;
            }
            return i;
        }
        #endregion

        #region 获取缓存,依赖时间
        /// <summary>
        /// 获取缓存,依赖时间
        /// </summary>
        /// <param name="CacheKey">键</param>
        /// <returns></returns>
        public T Get<T>(string CacheKey)
        {
            object obj_time = HttpRuntime.Cache[CacheKey + "_time"];
            object obj_cache = HttpRuntime.Cache[CacheKey];
            if (obj_time != null && obj_cache != null)
            {
                if (Convert.ToDateTime(obj_time) < DateTime.Now)
                {
                    Delete(CacheKey);
                    Delete(CacheKey + "_time");
                    return default(T);
                }
                else return (T)obj_cache;
            }
            else
            {
                Delete(CacheKey);
                Delete(CacheKey + "_time");
                return default(T);
            }
        }
        #endregion

        #region 获取缓存,依赖文件
        /// <summary>
        /// 获取缓存,依赖文件
        /// </summary>
        /// <param name="CacheKey">键</param>
        /// <param name="depFile">依赖的文件</param>
        /// <returns></returns>
        public T Get<T>(string CacheKey, string depFile)
        {
            object obj_time = HttpRuntime.Cache[CacheKey + "_time"];
            object obj_cache = HttpRuntime.Cache[CacheKey];
            if (File.Exists(depFile))
            {
                FileInfo fi = new FileInfo(depFile);

                if (obj_time != null && obj_cache != null)
                {
                    if (Convert.ToDateTime(obj_time) != fi.LastWriteTime)
                    {
                        Delete(CacheKey);
                        Delete(CacheKey + "_time");
                        return default(T);
                    }
                    else return (T)obj_cache;
                }
                else
                {
                    Delete(CacheKey);
                    Delete(CacheKey + "_time");
                    return default(T);
                }
            }
            else
            {
                throw new Exception("文件(" + depFile + ")不存在!");
            }
        }
        #endregion

        #region 简单的插入缓存
        /// <summary>
        /// 简单的插入缓存
        /// </summary>
        /// <param name="CacheKey">键</param>
        /// <param name="objObject">数据</param>
        public bool Set<T>(string CacheKey, T objObject)
        {
            HttpRuntime.Cache.Insert(CacheKey, objObject);
            return true;
        }
        #endregion

        #region 有过期时间的插入缓存数据
        public bool Set<T>(string CacheKey, T objObject, DateTime expiresAt)
        {
            HttpRuntime.Cache.Insert(CacheKey, objObject, null, expiresAt, Cache.NoSlidingExpiration);
            HttpRuntime.Cache.Insert(CacheKey + "_time", expiresAt, null, expiresAt, Cache.NoSlidingExpiration);//存储过期时间
            return true;
        }
        #endregion

        #region 插入缓存数据,指定缓存多少秒
        public bool Set<T>(string CacheKey, T objObject, int seconds)
        {
            DateTime expiresAt = DateTime.Now.AddSeconds(seconds);
            HttpRuntime.Cache.Insert(CacheKey, objObject, null, expiresAt, Cache.NoSlidingExpiration);
            HttpRuntime.Cache.Insert(CacheKey + "_time", expiresAt, null, expiresAt, Cache.NoSlidingExpiration);//存储过期时间
            return true;
        }
        #endregion

        #region 依赖文件的缓存,文件没改不会过期
        /// <summary>
        /// 依赖文件的缓存,文件没改不会过期
        /// </summary>
        /// <param name="CacheKey">键</param>
        /// <param name="objObject">数据</param>
        /// <param name="depfilename">依赖文件,可调用 DataCache 里的变量</param>
        public bool Set<T>(string CacheKey, T objObject, string depfilename)
        {
            //缓存依赖对象
            System.Web.Caching.CacheDependency dep = new System.Web.Caching.CacheDependency(depfilename);
            DateTime absoluteExpiration = System.Web.Caching.Cache.NoAbsoluteExpiration;
            TimeSpan slidingExpiration = System.Web.Caching.Cache.NoSlidingExpiration;
            System.Web.Caching.Cache objCache = HttpRuntime.Cache;
            objCache.Insert(
                CacheKey,
                objObject,
                dep,
                absoluteExpiration, //从不过期
                slidingExpiration, //禁用可调过期
                System.Web.Caching.CacheItemPriority.Default,
                null);
            if (File.Exists(depfilename))
            {
                FileInfo fi = new FileInfo(depfilename);
                DateTime lastWriteTime = fi.LastWriteTime;
                HttpRuntime.Cache.Insert(CacheKey + "_time", lastWriteTime, null, absoluteExpiration, slidingExpiration);//存储文件最后修改时间
            }
            return true;
        }
        #endregion
    }
}

//缓存统一入口

    public partial class DataCache
    {
        private static IDataCache _instance = null;
        /// <summary>
        /// 静态实例,外部可直接调用
        /// </summary>
        public static IDataCache Instance
        {
            get
            {
                if (_instance == null) _instance = new RuntimeCache();//这里可以改变缓存类型
                return _instance;
            }
        }
    }








相关实践学习
基于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
相关文章
|
1月前
|
消息中间件 缓存 NoSQL
Redis 是一个高性能的键值对存储系统,常用于缓存、消息队列和会话管理等场景。
【10月更文挑战第4天】Redis 是一个高性能的键值对存储系统,常用于缓存、消息队列和会话管理等场景。随着数据增长,有时需要将 Redis 数据导出以进行分析、备份或迁移。本文详细介绍几种导出方法:1)使用 Redis 命令与重定向;2)利用 Redis 的 RDB 和 AOF 持久化功能;3)借助第三方工具如 `redis-dump`。每种方法均附有示例代码,帮助你轻松完成数据导出任务。无论数据量大小,总有一款适合你。
77 6
|
12天前
|
缓存 NoSQL 关系型数据库
大厂面试高频:如何解决Redis缓存雪崩、缓存穿透、缓存并发等5大难题
本文详解缓存雪崩、缓存穿透、缓存并发及缓存预热等问题,提供高可用解决方案,帮助你在大厂面试和实际工作中应对这些常见并发场景。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
大厂面试高频:如何解决Redis缓存雪崩、缓存穿透、缓存并发等5大难题
|
14天前
|
存储 缓存 NoSQL
【赵渝强老师】基于Redis的旁路缓存架构
本文介绍了引入缓存后的系统架构,通过缓存可以提升访问性能、降低网络拥堵、减轻服务负载和增强可扩展性。文中提供了相关图片和视频讲解,并讨论了数据库读写分离、分库分表等方法来减轻数据库压力。同时,文章也指出了缓存可能带来的复杂度增加、成本提高和数据一致性问题。
【赵渝强老师】基于Redis的旁路缓存架构
|
7天前
|
缓存 NoSQL PHP
Redis作为PHP缓存解决方案的优势、实现方式及注意事项。Redis凭借其高性能、丰富的数据结构、数据持久化和分布式支持等特点,在提升应用响应速度和处理能力方面表现突出
本文深入探讨了Redis作为PHP缓存解决方案的优势、实现方式及注意事项。Redis凭借其高性能、丰富的数据结构、数据持久化和分布式支持等特点,在提升应用响应速度和处理能力方面表现突出。文章还介绍了Redis在页面缓存、数据缓存和会话缓存等应用场景中的使用,并强调了缓存数据一致性、过期时间设置、容量控制和安全问题的重要性。
23 5
|
22天前
|
缓存 NoSQL Redis
Redis 缓存使用的实践
《Redis缓存最佳实践指南》涵盖缓存更新策略、缓存击穿防护、大key处理和性能优化。包括Cache Aside Pattern、Write Through、分布式锁、大key拆分和批量操作等技术,帮助你在项目中高效使用Redis缓存。
120 22
|
21天前
|
缓存 NoSQL 中间件
redis高并发缓存中间件总结!
本文档详细介绍了高并发缓存中间件Redis的原理、高级操作及其在电商架构中的应用。通过阿里云的角度,分析了Redis与架构的关系,并展示了无Redis和使用Redis缓存的架构图。文档还涵盖了Redis的基本特性、应用场景、安装部署步骤、配置文件详解、启动和关闭方法、systemctl管理脚本的生成以及日志警告处理等内容。适合初学者和有一定经验的技术人员参考学习。
119 7
|
25天前
|
存储 缓存 监控
利用 Redis 缓存特性避免缓存穿透的策略与方法
【10月更文挑战第23天】通过以上对利用 Redis 缓存特性避免缓存穿透的详细阐述,我们对这一策略有了更深入的理解。在实际应用中,我们需要根据具体情况灵活运用这些方法,并结合其他技术手段,共同保障系统的稳定和高效运行。同时,要不断关注 Redis 缓存特性的发展和变化,及时调整策略,以应对不断出现的新挑战。
60 10
|
25天前
|
缓存 监控 NoSQL
Redis 缓存穿透的检测方法与分析
【10月更文挑战第23天】通过以上对 Redis 缓存穿透检测方法的深入探讨,我们对如何及时发现和处理这一问题有了更全面的认识。在实际应用中,我们需要综合运用多种检测手段,并结合业务场景和实际情况进行分析,以确保能够准确、及时地检测到缓存穿透现象,并采取有效的措施加以解决。同时,要不断优化和改进检测方法,提高检测的准确性和效率,为系统的稳定运行提供有力保障。
48 5
|
25天前
|
缓存 监控 NoSQL
Redis 缓存穿透及其应对策略
【10月更文挑战第23天】通过以上对 Redis 缓存穿透的详细阐述,我们对这一问题有了更深入的理解。在实际应用中,我们需要根据具体情况综合运用多种方法来解决缓存穿透问题,以保障系统的稳定运行和高效性能。同时,要不断关注技术的发展和变化,及时调整策略,以应对不断出现的新挑战。
42 4
|
26天前
|
缓存 NoSQL Java
有Redis为什么还要本地缓存?谈谈你对本地缓存的理解?
有Redis为什么还要本地缓存?谈谈你对本地缓存的理解?
51 0
有Redis为什么还要本地缓存?谈谈你对本地缓存的理解?
下一篇
无影云桌面