Memcached学习笔记

Memcached Like A HashTable 特征:
    系列文章: http://kb.cnblogs.com/page/42731/
  • 协议简单
memcached的服务器客户端不采用复杂的xml格式,而是采用简单的基于文本行的协议。因此,通过telenet也能在memcached上面进行保存数据,获取数据操作,例子:
$ telnet localhost 11211
Trying 127.0.0.1...
Connected to localhost.localdomain (127.0.0.1).
Escape character is '^]'.
set foo 0 0 3 (保存命令)
bar (数据)
STORED (结果)
get foo (取得命令)
VALUE foo 0 3 (数据)
bar (数据)
Memcached的协议文档:
  • 基于libevent事件处理
libevent(一个程序库),将linux的epoll,BSD类操作系统的kqueue事件处理功能封装成统一接口。即使服务器连接数增加,也能发挥O(1)性能。关于事件处理:
  • 内置内存存储方式
memcached将数据保存字memcached内置的内存空间中。数据仅存在内存中,因此重启memcached、重启操作系统都会造成全部数据丢失。
内存容量达到指标之后,会基于LRU(Last recently used)算法删除不使用的缓存。memcached是为缓存而设计的服务器,因此没有过多考虑数据的永久性问题。


  • memcached不相互通信的分布式
memcached尽管是“分布式”缓存服务器,但服务器端并没有分布式功能。各个memcached节点不会进行通信共享信息。memcached的分布式结构:

Memcached安装

  • Memcached支持平台
Linux
FeeBSD
Solaris
Mac OS X
  • memcached 安装
1、前置条件:安装memcached依赖的libevent库。>yum install libevent libevent-devel或者wget http://www.monkey.org/~provos/libevent-1.2.tar.gz这种方式安装。
2、下载memcached,安装步骤:configure、make、make install
>wget http://www.danga.com/memcached/dist/memcached-1.2.5.tar.gz
>tar zxf memcached-1.2.5.tar.gz
>cd memcached
>./configure
>make
>sudo make install
默认情况下,memcached 安装在/usr/local/bin下。
  • memcached的启动
>/usr/local/bin/memcached -p 11211 -m 64m -vv
后台启动
>/usr/local/bin/memcached -p 11211 -m 64m -d
查看memcache启动选项
>/usr/local/bin/memcached -h

参数说明:
-p 使用的Tcp端口号,默认为11211
-m最大内存大小,默认为64M
-vv使用very vrebose 模式启动,调试信息和错误信息输出到控制台
-d作为daemon在后台启动
  • 连接memcached客户端,以Perl 、PHP为主。
Perl
PHP
Python
Ruby
C#
C/C++
Lua
   
Memcached内存存储, http://lists.danga.com/pipermail/memcached/2003-September/000214.html  http://lists.danga.com/pipermail/memcached/2003-October/000302.html
  • memcached一开始使用的是malloc/free的方式来进行内存分配,这种方式导致的结果是一段时间之后内存就会出现碎片。
  • 最新的memcached采用的是slabs Allocation方式进行内存分配,Using Fixed-size memory chunks ,将内存划分为64byte(64*8bits) ,128byte,256byte ,etc每次都Doubling递增,直到1M。每一种大小分类的内存块的集合我们使用chunk(块)来进行描述管理。当需要申请一个特定大小的内存块时,会向上取最接近的内存大小快的chunk分配给申请者,如果没有空闲的内存块来分配的时候有两种处理方式:1、使用LRU策略从缓存Queue中释放一个内存块。2、从操作系统获取更多的内存。一般情况下是每次申请!M然后将其分割成需要的大小chunk。
  • 碎片和使用率的权衡:这种内存模式结果是Zero fragmentation , High percentage of Memory is wasted。防止内存使用率问题的方式是,尽量使放入的对象和分配的内存块大小接近。目前没有很好的方式来处理这问题,其中一种解决方法是:slab subsystem 会分析运行时的申请对象大小的共性,依据共性动态的修改chunks 的size List 以此来是的内存使用率得到提升,目前暂时没有做这个功能。
         这是另外一个人总结的slab subsystem方案:
          

Slab Allocator的缺点

Slab Allocator解决了当初的内存碎片问题,但新的机制也给memcached带来了新的问题。

这个问题就是,由于分配的是特定长度的内存,因此无法有效利用分配的内存。 例如,将100字节的数据缓存到128字节的chunk中,剩余的28字节就浪费了(图3)。


图3 chunk空间的使用

对于该问题目前还没有完美的解决方案,但在文档中记载了比较有效的解决方案。

