zl程序教程

您现在的位置是:首页 >  工具

当前栏目

CYQ.Data V5 分布式缓存MemCached应用开发介绍

应用缓存分布式分布式开发 介绍 Data memcached
2023-09-11 14:20:55 时间

今天大伙还在热议关于.NET Core的东西,我只想说一句:在.NET 跨平台叫了这么多年间,其实人们期待的是一个知名的跨平台案例,而不是一堆能跨平台的消息。

好,回头说说框架: 

在框架完成数据库读写分离的功能后,开始回想起2年前所构思的:关于框架集成分布式缓存MemCached的实现。

之前一直没动手,是因为思路比较飘,秉承着框架应该简单干净轻量引用无依赖和使用不复杂的思维:

看着MemCached的服务端协议,整天思考着自己用Socket写一个客户端。

后来可能是没激情,迟迟没动手。

又在某个时刻,想过偷懒,想动态反射Memcached.ClientLibrary库,但一看到它竟然关联了四个dll,我那纯洁的心就有点抗拒它了。

所以日子就这样飘来复去,这个功能被想起又遗忘......

框架集成MemCache

这几天,翻看了往昔下载的的相关源码中,有个叫BeITMemcached,扫了一下源码,发现简单轻量没外部引用。

于是就开始改造,并测试了一下,没发现问题,于是开始思考集成的方式。

框架的缓存类本来很孤单,只有一个:CacheManage.cs

现在改造完,多了10个类,编绎后dll大小多了30K,说多了也是泪~:

框架的代码重构思维 最终定案的重构思维:

1:原有的CacheManage类变更为LocalCache。

2:CacheManage类变更为抽象类

3:新增MemCache,并和LocalCache一并实现CacheManage抽象类方法。

以上三步,就是核心的思维。

一开始的重构思维:

1:从原有的CacheManage里提取接口ICache

2:CacheManage改名WebCache并继承自ICache(由于提口提取自本类,所以代码不需要怎么调整)

3:新建MemCache继承并实现ICache接口。

4:新建CacheManage类,并从WebCache处把Instance实例属性移到此类中,并返回对应的ICache接口。

编绎后发现:

因为原来的代码有一小部分是这样写的:CacheManage cache=CacheManage.Instance;

因为返回的类型不一样,原有代码受到影响,必须改成:ICache cache=CacheManage.Instance。

为了避开影响不用改动代码,所以最终改用定案里抽象类和抽象方法实现。

下面贴一下抽象类CacheManage的方法:
        /// 返回唯一实例(根据是否配置AppConfig.Cache.MemCacheServers的服务器决定启用本地缓存或分布式缓存)
        public abstract void Add(string key, object value, string fileName, double cacheMinutes);
        public abstract void Add(string key, object value, string fileName, double cacheMinutes, CacheItemPriority level);

这里新增对外一个属性:LocalInstance,是因为一但配置了AppConfig.Cache.MemCacheServers后:

原有的本机缓存就自动切换到分布式缓存,为了使用本机缓存依旧可以使用,所以提供LocalInstance属性。

一开始是对外三个:Instance(自动切换型)、LocalInstance、MemInstance。

大伙可以思考一下,为什么MemInstance被去掉了?感觉有点说不清道不明的感觉。

 

由于LocalCache是变更名称自CacheManage,而CacheManage在以前文章贴过源码,所以不重复了。

现在贴一下MemCache的源码: 复制代码
 1 /// summary 

 2 /// 分布式缓存类

 3 /// /summary 

 4 internal class MemCache : CacheManage

 6 MemcachedClient client;

 7 internal MemCache()

 9 MemcachedClient.Setup("MyCache", AppConfig.Cache.MemCacheServers.Split(,));

 10 client = MemcachedClient.GetInstance("MyCache");

 12 }

 14 public override void Add(string key, object value, double cacheMinutes)

 15 {

 16 client.Add(key, value, DateTime.Now.AddMinutes(cacheMinutes));

 17 }

 18 public override void Add(string key, object value, string fileName, double cacheMinutes)

 19 {

 20 client.Add(key, value, DateTime.Now.AddMinutes(cacheMinutes));

 21 }

 23 public override void Add(string key, object value, string fileName)

 24 {

 25 client.Add(key, value);

 26 }

 28 public override void Add(string key, object value)

 29 {

 30 client.Add(key, value);

 31 }

 33 public override void Add(string key, object value, string fileName, double cacheMinutes, CacheItemPriority level)

 34 {

 35 client.Add(key, value, DateTime.Now.AddMinutes(cacheMinutes));

 36 }

 38 public override Dictionary string, CacheDependencyInfo CacheInfo

 39 {

 40 get { return null; }

 41 }

 42 DateTime allowCacheTableTime = DateTime.Now;

 43 private MDataTable cacheTable = null;

 44 public override MDataTable CacheTable

 45 {

 46 get

 47 {

 48 if (cacheTable == null || DateTime.Now allowCacheTableTime)

 49 {

 50 cacheTable = null;

 51 cacheTable = new MDataTable();

 52 Dictionary string, Dictionary string, string status = client.Stats();

 53 if (status != null)

 54 {

 56 foreach (KeyValuePair string, Dictionary string, string item in status)

 57 {

 58 if (item.Value.Count 0)

 59 {

 60 MDataTable dt = MDataTable.CreateFrom(item.Value);

 61 if (cacheTable.Columns.Count == 0)//第一次

 62 {

 63 cacheTable = dt;

 64 }

 65 else

 66 {

 67 cacheTable.JoinOnName = "Key";

 68 cacheTable = cacheTable.Join(dt, "Value");

 69 }

 70 cacheTable.Columns["Value"].ColumnName = item.Key;

 71 }

 72 }

 73 }

 74 cacheTable.TableName = "MemCache";

 75 allowCacheTableTime = DateTime.Now.AddMinutes(1);

 76 }

 77 return cacheTable;

 78 }

 79 }

 81 public override void Clear()

 82 {

 83 client.FlushAll();

 84 }

 86 public override bool Contains(string key)

 87 {

 88 return Get(key) != null;

 89 }

 91 //int count = -1;

 92 //DateTime allowGetCountTime = DateTime.Now;

 93 public override int Count

 94 {

 95 get

 96 {

 97 int count = 0;

 98 MDataRow row = CacheTable.FindRow("Key=curr_items");

 99 if (row != null)

100 {

101 for (int i = 1; i row.Columns.Count; i++)

102 {

103 count += int.Parse(row[i].strValue);

104 }

105 }

106 return count;

107 }

108 }

