Xmemcached开源组件

 

         在项目中使用memcached处理缓存问题,发现一个用法差不过的开源组件据说,性能比较好,就随便看看,学习学习。

 memcached之memcached介绍
---------
现在许多web应用都将数据保存到RDBMS中,应用服务器从中读取数据并在浏览器中显示。但随着数据量的增大、访问的集中,就会出现RDBMS的负担加重、数据响应恶化、网站显示延迟等重大影响。
这时就该memcached大显身手了。memcached是高性能的分布式内存缓存服务器。一般的使用目的是,通过缓存数据库查询结果,减少数据库访问次数,以提高动态web应用的速度、提高可扩展性。

memcached的特征
memcached作为高速运行的分布式缓存服务器,具有以下的特点:
1.协议简单
2.基于libevent的事件处理
3.内置内存存储方式
4.memcached不互相通信的分布式

协议简单
memcached的服务器客户端通信并不使用复杂的XML等格式,而使用简单的基于文本行的协议。因此,通过telnet也能在memcached上保存数据、取得数据。如例:

 

[plain]   view plain copy
  1. $ telnet localhost 11211  
  2. Trying 127.0.0.1...  
  3. Connected to localhost.localdomain(127.0.0.1).  
  4. Escape character is '^]'.  
  5. set foo 0 0 3  (保存命令)  
  6. bar         (数据)  
  7. STORED      (结果)  
  8. get foo     (取得命令)  
  9. VALUE foo 0 3 (数据)  
  10. bar         (数据)  


基于libevent的事件处理
libevent是个程序库,它将linux的epoll、BSD类操作系统的kqueue等事件处理功能封装成统一的接口。memcached使用这个libevent库,因此能在linux,BSD,Solaris等操作系统上发挥其高性能。

内置内存存储方式
为了提高性能,memcached中保存的数据都存储在memcached内置的内存存储空间中。由于数据仅存在于内存中,因此重启memcached、重启操作系统会导致全部数据消失。另外,内容容量达到指定值之后,就基于LRU算法(LRU是Least Recently Used最近最少使用算法)自动删除不使用的缓存。memcached本身是为缓存而设计的服务器,
因此并没有过多考虑数据的永久性问题。

memcached不互相通信的分布式
memcached尽管是"分布式"缓存服务器,但服务器端并没有分布式功能。各个memcached不会互相通信以共享信息。那么,怎样进行分布式呢?这完全取决于客户端的实现。

memcached之memcached安装
---------

memcached支持许多平台,如:Linux,FreeBSD,Solaris(memcached1.2.5以上版本),Mac OS X,另外也能安装在windows上。

这里使用Fedora Core 8进行说明。

运行memcached需要前面介绍的libevent库。Fedora 8中有现成的rpm包,通过yum命令安装即可。

 

[plain]   view plain copy
  1. $ sudo yum install libevent libevent-devel  

memcached的源代码可以从memcached网站上下载。Fedora 8虽然也包含了memcached的rpm,但版本比较老。因为源代码安装并不困难,这里就不使用rpm了。
下载memcached: http://www.danga.com/memcached
memcached安装与一般应用程序相同,configure,make,make install就行了。

 

[plain]   view plain copy
  1. $ wget http://www.danga.com/memcached/dist/memcached-1.2.5.tar.gz  
  2. $ tar zxf memcached-1.2.5.tar.gz  
  3. $ ./configure  
  4. $ make  
  5. $ sudo make install  

默认情况下,memcached安装到/usr/local/bin下。

memcached的启动
从终端输入以下命令,启动memcached。

 

[plain]   view plain copy
  1. $ /usr/local/bin/memcached -p 11211 -m 64m -vv  

这样就在前台启动了memcached,监听TCP端口11211最大内存使用量为64M。作为daemon后台启动时,只需:

 

[plain]   view plain copy
  1. $ /usr/local/bin/memcached -p 11211 -m 64m -d  

这里使用的memcached启动选项的内容如下:

 

 

选项
说明
-p
使用的TCP端口。默认为11211
-m
最大内存大小。默认为64m
-vv
用very vrebose模式启动,调试信息和错误输出到控制台
-d
作为daemon在后台启动
   

上面四个是常用的启动选项,还有很多。通过:

 

[plain]   view plain copy
  1. $ /usr/local/bin/memcached -h  

命令可以显示。许多选项可以改变memcached的各种行为,推荐读一读。

memcached之理解memcached的内存存储 
---------
下面介绍memcached的内部构造的实现方式,以及内存的管理方式,以及memcached的内部构造导致的弱点也将加以说明。

