你的位置:首页 > ASP.net教程

[ASP.net教程]理解 Memcached


一、Memcached是什么?

Memcached是一个高性能的分布式内存对象缓存系统,可以在内存中缓存数据和对象来减少读取数据库的次数,从而提醒性能。Memcached基于一个K/V对的hashmap。

二、Memcached的特征

1. 协议简单:基于文本协议和二进制协议进行通信

2. 基于libevent的事件处理

3. 内置内存存储方式

数据存储在内存中,重启服务或系统后数据会全部消失

当内存容量达到指定值后,基于LRU(Least Recently Used)算法自动删除不适用的缓存。

4. memcached不互相通信的分布式

服务端没有分布式供能,取决于客户端的实现。

三、Memcached安装

安装命令:

sc create "Memcached Server1" start= auto binPath= "‪D:\Tools\memcached\memcached.exe -d runservice -m 32 -p 11220 -l 127.0.0.1" DisplayName= "Memcached Server1"

PS:修改下服务名字及端口号,就可以在一台电脑上配置多个服务了。

启动命令:

sc start "Memcached Server1"

卸载命令:

sc delete "Memcached Server1"

参数详解:

-d选项是启动一个守护进程,
-m是分配给Memcache使用的内存数量,单位是MB,我这里是10MB,
-u是运行Memcache的用户,我这里是root,
-l是监听的服务器IP地址,如果有多个地址的话,我这里指定了服务器的IP地址192.168.0.200,
-p是设置Memcache监听的端口,我这里设置了12000,最好是1024以上的端口,
-c选项是最大运行的并发连接数,默认是1024,我这里设置了256,按照你服务器的负载量来设定,
-P是设置保存Memcache的pid文件,我这里是保存在 /tmp/memcached.pid,

四、Memcached内存存储机制:Slab Allocation

Slab Allocator的基本原理是按照预先规定的大小,将分配的内存分割成特定长度的块, 以完全解决内存碎片问题。

image

Slab术语:

Page: 分配给Slab的内存空间,默认是1MB。分配给Slab之后根据slab的大小切分成chunk。

Chunk: 用于缓存记录的内存空间

Slab Class: 特定大小的chunk的组。

memcached根据收到的数据的大小,选择最适合数据大小的slab(图2)。 memcached中保存着slab内空闲chunk的列表,根据该列表选择chunk, 然后将数据缓存于其中

image

接下来,我们看一下具体的例子应用,看看chunk是怎么分配的?

var str = "我是中国人";for (var i = 0; i < 100; i++) {    var temp = str;    for (int j = 0; j < i; j++)    {      temp += str;     }     client.Store(StoreMode.Set, "k" + i, temp); } Console.WriteLine("chunk_size\tchunks_per_page\tchunk_key_num"); foreach (var item in GetSlabsItemList()){     Console.WriteLine("{0}\t\t{1}\t\t{2}",item.chunk_size, item.chunks_per_page, item.items_number); } Console.ReadKey();

生成了100个K/V对,每一对数据量都会递增,我们看看结果怎么样,如图:

image

chunk_size表示chunk块的大小,也可以看出目前所有的chunk块的总数。

chunk_key_num表示当前chunk包含了多少个key。

结合上图应该更好理解了。

五、实战Memcached

本次实战使用Enyim作为客户端,具体配置如下。

app.config:<?"1.0" encoding="utf-8" ?><configuration> <configSections>  <sectionGroup name="enyim.com">         <section name="memcached" type="Enyim.Caching.Configuration.MemcachedClientSection, Enyim.Caching" />     </sectionGroup>  </configSections> <enyim.com>  <memcached protocol="Binary">   <servers>    <add address="127.0.0.1" port="11220" />    <add address="127.0.0.1" port="11221" />    <add address="127.0.0.1" port="11222" />   </servers>  </memcached> </enyim.com> <startup>     <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />  </startup></configuration>实现代码:class Program  {    private static MemcachedClient client = new MemcachedClient("enyim.com/memcached");    static void Main(string[] args)    {      var max = 10000;      for (var i = 0; i < max; i++)      {        client.Store(StoreMode.Set, "k" + i, "v" + i);      }      for (var i = 0; i < max; i++)      {        Console.WriteLine(client.Get("k" + i));      }      ServerStats ss = client.Stats();      foreach (var endpoint in ss.GetRaw("All"))      {        Console.WriteLine("endpoint: {0}", endpoint.Key);        IPEndPoint ipendpoint = new IPEndPoint(endpoint.Key.Address, endpoint.Key.Port);        Console.WriteLine("\t\tStatItem.ItemCount:{0}", ss.GetRaw(ipendpoint, StatItem.ItemCount));        Console.WriteLine("\t\tStatItem.UsedBytes:{0}", ss.GetRaw(ipendpoint, StatItem.UsedBytes));        Console.WriteLine("\t\tStatItem.MaxBytes:{0}", ss.GetRaw(ipendpoint, StatItem.MaxBytes));      }      Console.ReadKey();    }  }

从代码中,可以看出,我采用了多个服务的方式,然后我插入了10000个K/V对,Enyim客户端会根据算法将数据划分到不同的memcached服务中,结果如下。

image

分布式算法参考:http://xiexiejiao.cn/java/memcached-consistent-hashing.html

参考资料:

http://kb.cnblogs.com/page/42731/

http://kb.cnblogs.com/page/42732/

http://kb.cnblogs.com/page/42733/

http://kb.cnblogs.com/page/42734/

http://xiexiejiao.cn/java/memcached-consistent-hashing.html