缓存篇~第七回 Redis实现基于方法签名的数据集缓存(可控更新,分布式数据缓存)

简介:

本篇文章可以说是第六回 Microsoft.Practices.EnterpriseLibrary.Caching实现基于方法签名的数据集缓存(可控更新,WEB端数据缓存)的续篇,事实上,有EnterpriseLibrary.Caching也只是实现缓存持久化的一种方式,而Redis做为成熟的分布式存储中间件来说,实现这个数据集缓存功能显得更加得心应手,也更加满足大型网站的设计规则。(在多web服务器时(web端实现负载均衡,反向代理),EnterpriseLibrary.Caching显得没什么作为,而这时,分布式缓存就可以一显身手了,它可以很轻松的将缓存服务器部署到第三方服务器上,解决了上面的问题)

一个标准,多种实现,面向对象的真谛:多态性,如果你问我接口有什么用,那么本篇文章可以告诉你答案:根据不同的场合,使用不同的持久化方式去存储数据。

下面是缓存标准接口ICacheProvider

 /// <summary>
    /// 表示实现该接口的类型是能够为应用程序提供缓存机制的类型。
    /// 这可以有多种实现机制
    /// </summary>
    public interface ICacheProvider
    {
        #region Methods
        /// <summary>
        /// 向缓存中添加一个对象。
        /// </summary>
        /// <param name="key">缓存的键值,该值通常是使用缓存机制的方法的名称。</param>
        /// <param name="valKey">缓存值的键值,该值通常是由使用缓存机制的方法的参数值所产生。</param>
        /// <param name="value">需要缓存的对象。</param>
        void Add(string key, string valKey, object value);
        /// <summary>
        /// 向缓存中更新一个对象。
        /// </summary>
        /// <param name="key">缓存的键值,该值通常是使用缓存机制的方法的名称。</param>
        /// <param name="valKey">缓存值的键值,该值通常是由使用缓存机制的方法的参数值所产生。</param>
        /// <param name="value">需要缓存的对象。</param>
        void Put(string key, string valKey, object value);
        /// <summary>
        /// 从缓存中读取对象。
        /// </summary>
        /// <param name="key">缓存的键值,该值通常是使用缓存机制的方法的名称。</param>
        /// <param name="valKey">缓存值的键值,该值通常是由使用缓存机制的方法的参数值所产生。</param>
        /// <returns>被缓存的对象。</returns>
        object Get(string key, string valKey);
        /// <summary>
        /// 从缓存中移除对象。
        /// </summary>
        /// <param name="key">缓存的键值,该值通常是使用缓存机制的方法的名称。</param>
        void Remove(string key);
        /// <summary>
        /// 获取一个<see cref="Boolean"/>值,该值表示拥有指定键值的缓存是否存在。
        /// </summary>
        /// <param name="key">指定的键值。</param>
        /// <returns>如果缓存存在,则返回true,否则返回false。</returns>
        bool Exists(string key);
        /// <summary>
        /// 获取一个<see cref="Boolean"/>值,该值表示拥有指定键值和缓存值键的缓存是否存在。
        /// </summary>
        /// <param name="key">指定的键值。</param>
        /// <param name="valKey">缓存值键。</param>
        /// <returns>如果缓存存在,则返回true,否则返回false。</returns>
        bool Exists(string key, string valKey);
        #endregion
    }

而这次我们使用Redis来作为实现持久化的方式,看一个RedisCacheProvider代码,它为了兼容性,将Dictionary<string, object>类型改为了Dictionary<string, byte[]>类型,这种设计避免了很多错误,因为我们知道,数据在发送时,它会被序列化,而兼容性,

安全性,性能等最佳的方式就是二进制的方式,所以,我们使用它来对数据进行存储。

    /// <summary>
    ///使用redis方式进行缓存持久化
    /// </summary>
    internal class RedisCacheProvider : ICacheProvider, IDisposable
    {
        private readonly IRedisClient _cacheManager = Redis.Client.RedisManager.GetClient();
        static byte[] Serialize(object data)
        {
            BinaryFormatter formatter = new BinaryFormatter();
            MemoryStream rems = new MemoryStream();
            formatter.Serialize(rems, data);
            return rems.GetBuffer();
        }
        static object Deserialize(byte[] data)
        {
            BinaryFormatter formatter = new BinaryFormatter();
            MemoryStream rems = new MemoryStream(data);
            data = null;
            return formatter.Deserialize(rems);
        }
        public void Add(string key, string valKey, object value)
        {
            byte[] byteValue = Serialize(value);
            using (var tbl = _cacheManager.GetTypedClient<Dictionary<string, byte[]>>())
            {
                Dictionary<string, byte[]> dict = null;
                if (tbl.ContainsKey(key))
                {
                    dict = (Dictionary<string, byte[]>)tbl.Lists[key][0];
                    dict[valKey] = byteValue;

                }
                else
                {
                    dict = new Dictionary<string, byte[]>();
                    dict.Add(valKey, byteValue);
                }
                Remove(key);
                tbl.Lists[key].Add(dict);
            }

        }

        public void Put(string key, string valKey, object value)
        {
            Add(key, valKey, value);
        }

        public object Get(string key, string valKey)
        {
            using (var tbl = _cacheManager.GetTypedClient<Dictionary<string, byte[]>>())
            {
                if (tbl.ContainsKey(key))
                {
                    Dictionary<string, byte[]> dict = (Dictionary<string, byte[]>)tbl.Lists[key][0];
                    if (dict != null && dict.ContainsKey(valKey))
                        return Deserialize(dict[valKey]);
                    else
                        return null;
                }
            }
            return null;

        }

        public void Remove(string key)
        {
            using (var tbl = _cacheManager.GetTypedClient<Dictionary<string, byte[]>>())
            {
                tbl.Lists[key].RemoveAll();
            }
        }

        public bool Exists(string key)
        {
            using (var tbl = _cacheManager.GetTypedClient<Dictionary<string, byte[]>>())
            {
                return tbl.ContainsKey(key);
            }
        }

        public bool Exists(string key, string valKey)
        {
            using (var tbl = _cacheManager.GetTypedClient<Dictionary<string, byte[]>>())
            {
                return tbl.ContainsKey(key) &&
                 ((System.Collections.Generic.Dictionary<string, byte[]>)tbl.Lists[key][0]).ContainsKey(valKey);
            }
        }

        public void Dispose()
        {
            _cacheManager.Dispose();
        }
    }