The most efficient way to reduce the waste is to use a list of size classes that closely matches (if that's at all possible) common sizes of objects that the clients of this particular installation of memcached are likely to store.

就是说,如果预先知道客户端发送的数据的公用大小,或者仅缓存大小相同的数据的情况下, 只要使用适合数据大小的组的列表,就可以减少浪费。

但是很遗憾,现在还不能进行任何调优,只能期待以后的版本了。 但是,我们可以调节slab class的大小的差别。 接下来说明growth factor选项。

使用Growth Factor进行调优

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

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

$ memcached -f 2 -vv
  • 查看memcached的内存状态
1、memcached stats命令使用 , stats 输出全部信息, stats slabs 或 stats items 获取关于魂村的记录信息
      $ telnet localhost 11211
Trying ::1...
Connected to localhost.
Escape character is '^]'.
stats slabs
STAT active_slabs 0
STAT total_malloced 0
END
set foo 0 0 3
bar
STORED
stats slabs
STAT 1:chunk_size 80
STAT 1:chunks_per_page 13107
STAT 1:total_pages 1
STAT 1:total_chunks 13107
STAT 1:used_chunks 1
STAT 1:free_chunks 13106
STAT 1:free_chunks_end 0
STAT 1:mem_requested 55 数据为key+value 6字节,所以有49字节做memcached自己的信息
STAT 1:get_hits 0
STAT 1:cmd_set 1
STAT 1:delete_hits 0
STAT 1:incr_hits 0
STAT 1:decr_hits 0
STAT 1:cas_hits 0
STAT 1:cas_badval 0
STAT 1:touch_hits 0
STAT active_slabs 1
STAT total_malloced 1048560
END
get foo
VALUE foo 0 3
bar
END
2、如果安装了libmemcached,可以一次性向多台服务器请求信息
     $ memsta -servers=server1,server2,server3

Memcached Big-O O(1) & Lazy Expiration  & LUR & Consistent Hash   
  • Memcached 的Get时间复杂度为o(1) , 因此由于这种支持,是的Memcached不能做Iterator遍历记录值。
  • Memecached不会去跟踪Value的过期时间主动释放已分配的内存,记录超时之后会变得对用户透明(Invisible) , 存储空间还是可以重复利用的。Laz expiration 是的Memcached不会在过期监控上耗费CPU。而是在Get的时候检查记录的时间戳是否过期。
  • Memecached优先选择使用已超时的记录空间,如果发生追加新纪录空间不足的情况。采用LRU(Least Recently Used)。 Memcached -M 可以禁止使用LRU。Memcached在进行Set 或者Add 是会将每一个记录的Counter 设置为Current Time ,在进行Get 操作是也会将定位到的记录Counter更新为Current Time。在进行LRU时会替换掉Counter最小的那个Chunks的记录值。 
  • Consistent Hash:
1、Memcached集群情况下:需要将key1,key2,key3......,keyn 分布到集群机器 node1,node2,node3 上面 已有方式:
通过Key的Hash值%nodes.size 得到机器偏移,Code:
     $server_id = hashfunc($key) % $servercount;
     这种方式如果遇到新增或者减少集群,可能就会是原有的keys Hash定位机器全部发生变化。
一致性Hash算法参考实例(并不是Memcached的算法):

在此我们采用了一种新的方式来解决问题,处理服务器的选择不再仅仅依赖key的hash本身而是将服务实例(节点)的配置也进行hash运算。

  1. 首先求出每个服务节点的hash,并将其配置到一个0~2^32的圆环(continuum)区间上。
  2. 其次使用同样的方法求出你所需要存储的key的hash,也将其配置到这个圆环(continuum)上。
  3. 然后从数据映射到的位置开始顺时针查找,将数据保存到找到的第一个服务节点上。如果超过2^32仍然找不到服务节点,就会保存到第一个memcached服务节点上。

 private static int origCompatHashingAlg( String key ) {
        int hash    = 0;
        char[] cArr = key.toCharArray();

        for ( int i = 0; i < cArr.length; ++i ) {
            hash = (hash * 33) + cArr[i];
        }

        return hash;
    }
这里还有另一个改进版本的算法:
    private static int newCompatHashingAlg( String key ) {
        CRC32 checksum = new CRC32();
        checksum.update( key.getBytes() );
        int crc = (int) checksum.getValue();

        return (crc >> 16) & 0x7fff;
    }这里需要说明的是对Key取32位的校验和然后向右16位和7fffff取与得到在圆周上的位置。

Memcached使用过程中的注意点:
  • memcached连接句柄需要保存起来,防止由于TCP连接建立的开销,防止短时间反复进行TCP连接断开而导致端口资源枯竭。
  • 当一台Memcached机器故障了,如何将定位到这台的数据进行Rehash,连接其他服务器。
  • 像新闻主页这样所有数据共享的缓存数据,设置信息等数据,访问很容易集中在某台Memcached服务器上面,如果这个服务器故障可能会对所有用户造成影响。这种数据可以通过设置命名规则,符合命名规则的数据自动保存在多台Memcached上面做备份,请求是选取一台服务器。这样Memcached服务器故障之后不会产生其他影响。
  • 使用daemontools等工具处理Memcached进程死掉之后重启Memcached
  • 使用监控平台,例如nagios等开源软件监视Memcached
  • Memcached和Redis的对比
  • Memcached不适合存储Session信息,理由:1、当Memcached发生故障Session丢失会导致部分用户被踢掉线 2、Memcached的回收机制可能会导致用户无缘无故掉线。memcached 设计的目标是缓存数据并不是存储数据系统。推荐方案:
          
      • 当用户登录时,将Session “set”到memcached,并写入数据库;
      • 在Session中增加一个字段,标识Session最后写入数据库的时间;
      • 每个页面加载的时候,优先从memcached读取Session,其次从数据库读取;
      • 每加载N页或者Y分钟后,再次将Session写入数据库;
      • 从数据库中获取过期Session,优先从memcached中获取最新数据。
     















  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值