MemCached详解

标签: memcached | 发表时间:2012-04-16 19:02 | 作者:zlb824
出处:http://blog.csdn.net

首先,我们来了解一下MemCached与MemCache之间的区别:

Memcache是什么?

Memcache是一个自由和开放源代码、高性能、分配的内存对象缓存系统。用于加速动态web应用程序,减轻数据库负载。

它可以应对任意多个连接,使用非阻塞的网络IO。由于它的工作机制是在内存中开辟一块空间,然后建立一个HashTable,Memcached自管理这 些HashTable。

Memcached又是什么?

Memcached是Memcache系统的主程序文件,以守护程序方式运行于一个或多个服务器中,随时接受客 户端的连接操作,使用共享内存存取数据。

那PHP中的Memcache是什么?php中的所讲的memcache是用于连接Memecached的php支持扩展之一(可用phpinfo查看),类似mbstring,eAccelerator。

简单的说

Memcache是总的缓存系统项目名称,容易和PHP中的Memcache混淆。

我们常提到Memcache其实是PHP中的Memcache,即PHP的Memcached扩展支持。

我们常提到Memcached是服务端主程序文件,服务端安装程序。

为了让你的程序飞起来,必须安装memcached服务端程序和PHP的Memcached扩展,所以如果您要使用Memcache来缓存系统,memcache和memcached两样我们都需要安装。

接下来,我们来了解一下 Memcached有关的知识点:

Memcached是danga.com(运营LiveJournal的技术团队)开发的一套分布式内存对象缓存系统,用于在动态系统中减少数据库 负载,提升性能。

