一、阿里云OCS简单介绍
阿里云OCS兼容Memcached,因为OCS就相当于Memcached的服务器端,我们代码只是当作客户端,链接上服务器端就行了。阿里云OCS介绍详情见 http://www.aliyun.com/product/ocs?spm=5176.2020520107.0.0.s2zgFk#Help 。
二、C#客户端链接OCS
1.阿里云文档上介绍的是用Enyim.Caching去链接OCS。那我们项目中就用nuget去下载Enyim.Caching包。nuget搜索Enyim,搜索到的结果如下图,第一个是nolog版本的,第二个是带log的,随便一个都可以。
nuget搜索结果如下:
2.安装成功以后,再链接OCS,写个初始化memcached的代码,代码如下。
1 using Enyim.Caching; 2 using Enyim.Caching.Configuration; 3 using Enyim.Caching.Memcached; 4 using System; 5 using System.Collections.Generic; 6 using System.Linq; 7 using System.Net; 8 using System.Text; 9 using System.Threading.Tasks; 10 11 namespace OCS 12 { 13 public class MemCached 14 { 15 private static MemcachedClient MemClient; 16 17 static readonly object padlock = new object(); 18 //线程安全的单例模式 19 public static MemcachedClient getInstance(string hostName,string userName,string password) 20 { 21 if (MemClient == null) 22 { 23 lock (padlock) 24 { 25 if (MemClient == null) 26 { 27 MemClientInit(hostName,userName,password); 28 } 29 } 30 } 31 return MemClient; 32 } 33 34 static void MemClientInit(string hostName,string userName,string password) 35 { 36 try 37 { 38 //初始化缓存 39 MemcachedClientConfiguration memConfig = new MemcachedClientConfiguration(); 40 IPAddress newaddress = IPAddress.Parse(Dns.GetHostEntry(hostName).AddressList[0].ToString()); 41 IPEndPoint ipEndPoint = new IPEndPoint(newaddress, 11211); 42 43 // 配置文件 - ip 44 memConfig.Servers.Add(ipEndPoint); 45 // 配置文件 - 协议 46 memConfig.Protocol = MemcachedProtocol.Binary; 47 // 配置文件-权限 48 memConfig.Authentication.Type = typeof(PlainTextAuthenticator); 49 memConfig.Authentication.Parameters["zone"] = ""; 50 memConfig.Authentication.Parameters["userName"] = userName; 51 memConfig.Authentication.Parameters["password"] = password; 52 //下面请根据实例的最大连接数进行设置 53 memConfig.SocketPool.MinPoolSize = 5; 54 memConfig.SocketPool.MaxPoolSize = 200; 55 MemClient = new MemcachedClient(memConfig); 56 } 57 catch (Exception) 58 { 59 MemClient = null; 60 } 61 } 62 } 63 }
3.再写个服务去调用上面的初始化代码,创建MemcachedClient的实例去调用客户端代码。下面代码中的构造函数中的_setting.HostAddress, _setting.AccessId, _setting.AccessKey分别对应的是,OCS的链接地址,链接密码和OCS的实例ID。
1 using Enyim.Caching; 2 using Enyim.Caching.Memcached; 3 using Enyim.Caching.Memcached.Results; 4 using System; 5 using System.Collections.Generic; 6 using System.Linq; 7 using System.Text; 8 using System.Text.RegularExpressions; 9 using System.Threading.Tasks; 10 using System.Web.Script.Serialization; 11 using Zupo.Core.Caching; 12 using ServiceStack.Text; 13 using Newtonsoft.Json; 14 15 namespace OCS 16 { 17 public class OCSService 18 { 19 IOCSSetting _setting; 20 21 private MemcachedClient client; 22 23 public OCSService(IOCSSetting setting) 24 { 25 this._setting = setting; 26 this.client = MemCached.getInstance(_setting.HostAddress, _setting.AccessId, _setting.AccessKey); 27 } 28 29 /// <summary> 30 /// 是否链接上服务器 31 /// </summary> 32 protected bool LinkServer 33 { 34 get 35 { 36 return client == null ? false : true; 37 } 38 } 39 40 protected IGetOperationResult ExecuteGet(string key) 41 { 42 return client.ExecuteGet(key); 43 } 44 45 /// <summary> 46 /// 根据key获得缓存 47 /// </summary> 48 /// <param name="key"></param> 49 /// <returns></returns> 50 protected object Get(string key) 51 { 52 return client.Get(key); 53 } 54 55 /// <summary> 56 /// 根据key获得缓存 泛型方法 57 /// </summary> 58 /// <typeparam name="T"></typeparam> 59 /// <param name="key"></param> 60 /// <returns></returns> 61 protected T Get<T>(string key) 62 { 63 try 64 { 65 //JavaScriptSerializer jsonSerializer = new JavaScriptSerializer(); 66 //string objectStr = client.Get(key).ToString(); 67 var obj = client.Get(key); 68 if (obj != null) 69 { 70 return JsonConvert.DeserializeObject<T>(obj.ToString()); 71 } 72 return default(T); 73 //return objectStr.FromJson<T>(); 74 } 75 catch (Exception) 76 { 77 this.Remove(key); 78 return default(T); 79 } 80 } 81 82 /// <summary> 83 /// 根据key获得缓存 泛型方法 84 /// </summary> 85 /// <typeparam name="T"></typeparam> 86 /// <param name="key"></param> 87 /// <returns></returns> 88 protected List<T> GetList<T>(string key) 89 { 90 var objectStr = client.Get(key).ToString(); 91 92 //return objectStr.FromJson<List<T>>(); 93 return JsonConvert.DeserializeObject<List<T>>(objectStr); 94 } 95 96 /// <summary> 97 /// 根据数组key获得数据 IDictionary 98 /// </summary> 99 /// <param name="keys"></param> 100 /// <returns></returns> 101 protected IDictionary<string, object> GetByKeys(string[] keys) 102 { 103 return client.Get(keys); 104 } 105 106 /// <summary> 107 /// 该key值缓存是否存在 108 /// </summary> 109 /// <param name="key"></param> 110 /// <returns></returns> 111 public bool Contains(string key) 112 { 113 object value; 114 115 return client.TryGet(key, out value); 116 } 117 118 /// <summary> 119 /// 存储,有的话直接覆盖 120 /// </summary> 121 /// <param name="key"></param> 122 /// <param name="value"></param> 123 /// <returns></returns> 124 protected bool Set(string key, object value) 125 { 126 return client.Store(StoreMode.Set, key, value); 127 } 128 129 /// <summary> 130 /// 存储,有的话直接覆盖 131 /// </summary> 132 /// <param name="key"></param> 133 /// <param name="value"></param> 134 /// <returns></returns> 135 protected bool Set<T>(string key, T value) 136 { 137 try 138 { 139 //执行序列化 140 //string objectStr = value.ToJson(); 141 string objectStr = JsonConvert.SerializeObject(value, Formatting.Indented, new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Ignore }); 142 return client.Store(StoreMode.Set, key, objectStr); 143 } 144 catch(Exception) 145 { 146 return false; 147 } 148 149 } 150 151 /// <summary> 152 /// 存储,有的话直接覆盖 153 /// </summary> 154 /// <param name="key"></param> 155 /// <param name="value"></param> 156 /// <returns></returns> 157 protected bool Set<T>(string key, List<T> value) 158 { 159 //执行序列化 160 //string objectStr = value.ToJson(); 161 string objectStr = JsonConvert.SerializeObject(value, Formatting.Indented, new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Ignore }); 162 return client.Store(StoreMode.Set, key, objectStr); 163 } 164 165 /// <summary> 166 /// 存储,有的话直接覆盖 167 /// </summary> 168 /// <param name="key"></param> 169 /// <param name="value"></param> 170 /// <param name="expire">失效时间:TimeSpan</param> 171 /// <returns></returns> 172 protected bool SetExpires(string key, object value, TimeSpan expire) 173 { 174 try 175 { 176 //string objectStr = value.ToJson(); 177 string objectStr = JsonConvert.SerializeObject(value, Formatting.Indented, new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Ignore }); 178 return client.Store(StoreMode.Set, key, objectStr, expire); 179 } 180 catch(Exception) 181 { 182 return false; 183 } 184 185 } 186 187 /// <summary> 188 /// 存储,有的话直接覆盖 189 /// </summary> 190 /// <param name="key"></param> 191 /// <param name="value"></param> 192 /// <param name="expire">失效时间:TimeSpan</param> 193 /// <returns></returns> 194 protected bool SetExpires<T>(string key, T value, TimeSpan expire) 195 { 196 //执行序列化 197 //string objectStr = value.ToJson(); 198 string objectStr = JsonConvert.SerializeObject(value, Formatting.Indented, new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Ignore }); 199 return client.Store(StoreMode.Set, key, objectStr, expire); 200 } 201 202 /// <summary> 203 /// 删除cached 204 /// </summary> 205 /// <param name="key"></param> 206 /// <returns></returns> 207 public void Remove(string key) 208 { 209 client.Remove(key); 210 } 211 212 /// <summary> 213 /// Removes items by pattern 214 /// 该方法未实现 215 /// </summary> 216 /// <param name="pattern">pattern</param> 217 public virtual void RemoveByPattern(string pattern) 218 { 219 var regex = new Regex(pattern, RegexOptions.Singleline | RegexOptions.Compiled | RegexOptions.IgnoreCase); 220 //var keysToRemove = new List<String>(); 221 222 //var allkeys = client. 223 //foreach (var key in allkeys) 224 // if (regex.IsMatch(key)) 225 // keysToRemove.Add(key); 226 227 //foreach (string key in keysToRemove) 228 //{ 229 // Remove(key); 230 //} 231 } 232 233 /// <summary> 234 /// 清空ocs缓存 235 /// </summary> 236 /// <returns></returns> 237 public void Clear() 238 { 239 client.FlushAll(); 240 } 241 } 242 }
三、使用注意点
因为OCS只支持key/value的格式进行存储,所以我项目中先运用了Newtonsoft.Json去先对对象序列化,再存入到OCS上,读取的时候再反序列化读取。代码如下:
1 /// <summary> 2 /// 存储,有的话直接覆盖 3 /// </summary> 4 /// <param name="key"></param> 5 /// <param name="value"></param> 6 /// <returns></returns> 7 protected bool Set<T>(string key, T value) 8 { 9 try 10 { 11 //执行序列化 12 string objectStr = JsonConvert.SerializeObject(value, Formatting.Indented, new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Ignore }); 13 return client.Store(StoreMode.Set, key, objectStr); 14 } 15 catch(Exception) 16 { 17 return false; 18 } 19 20 }
代码中设置了JsonSerializerSettings,因为项目用的是EF,一些对象里面的属性可能是另外一个对象还有是一些死循环的属性,所以数据量会比较大,直接执行序列化会内存溢出的,所以要在对象里面不需要序列化的属性上加上[JsonIgnore],忽略此属性或字段序列化。
那么反序列化获取数据代码如下:
1 /// <summary> 2 /// 根据key获得缓存 泛型方法 3 /// </summary> 4 /// <typeparam name="T"></typeparam> 5 /// <param name="key"></param> 6 /// <returns></returns> 7 protected T Get<T>(string key) 8 { 9 try 10 { 11 var obj = client.Get(key); 12 if (obj != null) 13 { 14 return JsonConvert.DeserializeObject<T>(obj.ToString()); 15 } 16 return default(T); 17 } 18 catch (Exception) 19 { 20 this.Remove(key); 21 return default(T); 22 } 23 }