Slab Allocation机制:整理内存以便重复使用
最近的memcached默认情况下采用了名为Slab Allocator的机制分配、管理内存。在该机制出现以前,内存的分配是通过对所有记录简单地进行malloc和free来进行的。但是,这种方式会导致内存碎片,加重操作系统内存管理器的负担,最坏的情况下,会导致操作系统比memcached进程本身还慢。Slab Allocator就是为解决该问题而诞生的。
Slab Allocator的基本原理是按照预先规定的大小,将分配的内存分割成特定长度的块,以完全解决内存碎片的问题。Slab Allocation的原理相当简单。将分配的内存分割成各种尺寸的块(chunk),并把尺寸相同的块分成组(chunk的集合).而且,slab allocator还有重复使用已分配的内存的目的。也就是说,分配到的内存不会释放,而是重复利用
Slab Allocation的主要术语:
Page: 分配给Slab的内存空间,默认是1MB。分配给Slab之后根据slab的大小切分成chunk。
Chunk: 用于缓存记录的内存空间。
Slab Class: 特定大小的chunk的组。

在Slab中缓存记录的原理
下面说明memcached如何针对客户端发送的数据选择slab并缓存到chunk中。
memcached根据收到的数据的大小,选择最适合数据大小的slab。memcached中保存着slab内空闲chunk的列表,根据该列表选择chunk,然后将数据缓存于其中。

Slab Allocator的缺点
Slab Allocator解决了当初的内存碎片问题,但新的机制也给memcached带来了新的问题。这个问题就是,由于分配的是特定长度的内存,因此无法有效利用分配的内存。例如,将100字节的数据缓存到128字节的chunk中,剩余的28字节就浪费了。
对于该问题目前还没有完美的解决方案,但在文档中记载了比较有效的解决方案。就是说,如果预先知道客户端发送的数据的公用大小,或者仅缓存大小相同的数据的情况下,只要使用适合数据大小的组的列表,就可以减少浪费。但是很遗憾,现在还不能进行任何调优,只能期待以后的版本了。但是,我们可以调节slab class的大小的差别。

使用Growth Factor进行调优
memcached在启动时指定Growth Factor因子(通过-f选项),就可以在某种程序上控制slab之间的差异。默认值为1.25。但是,在该选项出现之前,这个因子曾经固定2,称为"powers of 2"策略。

让我们用以前的设置,以verbose模式启动memcached试试看:

 

[plain]   view plain copy
  1. $ memcached -f 2 -vv  

下面是启动后的verbose输出:

 

[plain]   view plain copy
  1. slab class  1: chunk size   128 perslab 8192  
  2. slab class  2: chunk size   256 perslab 4096  
  3. slab class  3: chunk size   512 perslab 2048  
  4. slab class  4: chunk size   1024 perslab 1024  
  5. ...  

可见,从128字节的组开始,组的大小依次增大为原来的2倍。这样设置的问题是,slab之间的差别比较大,有些情况下就相当浪费内存。因此,为尽量减少内存浪费,两年前追加了growth factor这个选项。
来看看现在的默认设置(f=1.25)时的输出:

[plain]   view plain copy
  1. slab class  1:  chunk size      88 perslab  11915  
  2. slab class  2:  chunk size      112 perslab 9362  
  3. slab class  3:  chunk size      144 perslab 7281  
  4. slab class  4:  chunk size      184 perslab 5698  
  5. ...  

可见,组间差距比因子为2时小得多,更适合缓存几百字节的记录。
将memcached引入产品,或是直接使用默认值进行部署时,最好是重新计算一下数据的预期平均长度,调整growth factor,以获得最愉当的设置。内存是珍贵的资源,浪费就太可惜了。

查看memcached的内部状态
memcached有一个名为stats的命令,使用它可以获得各种各样的信息。执行命令的方法很多,用telnet最为简单:
$ telnet    主机名    端口号

连接到memcached之后,输入stats再按回车,即可获得包括资源利用率在内的各种信息。此外,输入"stats slabs"或"stats items"还可以获得关于缓存记录的信息。结束程序请输入quit

 

[plain]   view plain copy
  1. $ telnet localhost 11211  
  2. Trying ::1...  
  3. Connected to localhost.  
  4. Escape character is '^]'.  
  5. stats  
  6. STAT pid 481  
  7. STAT uptime 16574  
  8. STAT time 1213687612  
  9. STAT version 1.2.5  
  10. STAT pointer_size 32  
  11. STAT rusage_user 0.102297  
  12. STAT rusage_system 0.214317  
  13. STAT curr_items 0  
  14. STAT bytes 0  
  15. STAT curr_connections 6  
  16. STAT total_connections 8  
  17. STAT connection_structures 7  
  18. STAT cmd_get 0  
  19. STAT cmd_set 0  
  20. STAT get_hits 0  
  21. STAT get_messes 0  
  22. STAT evictions 0  
  23. STAT bytes_read 20  
  24. STAT bytes_written 465  
  25. STAT limit_maxbytes 67108864  
  26. STAT threads 4  
  27. END  
  28. quit  

 