110 public override object Get(string key)

111 {

112 return client.Get(key);

113 }

116 public override bool GetFileDependencyHasChanged(string key)

117 {

118 return false;

119 }

121 public override bool GetHasChanged(string key)

122 {

123 return false;

124 }

126 public override long RemainMemoryBytes

127 {

128 get { return 0; }

129 }

131 public override long RemainMemoryPercentage

132 {

133 get { return 0; }

134 }

136 public override void Remove(string key)

137 {

138 client.Delete(key);

139 }

141 public override void Set(string key, object value)

142 {

143 client.Set(key, value);

144 }

146 public override void Set(string key, object value, double cacheMinutes)

147 {

148 client.Set(key, value, DateTime.Now.AddMinutes(cacheMinutes));

149 }

151 public override void SetChange(string key, bool isChange)

152 {

154 }

156 public override void Update(string key, object value)

157 {

158 client.Replace(key, value);

159 }

161 DateTime allowGetWorkInfoTime = DateTime.Now;

162 string workInfo = string.Empty;

163 public override string WorkInfo

164 {

165 get

166 {

167 if (workInfo == string.Empty || DateTime.Now allowGetWorkInfoTime)

168 {

169 workInfo = null;

170 Dictionary string, Dictionary string, string status = client.Status();

171 if (status != null)

172 {

173 JsonHelper js = new JsonHelper(false, false);

174 js.Add("OKServerCount", client.okServer.ToString());

175 js.Add("DeadServerCount", client.errorServer.ToString());

176 foreach (KeyValuePair string, Dictionary string, string item in status)

177 {

178 js.Add(item.Key, JsonHelper.ToJson(item.Value));

179 }

180 js.AddBr();

181 workInfo = js.ToString();

182 }

183 allowGetWorkInfoTime = DateTime.Now.AddMinutes(5);

184 }

185 return workInfo;

186 }

187 }

188 }
复制代码

讲完实现的过程和贴完源码,下面讲一下使用过程了:

框架里使用MemCache功能的演示 1:服务端先安装,并运行起来

服务端的文件是这样的:

运行后的服务是这样的,这里开了两个服务进程,分别对应:11211和11212端口:

2:代码使用是这样的

原有的使用方式不变,只是增加了一行配置,就自动切换到分布式了,是不是从单机过渡到分布式太简单了。

通常我们不在代码里配置,而是配置在:

运行的结果是这样的:

使用此框架,不管是进化到数据库读写分离,还是演进到分布式缓存,整个架构的升级过程,只需增加1行配置文件。

几年前就一直在构思,浮浮沉沉地随着框架的演进,如今顺水推舟地实现了,想想都觉得有点不可思议。

另外最后Top150大神群里,有人问我,最近写的文章有人打赏么?我只弱弱的回了一句:还没。


本文原创发表于博客园,作者为路过秋天,原文链接:http://www.cnblogs.com/cyq1162/p/5617761.html


实战干货 | 分布式多级缓存设计方案 分布式多级缓存设计方案,解决海量数据读取的性能问题,包含多级缓存的存储设计,流程设计;利用多数据副本保证数据的可用性,同时通过不同数据源特点提供更高性能、更多场景数据差异化的支持
同一服务器上有多个 WordPress 网站如何配置 Memcached 缓存? 如果在同一台服务器上,部署了多个 Wordpress 项目,如果在每台服务器上都启用 Memcached ,那么将会出现网站白屏、数据串站的问题,本文我们来介绍如何处理这种问题。
突破Java面试(19) - 分布式缓存的第一个问题 这个问题,互联网公司必问,要是一个人连缓存都不太清楚,那确实比较尴尬 只要问到缓存,上来第一个问题,肯定能是先问问你项目哪里用了缓存?为啥要用?不用行不行?如果用了以后可能会有什么不良的后果? 这就是看看你对你用缓存这个东西背后,有没有思考,如果你就是傻乎乎的瞎用,没法给面试官一个合理的解答。