它所具有的特点有:

  • 协议简单
  • 基于libevent的事件处理
  • 内置内存存储方式
  • memcached不互相通信的分布式

    Memcached处理的原子是每一个(key,value)对(以下简称kv对),key会通过一个hash算法转化成hash-key,便于查找、对比以及做到尽可能的散列。同时,memcached用的是一个二级散列,通过一张大hash表来维护。

    Memcached有两个核心组件组成:服务端(ms)和客户端(mc),在一个memcached的查询中,mc先通过计算key的hash值来 确定kv对所处在的ms位置。当ms确定后,客户端就会发送一个查询请求给对应的ms,让它来查找确切的数据。因为这之间没有交互以及多播协议,所以 memcached交互带给网络的影响是最小化的。

    内存分配

    默认情况下,ms是用一个内置的叫“块分配器”的组件来分配内存的。舍弃c++标准的malloc/free的内存分配,而采用块分配器的主要目的 是为了避免内存碎片,否则操作系统要花费更多时间来查找这些逻辑上连续的内存块(实际上是断开的)。用了块分配器,ms会轮流的对内存进行大块的分配,并 不断重用。当然由于块的大小各不相同,当数据大小和块大小不太相符的情况下,还是有可能导致内存的浪费。

    同时,ms对key和data都有相应的限制,key的长度不能超过250字节,data也不能超过块大小的限制 --- 1MB。
    因为mc所使用的hash算法,并不会考虑到每个ms的内存大小。理论上mc会分配概率上等量的kv对给每个ms,这样如果每个ms的内存都不太一样,那 可能会导致内存使用率的降低。所以一种替代的解决方案是,根据每个ms的内存大小,找出他们的最大公约数,然后在每个ms上开n个容量=最大公约数的 instance,这样就等于拥有了多个容量大小一样的子ms,从而提供整体的内存使用率。

    缓存策略

    当ms的hash表满了之后,新的插入数据会替代老的数据,更新的策略是LRU(最近最少使用),以及每个kv对的有效时限。Kv对存储有效时限是在mc端由app设置并作为参数传给ms的。

    同时ms采用是偷懒替代法,ms不会开额外的进程来实时监测过时的kv对并删除,而是当且仅当,新来一个插入的数据,而此时又没有多余的空间放了,才会进行清除动作。

    缓存数据库查询

    现在memcached最流行的一种使用方式是缓存数据库查询,下面举一个简单例子说明:

    App需要得到userid=xxx的用户信息,对应的查询语句类似:

    “SELECT * FROM users WHERE userid = xxx”

    App先去问cache,有没有“user:userid”(key定义可预先定义约束好)的数据,如果有,返回数据;如果没有,App会从数据库中读取数据,并调用cache的add函数,把数据加入cache中。

    当取的数据需要更新,app会调用cache的update函数,来保持数据库与cache的数据同步。

    从上面的例子我们也可以发现,一旦数据库的数据发现变化,我们一定要及时更新cache中的数据,来保证app读到的是同步的正确数据。当然我们可 以通过定时器方式记录下cache中数据的失效时间,时间一过就会激发事件对cache进行更新,但这之间总会有时间上的延迟,导致app可能从 cache读到脏数据,这也被称为狗洞问题。(以后我会专门描述研究这个问题)

    数据冗余与故障预防

    从设计角度上,memcached是没有数据冗余环节的,它本身就是一个大规模的高性能cache层,加入数据冗余所能带来的只有设计的复杂性和提高系统的开支。

    当一个ms上丢失了数据之后,app还是可以从数据库中取得数据。不过更谨慎的做法是在某些ms不能正常工作时,提供额外的ms来支持cache,这样就不会因为app从cache中取不到数据而一下子给数据库带来过大的负载。

    同时为了减少某台ms故障所带来的影响,可以使用“热备份”方案,就是用一台新的ms来取代有问题的ms,当然新的ms还是要用原来ms的IP地址,大不了数据重新装载一遍。

    另外一种方式,就是提高你ms的节点数,然后mc会实时侦查每个节点的状态,如果发现某个节点长时间没有响应,就会从mc的可用server列表里 删除,并对server节点进行重新hash定位。当然这样也会造成的问题是,原本key存储在B上,变成存储在C上了。所以此方案本身也有其弱点,最好 能和“热备份”方案结合使用,就可以使故障造成的影响最小化。

    Memcached客户端(mc)

    Memcached客户端有各种语言的版本供大家使用,包括java,c,php,.net等等,具体可参见 memcached api page [2]。
    大家可以根据自己项目的需要,选择合适的客户端来集成。

    缓存式的WEB应用程序架构

    有了缓存的支持,我们可以在传统的app层和db层之间加入cache层,每个app服务器都可以绑定一个mc,每次数据的读取都可以从ms中取得,如果 没有,再从db层读取。而当数据要进行更新时,除了要发送update的sql给db层,同时也要将更新的数据发给mc,让mc去更新ms中的数据。

    性能测试

    Memcached 写速度
    平均速度: 16222 次/秒
    最大速度 18799 次/秒

    Memcached 读速度
    平均速度: 20971 次/秒
    最大速度 22497 次/秒

    Memcachedb 写速度
    平均速度: 8958 次/秒
    最大速度 10480 次/秒

    Memcachedb 读速度
    平均速度: 6871 次/秒
    最大速度 12542 次/秒
    Memcached客户端(mc)的使用方法

    创建memcached.xml文件:

    <?xml version="1.0" encoding="UTF-8"?>
    <memcached>
       
        <client name="mclient0" compressEnable="true" defaultEncoding="UTF-8" socketpool="pool0">
            <errorHandler>com.moit.xplatform.asf.cache.memcached.MemcachedErrorHandler</errorHandler>
        </client>
       
        <client name="mclient1" compressEnable="true" defaultEncoding="UTF-8" socketpool="pool1">
            <errorHandler>com.moit.xplatform.asf.cache.memcached.MemcachedErrorHandler</errorHandler>
        </client>
       
        <client name="mclient2" compressEnable="true" defaultEncoding="UTF-8" socketpool="pool2">
            <errorHandler>com.moit.xplatform.asf.cache.memcached.MemcachedErrorHandler</errorHandler>
        </client>
       
        <socketpool name="pool0" failover="true" initConn="5" minConn="5" maxConn="250" maintSleep="0"
            nagle="false" socketTO="3000" aliveCheck="true">
    	<!--MS的服务器地址-->
            <servers>192.168.3.251:11211,192.168.3.251:11211</servers>
        </socketpool>
       
        <socketpool name="pool1" failover="true" initConn="5" minConn="5" maxConn="250" maintSleep="0"
            nagle="false" socketTO="3000" aliveCheck="true">
            <servers>192.168.3.251:11211,192.168.3.251:11211</servers>
        </socketpool>
       
        <socketpool name="pool2" failover="true" initConn="5" minConn="5" maxConn="250" maintSleep="0"
            nagle="false" socketTO="3000" aliveCheck="true">
            <servers>192.168.3.251:11211,192.168.3.251:11211</servers>
        </socketpool>
        <cluster name="cluster1">
            <memCachedClients>mclient1,mclient2</memCachedClients>
        </cluster>
    </memcached>
    //用containsKey方法判断cache服务器按指定的key值是否存在。
    System.out.println("是否包含了key的数据="+cache.containsKey("key"));
    if(cache.containsKey("key"))
    {
        System.out.println("包含了key的数据");
        System.out.println("从cache服务器获得key值");
    }
    else
    {
        System.out.println("没有包含了key的数据");
        System.out.println("cache服务器,没有数据,则去取数据库数据!");
    }

    例子如下:

    static ICacheManager<IMemcachedCache> manager;

    public String memcache()
    {
        manager = CacheUtil.getCacheManager(IMemcachedCache.class,
        MemcachedCacheManager.class.getName());
        manager.start();
        try{
           //"mclient0"为配置文件中client标签中的名字
           IMemcachedCache cache = manager.getCache("mclient0");
           //根据key得到缓存数据
            String a =(String)cache.get("key");
           //用containsKey方法判断cache服务器按指定的key值是否存在。
            System.out.println("是否包含了key的数据="+cache.containsKey("key"));
           if(cache.containsKey("key"))
           {
            System.out.println("包含了key的数据");
            System.out.println("从cache服务器获得key值");
           }
           else
           {
            System.out.println("没有包含了key的数据");
            System.out.println("cache服务器,没有数据,则去取数据库数据!");
           }
           //根据key删除服务器上的对应的缓存数据
            cache.remove("key");
           //根据key保存数据到服务器上
            cache.put("key", "你好!");
           //设置带有过期时间的例子
            //过30分钟
            Calendar calendar = Calendar.getInstance();//当前日期
            calendar.setTime(new Date());
            calendar.add(Calendar.MINUTE, 30);//
            cache.remove("keytime");
            cache.put("keytime", "30分钟后过期",calendar.getTime());
            System.out.println("30分钟后过期=keytime="+cache.get("keytime"));
            System.out.println("cache服务器getTime="+calendar.getTime());  
      
       }finally{ manager.stop();}
         //jsp 使用请参考test.jsp文件
         return "testmempage";
    }

    安装memcache

    # cd /usr/local/src
    # wget http://pecl.php.net/get/memcache-2.2.5.tgz
    # gzip -d memcache-2.2.5.tgz
    # tar xvf memcache-2.2.5.tar
    # cd memcache-2.2.5

    以下几句,是以php所在目录为/usr/local/php为例,如果您的php有变化,请自行替换几句中/usr/local/php的部分

    # /usr/local/php/bin/phpize
    # ./configure --enable-memcache --with-php-config=/usr/local/php/bin/php-config --with-zlib-dir
    # make && make install

    将memcache加入php扩展

    # vi /etc/php.ini(/etc/php.ini地址为我的php.ini位置,如果你不知道你的php.ini在哪里,可以用# find / -name php.ini进行查找,或者传个探针phpinfo,找到Configuration File (php.ini) Path)中php.ini的位置.

    末尾加入

    按键盘上的 i 开始编辑

    CTRL+F翻页拉到最下面在[Zend]之前加入

    extension_dir = "/usr/local/php/lib/php/extensions/no-debug-non-zts-20060613/"
    extension=memcache.so

    按Esc键,再输入

    :wq

    保存退出

    重启你的web服务器,比如apache

       
    /etc/init.d/httpd restart

    下面刷新下PHP探针,看下是不是有这个了,有的话就是装好了

    memcache
    Version 2.2.5memcache
    Version 2.2.5

    下面安装memcached

    装memcached首先需要安装安装libevent

    如果是centos可以yum安装

    # yum install libevent-devel

    如果不支持yum的系统,可以这样装libevent

    # cd /usr/local/src
    # wget http://www.monkey.org/~provos/libevent-1.4.12-stable.tar.gz
    # tar vxf libevent-1.4.12-stable.tar.gz
    # cd libevent-1.4.12
    # ./configure --prefix=/usr/local/libevent
    # make && make install

    接续安装memcached

    # cd /usr/local/src
    # wget http://cloud.github.com/downloads/saberma/saberma.github.com/memcached-1.4.4.tar.gz
    # tar vxf memcached-1.4.4.tar.gz
    # cd memcached-1.4.4
    # ./configure --prefix=/usr/local/memcached
    # make && make install

    安装完后启动memcached并分配32m内存(32为使用内存数,可按自身情况修改)

    /usr/local/memcached/bin/memcached -d -m 32 -l 127.0.0.1 -p 11211 -u root

    将memcached加入启动项

    # vi /etc/rc.d/rc.local

    按键盘上的 i 开始编辑

    在最后加入

    /usr/local/memcached/bin/memcached -d -m 32 -l 127.0.0.1 -p 11211 -u root

    按Esc键,再输入

    :wq

    保存退出

    如果需要,可以reboot一下,不过不用reboot应该已经生效~

    加速效果测试

    用没有什么负载的Discuz X1做个测试,未启用时

    GMT+8, 2010-9-12 09:08, Processed in 0.038893 second(s), 2 queries.

    缓存启用后的效果,不过总体感觉VPS上效果不如用eAccelerato缓存加入效果那么明显

    GMT+8, 2010-9-12 09:08, Processed in 0.008383 second(s), 2 queries, Memcache On.

    大功告成,打完收工!~~

    参考资源:
    http://www.chinaz.com/web/2010/0916/133310.shtml
    http://sebug.net/paper/databases/nosql/Nosql.html#MemCached_4727136253125943_099_19137860612924817

    http://blog.sina.com.cn/s/blog_6cabf4070100pccn.html
  • 作者:zlb824 发表于2012-4-16 19:02:28 原文链接
    阅读:2 评论:0 查看评论

    相关 [memcached] 推荐:

    memcached+magent实现memcached集群

    - - 编程语言 - ITeye博客
    首先说明下memcached存在如下问题.   本身没有内置分布式功能,无法实现使用多台Memcache服务器来存储不同的数据,最大程度的使用相同的资源;无法同步数据,容易造成单点故障. (memagent代理实现集群).       在 Memcached中可以保存的item数据量是没有限制的,只要内存足够.

    MemCached详解

    - - CSDN博客推荐文章
    首先,我们来了解一下MemCached与MemCache之间的区别:. Memcache是一个自由和开放源代码、高性能、分配的内存对象缓存系统. 用于加速动态web应用程序,减轻数据库负载. 它可以应对任意多个连接,使用非阻塞的网络IO. 由于它的工作机制是在内存中开辟一块空间,然后建立一个HashTable,Memcached自管理这 些HashTable.

    Memcached调优

    - - 四火的唠叨
    文章系本人原创,转载请保持完整性并注明出自 《四火的唠叨》. 项目中有一个对实时响应性比较高的服务,引入了Memcached以减少延迟和减少数据库压力. 但是期间遇到了一些问题,这里记录一些调优细节. 最开始我使用的是 Memcached Java Client,但是最后放弃了,放弃原因包括:.

    memcached协议

    - - 开源软件 - ITeye博客
    旧版: http://code.sixapart.com/svn/memcached/trunk/server/doc/protocol.txt. 新版: https://github.com/memcached/memcached/blob/master/doc/protocol.txt.

    Java使用memcached

    - - 互联网 - ITeye博客
    首先到 http://danga.com/memcached下载memcached的windows版本和java客户端jar包,目前最新版本是memcached-1.2.1-win32.zip和java_memcached-release_1.6.zip,分别解压后即可. 然后是安装运行memcached服务器,我们将memcached-1.2.1-win32.zip解压后,进入其目录,然后运行如下命令:c:>;memcached.exe -d install
    c:>memcached.exe -l 127.0.0.1 -m 32 -d start.

    Spring+memcached整合

    - - 行业应用 - ITeye博客
    1)  下载memcached服务端memcached-1.2.6-win32-bin.zip,地址:http:. 2)  下载java版客户端 java_memcached-release_2.6.1.zip. 3)  解压缩memcached-1.2.6-win32-bin.zip到指定目录,例如:D:\memcached-1.2.6-win32 ,.

    转 redis vs memcached

    - - 数据库 - ITeye博客
    传统MySQL+ Memcached架构遇到的问题.   实际MySQL是适合进行海量数据存储的,通过Memcached将热点数据加载到cache,加速访问,很多公司都曾经使用过这样的架构,但随着业务数据量的不断增加,和访问量的持续增长,我们遇到了很多问题:.   1.MySQL需要不断进行拆库拆表,Memcached也需不断跟着扩容,扩容和维护工作占据大量开发时间.

    Memcached安全性

    - - xiaobaoqiu Blog
    1.Memcached -l参数. 1.Memcached -l参数. 最近整理了组内使用的Memcached. 发现很多问题,其中一个问题就是开发机器测试机器可以直连线上的Memcached. 这也是memcached公认的问题:memcached 是一种很简单、有效的协议,但也有其缺点,就是 memcached 自身没有 ACL 控制(或者相当弱).

    Memcached的LRU算法

    - Eric - 平凡的世界
    最近计划对Memcached做一些尝试性的改造,主要是针对Memcached在处理过期数据的时候进行改造,以实现在一个缓存的过期时间达到的时候,可以对该缓存的数据进行一个验证和存储的处理. 这个需求,主要是为了解决MySQL的写入瓶颈,通过延期、合并写入请求来减少MySQL的并发写入量. 现在逐渐记录出来和有需要的朋友一起讨论.

    [转]memCached 客户端

    - - 小鸥的博客
    memcache客户端下载. 许多Web应用都将数据保存到DBMS中,应用服务器从中读取数据并在浏览器中显示. 但随着数据量的增大、访问的集中,就会出现RDBMS的负担加重、数据库响应恶化、 网站显示延迟等重大影响. memcached 是以LiveJournal 旗下Danga Interactive 公司的Brad Fitzpatric 为首开发的一款软件.