查看slabs的使用状况
$ memcached-tool    主机名:端口    选项
查看slabs使用状况时无需指定选项,因此用下面的命令即可:
$ memcached-tool    主机名:端口
获得的信息如下:

[plain]   view plain copy
  1. #   Item_Size   Max_age     IMB_pages   Count       Full?  
  2. 1   104B        1394292 s   1215        12249628    yes  
  3. ....  

各列的含义为:

 

含义
#
slab class编号
Item_Size
Chunk大小
Max_age
LRU内最旧的记录的生存时间
IMB_pages
分配给Slab的页数
Count
Slab内的记录数
Full?
Slab内是否含有空闲chunk
   memcached之memcached的删除机制和发展方向
---------
memcached是缓存,所以数据不会永久保存在服务器上,这是向系统中引入memcached的前提。本次介绍memcached的数据删除机制,以及memcahced的最新发展方向---二进抽协议(Binary Protocol)和外部引擎支持

memcached在数据删除方面有效利用资源
memcached不会释放已分配的内存。记录超时后,客户端就无法再看见该记录,其存储空间即可重复使用。memcached内部不会监视记录是否过期,而是在get时查看记录的时间戳,检查记录是否过期。这种技术被称为laxy(惰性)expiration。因此,memcached不会在过期监视上耗费CPU时间。

LRU:从缓存中有效删除数据的原理
memcached会优先使用已超时的记录的空间,但即使如此,也会发生追加新记录时空间不足的情况,此时就要使用名为Least Recently Used(LRU)机制来分配空间。顾名思义,这是删除"最近最少使用"的记录的机制。因此,当memcached的内存空间不足时(无法从slab class获取到新的空间时),就从最近未被使用的记录中搜索,并将其空间分配给新的记录。从缓存的实用角度来看,该模型十分理想。
不过,有些情况下LRU机制反倒会造成麻烦。memcached启动时通过"-M"参数可以禁止LRU,如下所示:
[plain]   view plain copy
  1. $ memcached -M -m l024  

启动时必须注意的是,小写的"-m"选项是用来指定最大内存大小的。不指定具体数值则使用默认值64MB。
指定"-M"参数启动后,内存用尽时memcached会返回错误。话说回来,memcached毕竟不是存储器,而是缓存,所以推荐使用LRU。
------
memcached的最新发展方向
memcached的roadmap上有两个大的目标。一个是二进制协议的策划和实现,另一个是外部引擎的加载功能。

关于二进制协议
使用二进协议的理由是它不需要文本协议的解析处理,使得原本高速的memcached的性能更上一层楼,还能减少文本协议的漏洞
二进制协议的格式
协议的包为24字节的帧,其后面是键和无结构数据(Unstructured Data)。包格式十分简单,需要注意的是,占据了16字节的头部(HEADER)分为请求头和响应头两种。头部中包含了表示包的有效性的Magic字节、命令各类、键长度、值长度等信息。
HEADER中引人注目的地方
现在的memcached规格中,键长度最大为250字节,但二进制协议中键的大小用2字节表示。因此,理论上最大可使用65536字节长的键。尽管250字节以上的键并不会太常用,二进制协议发布之后就可以使用巨大的键了。
二进制协议从下一版本1.3系列开始支持

外部引擎支持
外部引擎支持的必要性
世界上有许多memcached的派生软件,其理由是希望永久保存数据、实现数据冗余等,即使牺牲一些性能也在所不惜。目前设计的外部引擎的加载机制能封装memcached的网络功能、事件处理等复杂的处理。因此,现阶段通过强制手段或重新设计等方式使memcached和存储引擎合作的困难就会烟消云散,尝试各种引擎就会变得轻而易举了。
重新审视现在的体系
memcached支持外部存储的难点是,网络和事件处理相关的代码(核心服务器)与内存存储的代码紧密关联。这种现象也称为tightly coupled(紧密耦合)。必须将内存存储的代码从核心服务器中独立出来,才能灵活地支持外部引擎。

 

