Memcached,你懂的
一、Memcached简介
Memcached 是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载。它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提高动态、数据库驱动网站的速度。Memcached基于一个存储键/值对的hashmap。其守护进程(daemon )是用C写的,但是客户端可以用任何语言来编写,并通过memcached协议与守护进程通信。
目前有多种平台的Memcached版本,比如Linux、FreeBSD、Solaris 、Mac OS X及Windows平台。
可在官网下载到最新版本: http://memcached.org/ (LINUX) 。
这里,官网上好像没有找到Memcached for windows
我们安装Windows版本来演示。
32bit:下载 memcached-win32-1.4.4-14.zip
64bit:如果需要win64版,下载 memcached-win64-1.4.4-14.zip
二、安装和启动
首先,我解压文件路径
D:\Memcached\Memcached32
安装命令
以管理员身份运行 cmd.exe
进入到解压文件
D:\>cd Memcached\Memcached32
安装
D:\Memcached\Memcached32>memcached.exe -d install
启动
D:\Memcached\Memcached32>memcached.exe -d start
OK,命令咱们已经执行完了.怎么才知道Memcached服务已经安装成功并启动了呢?
cmd 命令 services.msc
有时候,为了方便起见,我们也不能每次安装,停止和启动服务的时候都打开cmd命令框吧
常见的办法是做成批处理命令,如下:
install.bat
memcached.exe -d install
start.bat
memcached.exe -d start
stop.bat
memcached.exe -d stop
unInstall.bat
memcached.exe -d uninstall
三、.net 项目中使用
笔者查阅了相关资料,发现有很多支持Memcached的客户端,这里由于笔者的个人喜好,
选择了EnyimMemcached.2.13
可以通过Nuget安装
PM> Install-Package EnyimMemcached
笔者特意做了一个Demo来体验一下,EnyimMemcached使用
首先,我们要连接到这个分布式数据库服务,类似以前的关系型数据库,这里也是需要配置连接的,配置如下
<?xml version="1.0" encoding="utf-8" ?> <configuration> <configSections> <sectionGroup name="enyim.com"> <section name="memcached" type="Enyim.Caching.Configuration.MemcachedClientSection,Enyim.Caching" /> </sectionGroup> <section name="memcached" type="Enyim.Caching.Configuration.MemcachedClientSection, Enyim.Caching"/> </configSections> <enyim.com> <memcached> <servers> <!-- put your own server(s) here--> <add address="127.0.0.1" port="11211" /> </servers> <socketPool minPoolSize="10" maxPoolSize="100" connectionTimeout="00:00:10" deadTimeout="00:02:00" /> </memcached> </enyim.com> <memcached keyTransformer="Enyim.Caching.TigerHashTransformer,Enyim.Caching"> <servers> <add address="127.0.0.1" port="11211" /> </servers> <socketPool minPoolSize="2" maxPoolSize="100" connectionTimeout="00:00:10" deadTimeout="00:02:00" /> </memcached> <startup> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" /> </startup> </configuration>
为了方便使用,可以再封装一下,便于调用,
using Enyim.Caching; using Enyim.Caching.Configuration; using Enyim.Caching.Memcached; using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading.Tasks; namespace MemcachdDemo.Helper { public sealed class MemCachedHelper { private static MemcachedClient MemClient; static readonly object padlock = new object(); //线程安全的单例模式 public static MemcachedClient getInstance() { if (MemClient == null) { lock (padlock) { if (MemClient == null) { MemClientInit(); } } } return MemClient; } static void MemClientInit() { try { MemClient = new MemcachedClient(); /*MemcachedClientConfiguration config = new MemcachedClientConfiguration(); config.Servers.Add(new System.Net.IPEndPoint(IPAddress.Parse("127.0.0.1"), 11211)); config.Protocol = MemcachedProtocol.Binary; //config.Authentication.Type = typeof(PlainTextAuthenticator); //config.Authentication.Parameters["userName"] = "memcache"; //config.Authentication.Parameters["password"] = "password"; MemClient = new MemcachedClient(config);*/ /*MemcachedClientConfiguration config = new MemcachedClientConfiguration(); //config.Servers.Add(new IPEndPoint("127.0.0.1", 11211)); config.Servers.Add(new System.Net.IPEndPoint(IPAddress.Parse("127.0.0.1"), 11211)); config.Protocol = MemcachedProtocol.Binary; config.Authentication.Type = typeof(PlainTextAuthenticator); config.Authentication.Parameters["userName"] = "username"; config.Authentication.Parameters["password"] = "password"; config.Authentication.Parameters["zone"] = ""; MemClient = new MemcachedClient(config);*/ } catch (Exception ex) { throw ex; } } #region getAllKeys public static List<string> GetAllKeys(string ipString, int port) { List<string> allKeys = new List<string>(); //var ipString = "127.0.0.1"; //var port = 11211; var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); socket.Connect(new IPEndPoint(IPAddress.Parse(ipString), port)); var slabIdIter = QuerySlabId(socket); var keyIter = QueryKeys(socket, slabIdIter); socket.Close(); foreach (String key in keyIter) { if (!allKeys.Contains(key)) allKeys.Add(key); } return allKeys; } /// <summary> /// 执行返回字符串标量 /// </summary> /// <param name="socket">套接字</param> /// <param name="command">命令</param> /// <returns>执行结果</returns> static String ExecuteScalarAsString(Socket socket, String command) { var sendNumOfBytes = socket.Send(Encoding.UTF8.GetBytes(command)); var bufferSize = 0x1000; var buffer = new Byte[bufferSize]; var readNumOfBytes = 0; var sb = new StringBuilder(); while (true) { readNumOfBytes = socket.Receive(buffer); sb.Append(Encoding.UTF8.GetString(buffer)); if (readNumOfBytes < bufferSize) break; } return sb.ToString(); } /// <summary> /// 查询slabId /// </summary> /// <param name="socket">套接字</param> /// <returns>slabId遍历器</returns> static IEnumerable<String> QuerySlabId(Socket socket) { var command = "stats items STAT items:0:number 0 \r\n"; var contentAsString = ExecuteScalarAsString(socket, command); return ParseStatsItems(contentAsString); } /// <summary> /// 解析STAT items返回slabId /// </summary> /// <param name="contentAsString">解析内容</param> /// <returns>slabId遍历器</returns> static IEnumerable<String> ParseStatsItems(String contentAsString) { var slabIds = new List<String>(); var separator = "\r\n"; var separator2 = ':'; var items = contentAsString.Split(separator, StringSplitOptions.RemoveEmptyEntries); for (Int32 i = 0; i < items.Length; i += 4) { var itemParts = items[i].Split(separator2, StringSplitOptions.RemoveEmptyEntries); if (itemParts.Length < 3) continue; slabIds.Add(itemParts[1]); } return slabIds; } /// <summary> /// 查询键 /// </summary> /// <param name="socket">套接字</param> /// <param name="slabIdIter">被查询slabId</param> /// <returns>键遍历器</returns> static IEnumerable<String> QueryKeys(Socket socket, IEnumerable<String> slabIdIter) { var keys = new List<String>(); var cmdFmt = "stats cachedump {0} 200000 ITEM views.decorators.cache.cache_header..cc7d9 [6 b; 1256056128 s] \r\n"; var contentAsString = String.Empty; foreach (String slabId in slabIdIter) { contentAsString = ExecuteScalarAsString(socket, String.Format(cmdFmt, slabId)); keys.AddRange(ParseKeys(contentAsString)); } return keys; } /// <summary> /// 解析stats cachedump返回键 /// </summary> /// <param name="contentAsString">解析内容</param> /// <returns>键遍历器</returns> static IEnumerable<String> ParseKeys(String contentAsString) { var keys = new List<String>(); var separator = "\r\n"; var separator2 = ' '; var prefix = "ITEM"; var items = contentAsString.Split(separator, StringSplitOptions.RemoveEmptyEntries); foreach (var item in items) { var itemParts = item.Split(separator2, StringSplitOptions.RemoveEmptyEntries); if ((itemParts.Length < 3) || !String.Equals(itemParts.FirstOrDefault(), prefix, StringComparison.OrdinalIgnoreCase)) continue; keys.Add(itemParts[1]); } return keys; } } /// <summary> /// String扩展函数 /// </summary> static class StringExtension { /// <summary> /// 切割 /// </summary> /// <param name="str">字符串</param> /// <param name="separator">分隔符</param> /// <param name="options">选项</param> /// <returns>切割结果</returns> public static String[] Split(this String str, Char separator, StringSplitOptions options) { return str.Split(new Char[] { separator }, options); } /// <summary> /// 切割 /// </summary> /// <param name="str">字符串</param> /// <param name="separator">分隔符</param> /// <param name="options">选项</param> /// <returns>切割结果</returns> public static String[] Split(this String str, String separator, StringSplitOptions options) { return str.Split(new String[] { separator }, options); } #endregion } }
因为EnyimMemcached帮我们封装的很好,剩下的就是调用了
private void button3_Click(object sender, EventArgs e) { try { if (String.IsNullOrEmpty(this.txtKey.Text)) { MessageBox.Show("key不能为空!"); return; } else { var key = this.txtKey.Text.Trim(); var value = this.txtValue.Text.Trim(); var bRet = client.Store(StoreMode.Set, key.Trim(), txtValue.Text.Trim()); } } catch (Exception ex) { throw ex; } }
截图如下
由于是key-value存储,查询方法:
var value = mc.Get("name");
对于Memcached的安装,启动和基本使用,有了简单的介绍,希望对你有用, 有用的话,请支持一下哈!