事实上,写到这里,我们的redis方法签名存储就完成了,配合上一篇文章,你可以设计出自己的缓存系统了,在这里再多说一句,本缓存系统用到的设计模式类似于策略模式,它对于一个完善功能,可以多种实现的策略,而对外只公开一个标准的对象,其它具体

的,完整功能的实现都使用了internal作为修饰符,来对外界隐藏。

本文转自博客园张占岭(仓储大叔)的博客,原文链接:缓存篇~第七回 Redis实现基于方法签名的数据集缓存(可控更新,分布式数据缓存),如需转载请自行联系原博主。

目录
相关文章
|
4月前
|
缓存 负载均衡 监控
135_负载均衡:Redis缓存 - 提高缓存命中率的配置与最佳实践
在现代大型语言模型(LLM)部署架构中,缓存系统扮演着至关重要的角色。随着LLM应用规模的不断扩大和用户需求的持续增长,如何构建高效、可靠的缓存架构成为系统性能优化的核心挑战。Redis作为业界领先的内存数据库,因其高性能、丰富的数据结构和灵活的配置选项,已成为LLM部署中首选的缓存解决方案。
|
4月前
|
缓存 运维 监控
Redis 7.0 高性能缓存架构设计与优化
🌟蒋星熠Jaxonic,技术宇宙中的星际旅人。深耕Redis 7.0高性能缓存架构,探索函数化编程、多层缓存、集群优化与分片消息系统,用代码在二进制星河中谱写极客诗篇。
|
5月前
|
NoSQL 数据可视化 Redis
redis上db复制的方法
首先排除使用命令行实现,因为没有现成的命令可以完成db复制,跨redis实例的复制迁移就更加没有这种命令了。假如非要使用命令来实现,要写大量的脚本,但是这样可靠性和速度无法保证,因为你无法保证你写的程序是否会有bug。db的复制,可以使用yunedit-redis来实现,yunedit-redis有可视化界面,复制起来非常简单。
|
5月前
|
存储 缓存 NoSQL
Redis专题-实战篇二-商户查询缓存
本文介绍了缓存的基本概念、应用场景及实现方式,涵盖Redis缓存设计、缓存更新策略、缓存穿透问题及其解决方案。重点讲解了缓存空对象与布隆过滤器的使用,并通过代码示例演示了商铺查询的缓存优化实践。
282 1
Redis专题-实战篇二-商户查询缓存
|
5月前
|
缓存 NoSQL 关系型数据库
Redis缓存和分布式锁
Redis 是一种高性能的键值存储系统,广泛用于缓存、消息队列和内存数据库。其典型应用包括缓解关系型数据库压力,通过缓存热点数据提高查询效率,支持高并发访问。此外,Redis 还可用于实现分布式锁,解决分布式系统中的资源竞争问题。文章还探讨了缓存的更新策略、缓存穿透与雪崩的解决方案,以及 Redlock 算法等关键技术。
NoSQL 数据可视化 关系型数据库
144 0
|
5月前
|
NoSQL Java 调度
分布式锁与分布式锁使用 Redis 和 Spring Boot 进行调度锁(不带 ShedLock)
分布式锁是分布式系统中用于同步多节点访问共享资源的机制,防止并发操作带来的冲突。本文介绍了基于Spring Boot和Redis实现分布式锁的技术方案,涵盖锁的获取与释放、Redis配置、服务调度及多实例运行等内容,通过Docker Compose搭建环境,验证了锁的有效性与互斥特性。
495 0
分布式锁与分布式锁使用 Redis 和 Spring Boot 进行调度锁(不带 ShedLock)
|
6月前
|
存储 负载均衡 NoSQL
【赵渝强老师】Redis Cluster分布式集群
Redis Cluster是Redis的分布式存储解决方案,通过哈希槽(slot)实现数据分片,支持水平扩展,具备高可用性和负载均衡能力,适用于大规模数据场景。
475 2
|
6月前
|
NoSQL 数据可视化 网络安全
redis客户端备份/迁移数据的方法
第二种是客户端备份,客户端连接redis数据源,使用redis的标准协议进行导出和导入。优点是只需要知道redis的用户名和密码,而不需要知道redis的宿主机的ssh密码即可操作。而且备份和恢复数据,不会影响新数据,比如备份到恢复这段时间产生了其他的主键的数据,恢复是不会清掉这部分主键的。 目前支持redis备份/数据迁移的可视化客户端软件,主要是yunedit-redis
|
6月前
|
存储 缓存 NoSQL
【📕分布式锁通关指南 12】源码剖析redisson如何利用Redis数据结构实现Semaphore和CountDownLatch
本文解析 Redisson 如何通过 Redis 实现分布式信号量(RSemaphore)与倒数闩(RCountDownLatch),利用 Lua 脚本与原子操作保障分布式环境下的同步控制,帮助开发者更好地理解其原理与应用。
427 6