memcached之memcached的分布式算法
---------
memcached的分布式
memcached虽然称为"分布式"缓存服务器,但服务器端并没有"分布式"功能memcached的分布式,则是完全由客户端程序库实现的。这种分布式是memcached的最大特点。如例:下面假设memcached服务器有node1~node3三台,应用程序要保存键名为:"tokyo","kanagawa","chiba","saitama","gunma"的数据。首先向memcached中添加"tokyo"。将"tokyo"传给客户端程序库后,客户端实现的算法就会根据"键"来决定保存数据的memcached服务器。服务器选定后,即命令它保存"tokyo"及其值。同样,"kanagawa"、"chiba"、"saitama"、"gunma"都是选择服务器再保存。
接下来获取保存的数据。获取时也要将要获取的键"tokyo"传递给函数库。函数库通过与数据保存时相同的算法,根据"键"选择服务器。使用的算法相同,就能选中与保存时相同的服务器,然后发送get命令。只要数据没有因为某些原因被删除,就能获得保存的值。
这样,将不同的键保存到不同的服务器上,就实现了memcached的分布式。memcached服务器增多后,键就会分散,即使一台memcached服务器发生故障无法连接,也不会影响其他的缓存,系统依然能继续运行。

Cache::Memcached的分布式方法
Perl的memcached客户端函数库Cache::Memcached是memcached的作者Brad Fitzpatrick的作品,可以说是原装的函数库了。该函数库实现了分布式功能,是memcached标准的分布式方法。
根据余数计算分散
Cache:Memcached的分布式方法简单来说,就是"根据服务器台数的余数进行分散"。求得键的整数哈希值,再除以服务器台数,根据其余数来选择服务器。
Cache::Memcached在求哈希值时使用了CRC。首先求得字符串的CRC值,根据该值除以服务器节点数目得到的余数决定服务器。当选择的服务器无法连接时,Cache::Memcached会将连接次数添加到键之后,再次计算哈希值并尝试连接。这个动作称为rehash。不希望rehash时可以在生成Cache::Memcached对象时指定"rehash=>0"选项。
根据余数计算分散的缺点
余数计算的方法简单,数据的分散性也相当优秀,但也有其缺点。那就是当添加或移除服务器时,缓存重组的代价相当巨大。添加服务器后,余数就会产生巨变,这样就无法获取与保存时相同的服务器,从而影响缓存的命中率。
Consistent Hashing算法
首先求出memcached服务器(节点)的哈希值,并将其配置到0到2的32次方的圆上。然后用同样的方法求出存储数据的键的哈希值,并映射到圆上。然后从数据映射到的位置开始顺时针查找,将数据保存到找到的第一个服务器上。如果超过2的32次方仍然找不到服务器,就会保存到第一台memcached服务器上。如果添加一台memcached服务器。余数分布式算法由于保存键的服务器发生巨大变化而影响缓存的命中率,但Consistent Hashing中,只有在圆上增加服务器的地点逆时针方向的第一台服务器之间的键会受到影响。因此,Consistem Hashing最大限度地抑制了键的重新分布。而且,有的Consistent Hashing的实现方法还采用了虚拟节点的思想。使用一般的hash函数的话,服务器的映射地点的分布非常不均匀。因此,使用虚拟节点的思想,为每个物理节点(服务器)在圆上分配100~200个点。这样就能抑制分布不均匀,最在限度地减小服务器增减时的
缓存重新分布。



Xmemcached是一个高性能的基于java nio的memcached客户端。在经过三个RC版本后,正式发布1.10-final版本。

 

xmemcached特性一览
1、高性能
2、支持完整的memcached文本协议,二进制协议将在1.2版本实现。
3、支持JMX,可以通过MBean调整性能参数、动态添加/移除server、查看统计等。
4、支持客户端统计
5、支持memcached节点的动态增减。
6、支持memcached分布:余数分布和一致性哈希分布。
7、更多的性能调整选项。

 

xmemcached与spymemcached的对比

1、xmemcached比spymemcached有更好的性能表现,在get、set、delete、multi-gets等操作的测试中都远远超过或者接近spymemcached。
   xmemcached在win32和linux两个平台上都有极佳的性能表现。

2、xmemcached支持动态地添加或者移除memcached server,可以通过编程或者JMX来做到。

3、xmemcached支持JMX,可以通过jmx调整性能参数、添加/移除memcached节点、查看统计

4、xmemcached有客户端统计,可以统计xmemcached客户端的各种操作的总次数

5、xmemcached允许调整更多的网络层参数和优化选项.

6、xmemcached暂未支持二进制协议,计划在1.2版本中实现。

7、xmemcached的API模型是同步的,而spymemcached的API模型是异步模型,同步模型对应用编程来说更容易使用和直观。

 

8、xmemcached的序列化机制,是使用了spymemcached的序列化机制,并做了部分改造。

 

 

 

项目主页:http://code.google.com/p/xmemcached/

 

下载地址:http://code.google.com/p/xmemcached/downloads/list

 

 wiki地址:http://code.google.com/p/xmemcached/w/list

 

    讨论组:http://groups.google.com/group/xmemcached

 

       协议: Apache License 2.0

 

  svn地址:http://xmemcached.googlecode.com/svn/branches/xmemcached-1.10/

你可能感兴趣的:(编程,SVN,memcached,Google,网络协议)