zoukankan      html  css  js  c++  java
  • Memcached 内存级缓存

    Memcached在大型网站中应用
        memcached是一个高性能的分布式的内存对象缓存系统,通过在内存里维护一个统一的巨大的hash表,它能够用来存储各种格式的数据,包括图像、视 频、文件以及数据库检索的结果等。最初为了加速 LiveJournal 访问速度而开发的,后来被很多大型的网站采用。起初作者编写它可能是为了提高动态网页应用,为了减轻数据库检索的压力,来做的这个缓存系统。它的缓存是一 种分布式的,也就是可以允许不同主机上的多个用户同时访问这个缓存系统, 这种方法不仅解决了共享内存只能是单机的弊端, 同时也解决了数据库检索的压力,最大的优点是提高了访问获取数据的速度!基于memcached作者对分布式cache的理解和解决方案。 memcached完全可以用到其他地方 比如分布式数据库, 分布式计算等领域。
    1、 memcached 协议理解
    memcache是为了加快http://www.livejournal.com/访问速度而诞生的一个项目。
    它的官方主页是:http://www.danga.com/memcached/
    目前在网站开发中应用较少,主要的应用有:
    http://www.danga.com/memcached/users.bml
    在国内的网站开发中,还很少没见到有应用的,中文资料十分匮乏。
    工 作机制:通过在内存中开辟一块区域来维持一个大的hash表来加快页面访问速度,和数据库是独立的。但是目前主要用来缓存数据库的数据。允许多个 server通过网络形成一个大的hash,用户不必关心数据存放在哪,只调用相关接口就可。存放在内存的数据通过LRU算法进行淘汰出内存。同时可以通 过删除和设置失效时间来淘汰存放在内存的数据。
    2、 memcached 使用入门
    2.1 memcached的安装
    <1>memcached服务的安装
    先检查linux内核版本,建议将memcached 安装在2.6以上。
    因为memcached 需要用到libevent和 epoll 。
    memcached安装前首先确定你的服务器上面安装了libevent库,
    libevent下载地址( http://www.monkey.org/~provos/libevent/)。
    下载memcached的源码( http://www.danga.com/memcached/download.bml)。
    Memcached最初是用perl写的,现在的版本是用c写的。
    下载后拷贝到一个目录,安装需要root用户来执行
    tar -zxvf memcached-1.1.12.tar.gz
    cd memcached-1.1.12
    ./configure
    这里必须先要configure, 它会检测你的系统情况,然后生成一个config.h文件和其它的几个文件,另外和其它的configure一样,你可以配置它的安装路径等等。默认应用程序安装在/usr/local/bin目录下。
    make //编译
    make install //安装
    <2>memcached客户端的安装
    根据memcached协议,用户可以自己写出符合自己要求的客户端程序。目前http://www.danga.com/memcached/download.bml
    提供perl,c,java,python,php等客户端程序供下载和参考。下面我就以perl客户端程序为例说明客户端的安装:
    下载后拷贝到一个目录,安装需要root用户来执行
    tar -zxvf Cache-Memcached-1.14.tar.gz
    cd Cache-Memcached-1.14
    perl makefile.pl
    make
    make install
    make test
    这样就安装好了memcahced, 启动memcached就可使用分布式缓存系统了!
    2.2 快速入门
    <1> memcached服务的启动
    memcached的启动非常简单,它没有配置文件,只要配置好几个参数就可以使用了。下面我以一个实际应用的例子,具体说明一下:
    memcached –d –m 500 -l 64.128.191.151 -p 11211 -vv >>/var/www/kelly/test/logs/memcached_$$.log
    启 动的这个memcached为一个后台守护进程模式(-d), 然后缓存的空间为500M(-m), 监听(-l)服务器64.128.191.15的11211号端口(-p).,将日志写道 /var/www/kelly/test/logs/memcached_$$.log(-vv)。
    其实memcached的参数也非常的有限,就下面这几个:
    ? -p port number to listen on
    ? -l interface to listen on, default is INDRR_ANY
    ? -d run as a daemon
    ? -r maximize core file limit
    ? -u assume identity of (only when run as root)
    ? -m max memory to use for items in megabytes, default is 64 MB
    ? -M return error on memory exhausted (rather than removing items)
    ? -c max simultaneous connections, default is 1024
    ? -k lock down all paged memory
    ? -v verbose (print errors/warnings while in event loop)
    ? -vv very verbose (also print client commands/reponses)
    ? -h print this help and exit
    ? -i print memcached and libevent license
    我们也可以将这个启动脚本写道/etc/rc.d或者/erc/rc.local,这样可以在服务器启动时候执行。
    <2> memcached客户端的连接
    下面我就以perl客户端程序为例说明客户端的连接:
    启动两个memcached server
    memcached –d –m 500 -l 64.128.191.151 -p 11211 -vv >>/var/www/kelly/test/logs/memcached_$$.log
    memcached –d –m 500 -l 64.128.191.151 -p 11212 -vv >>/var/www/kelly/test/logs/memcached_$$.log
    perl客户端程序
    #!/usr/bin/perl
    use Cache::Memcached;
    my $memd = new Cache::Memcached {
    'servers' => [ "64.128.191.15:11211" , "64.128.191.15:11212"],
    };
    my $val = $memd->get( "my_key" );
    if ( $val )
    {
    print "Value is '$val' ";
    }
    # Set a value
    $memd->set("my_key", "123");
    $memd->disconnect_all();
    运行测试
    $ perl test-memcache.pl
    $ perl test-memcache.pl
    Value is '123'
    可以看到,第一次没有取得my_key,第二次从memcached中得到my_key的值。
    同时通过查看日志,可以发现的确存储在两个memcache server中。
    这个简单的例子,解释了如何在memcached中存取数据,以及memcache是真正的分布式缓存系统。
    当然,这还只是很简单的例子,体现不出memcache的优势,下面将通过一个很具体的例子,给出详细的应用。
    3、 memcached在Zorpia的应用
    http://www.zorpia.com 是一个网页相册,博客,交友,论坛的大型网站公司。现在已有超过140万活跃使用者遍布美国,香港,东南亚,欧洲,澳洲,亚洲等其它地区。每天的访问量都在增长,已成为全世界排名第五的社会生活关系网。
    Memcached也采用了memcached来提高网站的访问速度,并且取得了很好的效果,我在负责zorpia的memcached项目时候积累了一些经验,主要的做法如下:
    1) 通过对memcache的perl客户端进行包装,定制自己的客户端。
    2) 通过制定符合zorpia规范的hash key命名规范
    ? ? memcache中需要存储的内容的key均由string组成。
    这个string统一由一个memcache.pm的subroutine来实现。(假设这个subroutine是 get_key() )
    ? ? memcache中存放两种形式的数据
    (1) result of SQL query :
    (2) 普通变量(variable)
    这两种数据的key的组合方式是不相同的,由get_key进行判断和完成
    ? ? 关于get_key 和 naming rule
    get_key subroutine完成所有memcache key的命名,naming rule也是在它里边体现:
    (1)输入参数 -- hash结构,里边定义了当前需要存放的数据的信息
    结构
    (2)返回值 -- string,返回数据的key_name
    ?必须确定 get_key 的传入hash的结构,
    hash中主要有两个元素
    type --- 定义当前数据结构的类型 ,有 'var' , 'sql'两种值
    object --- 存放当前数据结构的详细信息,
    当 type eq 'var'时,object表示变量的名字,该名字由程序员指定
    当 type eq 'sql'时,object包含所存放sql的主要基本信息,hash结构,也由程序员按照规则制定
    ## 当variable 数据类型,比较简单
    $var_hash = {
    type => 'var', ## var表示当前类型是 variable
    object => 'language', ## language代表variable的名字
    };
    生成的key是Zorpia::var| language
    ## sql 数据
    比如select first_name from user where user_id =2那么hash为
    $sql_hash = {
    type => 'sql',
    object => {
    table => {table2=>"user",}, ## sql 查询的表
    column => {column1=>"first_name",}, ## sql所要查询的column
    condition => { user_id =>"2",}, ## sql条件
    },
    };
    生成的key是Zorpia::sql|user|first_name| user_id =2
    get_key subroutine必须对传入hash进行判断,对不同类型的数据按照不同的方式组合,形成key,返回给使用者。这个key,必须保证其唯一性:
    比如:所有字母小写,一些数组在组合成key之前必须首先排序
    ? ? get_key函数
    sub get_key{
    my $hash = shift;
    return undef unless $hash && ref $hash eq "HASH";
    my $type = $hash->{type};
    my $key_name;
    if ($type eq 'sql') {
    my ($table_key,$column_key,$condition_key);
    $table_key=_get_key($hash->{object}->{table});
    $column_key=_get_key($hash->{object}->{column});
    $condition_key=_get_key($hash->{object}->{condition});
    $key_name = join('|',$type,$table_key,$column_key,$condition_key);
    #Currently the length limit of a key is set at 250 characters
    if (length($key_name)>250)
    {
    $key_name=substr(0,250,$key_name);
    }
    }
    elsif($type eq 'var')
    {
    $key_name = join('|',$type,$hash->{object});
    }
    return $key_name;
    }
    sub _get_key
    {
    my $hash=shift;
    return undef unless $hash && ref $hash eq "HASH";
    my ($t,$ret,$i);
    foreach $i (sort keys %$hash)
    {
    $i=~s/^s+|s+$//g;
    $hash->{$i}=~s/^s+|s+$//g;
    push(@$t,lc("$i=$hash->{$i}"));
    }
    $ret=join(':',sort { $a cmp $b } @$t);
    return $ret;
    }
    3) 制定需要应用memcached的规则
    ?经常访问的表user,user_details
    ?合理设定变量在memcached的生存周期
    ?将活跃用户的信息预先导入到memcached
    ?分别在多台机器上启动多个memcached服务
    ?编写脚本监控memcached服务是否活动
    4) User表的具体应用举例
    ? 在 select时候
    先查询memcahce里有没有,有的话,返回;否则从数据库select,在memcache里设置,返回。
    my $sql_hash = {
    type => 'sql',
    object => {
    table => {table1=>"user",},
    column => {column1=>"user_id",},
    condition => {email=>$user_id,},
    },
    };
    my $key=Zorpia::MemCache::get_key($sql_hash);
    my $user_id_by_email=Zorpia::MemCache::get($key);
    if(!$user_id_by_email)
    {
    my $sth;
    my $query ="select user_id from user where email=?";
    $sth = $dbh->prepare($query);
    $sth->execute($user_id);
    my $user1 = $sth->fetchrow_hashref();
    $user_id_by_email=$user1->{'user_id'};
    Zorpia::MemCache::set($key,$user_id_by_email,1800);
    }
    ?在 update,insert,delete时候
    先在数据库update,insert,delete,在memcache里设置,返回。
    &Zorpia::DB::data_entry_no_return($dbh,"user","COUNT(*)","$account_information_insert_statement user_id=$current_user_id", "user_id=$current_user_id");
    #add by kelly
    my $sql_hash = {
    type => 'sql',
    object => {
    table => {table1=>"user",},
    column => {column1=>"user_id",},
    condition => {user_id=>$current_user_id,},
    },
    };
    my $key=Zorpia::MemCache::get_key($sql_hash);
    my $query = "SELECT *, user_id AS id FROM user WHERE user_id=?";
    my $sth_memc = $dbh->prepare($query);
    $sth_memc->execute($current_user_id);
    my $user_memc = $sth_memc->fetchrow_hashref();
    &Zorpia::MemCache::set($key,$user_memc,21600);
    4、 memcached的应用展望
    使 用了memcached以后, 我发现以前做过的很多的项目都可以应用它提高效率,包括最近做的“大单追踪”, “数码搜索”等等。当然既然memcahced是分布式的缓存系统,那么它就是建立了一个分布式的平台, 我们可以用它来进行分布式的记数, 因为对于一个键值key我们可以设置它的数值以及有效期在参数中,另外还可以重新设置这个键值的数值。 所以我总结了一下目前可以应用到的地方:
    <1>.数据库检索结果的缓存,也就是说可以有机的和数据库结合起来应用,提高效率。
    这也是目前memcached用到的最多的地方,比如用于大型网站等。
    可以这样来实现:
    打开memcached服务器连接
    编写sql语句, 同时算出它的一个hash key值
    获取这个hash值的memcached保存数据(get)
    如果获取的这个hash值的数据存在。返回
    否则连接数据库查找
    把这个查找结果保存在memcached中(set),可以设置有效期
    返回查找结果
    <2>.分布式计算
    <3>.分布式共享数据
    总之,memcached的机制比较灵活,可以适用于一切需要分布式缓存数据的地方,随着memcached逐渐为人所知,必将在更多的分布式应用领域大放异彩。

    ---------------------------------------------------------------------------------------------------------------------------------------------

    Memcached是什么?
    Memcached是高性能的,分布式的内存对象缓存系统,用于在动态应用中减少数据库负载,提升访问速度。
    Memcached由Danga Interactive开发,用于提升LiveJournal.com访问速度的。LJ每秒动态页面访问量几千次,用户700万。Memcached将数据库负载大幅度降低,更好的分配资源,更快速访问。
    如何使用memcached-Server端?
    在服务端运行:
    # ./memcached -d -m 2048 -l 10.0.0.40 -p 11211
    这将会启动一个占用2G内存的进程,并打开11211端口用于接收请求。由于32位系统只能处理4G内存的寻址,所以在大于4G内存使用PAE的32位服务器上可以运行2-3个进程,并在不同端口进行监听。
    如何使用memcached-Client端?
    在应用端包含一个用于描述Client的Class后,就可以直接使用,非常简单。
    PHP Example:
    $options["servers"] = array("192.168.1.41:11211", "192.168.1.42:11212");
    $options["debug"] = false;
    $memc = new MemCachedClient($options);
    $myarr = array("one","two", 3);
    $memc->set("key_one", $myarr);
    $val = $memc->get("key_one");
    print $val[0]." "; // prints 'one‘
    print $val[1]." "; // prints 'two‘
    print $val[2]." "; // prints 3
    为什么不使用数据库做这些?
    暂且不考虑使用什么样的数据库(MS-SQL, Oracle, Postgres, MysQL-InnoDB, etc..), 实现事务(ACID,Atomicity, Consistency, Isolation, and Durability )需要大量开销,特别当使用到硬盘的时候,这就意味着查询可能会阻塞。当使用不包含事务的数据库(例如Mysql-MyISAM),上面的开销不存在,但 读线程又可能会被写线程阻塞。
    Memcached从不阻塞,速度非常快。
    为什么不使用共享内存?
    最初的缓存做法是在线程内对对象进行缓存,但这样进程间就无法共享缓存,命中率非常低,导致缓存效率极低。后来出现了共享内存的缓存,多个进程或者线程共享同一块缓存,但毕竟还是只能局限在一台机器上,多台机器做相同的缓存同样是一种资源的浪费,而且命中率也比较低。
    Memcached Server和Clients共同工作,实现跨服务器分布式的全局的缓存。并且可以与Web Server共同工作,Web Server对CPU要求高,对内存要求低,Memcached Server对CPU要求低,对内存要求高,所以可以搭配使用。
    Mysql 4.x的缓存怎么样?
    Mysql查询缓存不是很理想,因为以下几点:
    当指定的表发生更新后,查询缓存会被清空。在一个大负载的系统上这样的事情发生的非常频繁,导致查询缓存效率非常低,有的情况下甚至还不如不开,因为它对cache的管理还是会有开销。
    在32位机器上,Mysql对内存的操作还是被限制在4G以内,但memcached可以分布开,内存规模理论上不受限制。
    Mysql上的是查询缓存,而不是对象缓存,如果在查询后还需要大量其它操作,查询缓存就帮不上忙了。
    如果要缓存的数据不大,并且查询的不是非常频繁,这样的情况下可以用Mysql 查询缓存,不然的话memcached更好。
    数据库同步怎么样?
    这里的数据库同步是指的类似Mysql Master-Slave模式的靠日志同步实现数据库同步的机制。
    你可以分布读操作,但无法分布写操作,但写操作的同步需要消耗大量的资源,而且这个开销是随着slave服务器的增长而不断增长的。
    下一步是要对数据库进行水平切分,从而让不同的数据分布到不同的数据库服务器组上,从而实现分布的读写,这需要在应用中实现根据不同的数据连接不同的数据库。
    当这一模式工作后(我们也推荐这样做),更多的数据库导致更多的让人头疼的硬件错误。
    Memcached可以有效的降低对数据库的访问,让数据库用主要的精力来做不频繁的写操作,而这是数据库自己控制的,很少会自己阻塞 自己。
    Memcached快吗?
    非常快,它使用libevent,可以应付任意数量打开的连接(使用epoll,而非poll),使用非阻塞网络IO,分布式散列对象到不同的服务器,查询复杂度是O(1)。
    参考资料:
    Distributed Caching with Memcached | Linux Journal
    http://www.danga.com/
    http://www.linuxjournal.com/article/7451

  • 相关阅读:
    mvc性能优化
    wordpress分享到微信无缩略图的问题
    wordpress插件汉化包,和使用教程
    wordpress重力表单实时提醒功能教程(亲测可用)
    无法建立目录wp-content/uploads/xxxx/xx。有没有上级目录的写权限?解决办法
    font-face自定义字体使用方法
    图片在父元素里面水平垂直居中
    wordpress改不了固定连接的解决办法
    wordpress更换域名
    iframe添加点击事件
  • 原文地址:https://www.cnblogs.com/wayne173/p/3741797.html
Copyright © 2011-2022 走看看