如何File文件缓存和清理memcache缓存存同时使用

文件缓存和memcache内存缓存,我该选那个?因为公司需要,要我统计每个用户在网页上的点击状况,进了那些链接。公司网站访问量大概是100多万ip 800w pv 。在最开始使用了memcache来缓存用户的点击,当点击次数达到一定数量的时候,才写入数据库。 但是由于并发的原因,造成了多php进程同时写入数据库的问题,数据很多重复。现在我和同事有两种方案,第一种他的是,在memcache中建立多个数组,存放缓存数据,单个数组不能大于1M。然后用独立的一个php进程来做计划任务,定时取memcache中的数组,来执行入库。第二种我的,就是使用文件缓存,在memcache中点击次数满上限,就把数据存入文件中,清空memcache。然后同样用一个独立的进程来执行入库操作。我们该选哪种呢?
既然要入库,又何必用文件缓存呢?在memcache中点击次数满上限,就把数据执行入库操作,清空memcache
pengcq2008
memcache达到上限的时候,不要急着入库,应该重新创建一个 memcache 缓存。可以这样来理解:一共有两个 memcache 缓存,一个正在工作,另一个在后面等着。当前面的那个工作到一定限度了,那就扯下来,另一个上。典型的换班。。不知道这样能否解决你的问题
pengchuanzsj温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!&&|&&
主要从事JAVA中间件,大数据,分布式系统,高并发等相关底层技术。
LOFTER精选
网易考拉推荐
用微信&&“扫一扫”
将文章分享到朋友圈。
用易信&&“扫一扫”
将文章分享到朋友圈。
memcached的服务器客户端通信并不使用复杂的XML等格式,而使用简单的基于文本行的协议。 协议文档位于memcached的源代码内,也可以参考以下的URL。
libevent是个程序库,它将Linux的epoll、BSD类操作系统的kqueue等事件处理功能封装成统一的接口。即使对服务器的连接数增加,也能发挥O(1)的性能。 memcached使用这个libevent库,因此能在Linux、BSD、Solaris等操作系统上发挥其高性能。关于事件处理这里就不再详细介绍,可以参考Dan Kegel的The C10K Problem。 :
为了提高性能,memcached中保存的数据都存储在memcached内置的内存存储空间中。由于数据仅存在于内存中,因此重启memcached、重启操作系统会导致全部数据消失。另外,内容容量达到指定值之后,就基于LRU(Least Recently Used)算法自动删除不使用的缓存。 memcached本身是为缓存而设计的服务器,因此并没有过多考虑数据的永久性问题。
memcached尽管是“分布式”缓存服务器,但服务器端并没有分布式功能。各个memcached不会互相通信以共享信息。那么,怎样进行分布式呢?这完全取决于客户端的实现。
图2 memcached的分布式 安装memcached memcached的安装比较简单,这里稍加说明。 memcached支持许多平台。 l l l l 另外也能安装在Windows上。
memcached安装与一般应用程序相同,configure、make、make install就行了。
服务器端主要是安装memcache服务器端,目前的最新版本是 memcached-1.4.8 。 下载:/memcached/dist/memcached-1.2.2.tar.gz 另外,Memcache用到了libevent这个库用于Socket的处理,所以还需要安装libevent,libevent的最新版本是libevent-1.4。(如果你的系统已经安装了libevent,可以不用安装) 官网:http://www.monkey.org/~provos/libevent/ 下载: 1.分别把memcached和libevent下载回来,放到你指定的目录中,例如: /tmp 目录下: 2.先安装libevent: # tar zxvf libevent-1.2.tar.gz # cd libevent-1.2&& //进入linux系统中libevent所在目录 # ./configure --prefix=/usr/local/libevent # make # make install 3.测试libevent是否安装成功: # ls -al /usr/lib | grep libevent
lrwxrwxrwx 1 root root 21 11?? 12 17:38 libevent-1.2.so.1 -& libevent-1.2.so.1.0.3 -rwxr-xr-x 1 root root ?? 12 17:38 libevent-1.2.so.1.0.3 -rw-r–r– 1 root root ?? 12 17:38 libevent.a -rwxr-xr-x 1 root root 811 11?? 12 17:38 libevent.la lrwxrwxrwx 1 root root 21 11?? 12 17:38 libevent.so -& libevent-1.2.so.1.0.3 还不错,都安装上了。 4.安装memcached,同时需要安装中指定libevent的安装位置: # cd /tmp # tar zxvf memcached-1.2.0.tar.gz # cd memcached-1.2.0&&&&&& //进入linux系统中memcached所在目录 # ./configure –-prefix=/usr/local/memcached& --with-libevent=/usr/local/libevent # make # make install 如果中间出现报错,请仔细检查错误信息,按照错误信息来配置或者增加相应的库或者路径。 5.测试是否成功安装memcached: # ls -al /usr/local/mem* -rwxr-xr-x 1 root root ?? 12 17:39 /usr/local/bin/memcached -rwxr-xr-x 1 root root ?? 12 17:39 /usr/local/bin/memcached-debug
6.作软连接,否则运行memcached的时候将找不到libevent模块(注意你安装的libevent 的版本,以下为libevent安装目录中libevent-1.2.so.1) &&& # ln -s /usr/local/libevent/lib/libevent-1.2.so.1 /usr/lib 7.启动memcached (/usr/local/memcached为memcached的安装路径,到memcached的bin中启动memcached) # /usr/local/memcached/bin/memcached -d -m 256 -p 11211 -u root
启动参数注释如下: -p &num&& 指定服务TCP端口,默认为11211 -U &num&& &指定服务UDP端口& 默认11211表示打开,设置0表示关闭 -s &file& 指定unix domain socket的文件名,则关闭端口绑定 -a &mask& 文件属性屏蔽字。8进制,默认0700(和-s配合使用) -l &ip_addr&& 指定监听IP地址(默认对所有网卡IP都生效) -d &&run as a daemon 以精灵程序的方式运行 -r&& 设置coredump文件SIZE至上限 -u &username& 指定进程用户身份(只有以root运行时才有效,且root身份必须指定用户身份,memcached禁止以进程用户身份为root) -m &num&& 分配给memcached用作缓存的内存大小,单位为MB。默认64MB。 注意32位系统最大可管理的内存上限为3G,预留一些,测试分配2.8G是有效的。不要给memcached分配超过机器内存数,否则会自动使用swap分区,让性能大降,产生超时。(调优参数) -M& LRU算法开关。缓存满时不使用LRU算法替换旧的数据,返回错误 每个slab内的数据使用LRU,不是全局的。因此,在一些情况下,反而会影响命中率(例如多数KEY-VALUE大小近似,都保存在同一slab的情况下) -c &num&& &最大并发连接数。默认1024。 memcached使用libevent, 可以支持10K个连接。且memcached推荐客户端缓存连接(长连接)(调优参数) -k&& 是否调用mlockall()锁定内存页。 &&&& 注意:如果锁定了内存页,则若申请内存大小超过锁定值(可以通过ulimit -l查看)时就有可能失败(不建议使用。默认ulimit -l只有64KB) -v&&& 输出详细信息(在event轮询时输出错误或警告信息,以daemon方式运行无效) -vv&& 输出更详细的信息(包括输出客户端的命令及回应信息) -vvv &输出最详细的信息(包括输出内部的状态信息) -h &&打印版本、帮助信息及退出 -i&& 打印memcached及libevent的licence -P &file& 保存进程ID到指定文件。与-d配合使用 -f &factor&&& chunk size的增长因子(合理范围1.05~2,默认:1.25)(1.2版本之前默认是2) (调优参数) -n &bytes& &每个ITEM保存数据占用的最小空间。最小空间大小=KEY的长度+value的长度+flags的长度(默认为48字节) 而每个ITEM的实际占用空间为 ITEM保存占用数据保存的最小空间 + ITEM结构占用的空间 = 48 + 32 = 80字节。因此chunk size的默认初始值为80字节(调优参数) -L&&& 尝试使用大容量内存页(如果可能的话)。增加内存页容量可以减少虚存-物理内存映射页表缓冲命中失败(TLB-MISSED)的次数, 并提高性能。但memcached会在启动的时候立即向OS申请-m参数指定的最大缓存块。(调优参数) -D &char&& 指定统计报告时ID同KEY之间的分隔符。默认的分隔符为“:”。 如果指定了此参数,统计采集功能就会自动启动;否则,可以通过发送“stats detail on”命令启动统计采集功能。 -t &num&& 默认会创建4个工作线程,主线程用于监听客户建立的连接请求、accpet请求,然后通过管道通知子线程,由子线程处理读写请求。 memcached的多线程主要是通过实例化多个libevent实现的,分别是一个主线程和n个工作(workers)线程,无论是主线程还是workers线程全部通过libevent 管理网络事件, 实际上每个线程都是一个单独的libevent实例。建议不要超过系统CPU的个数。(调优参数) -R& 每次事件触发响应新连接的最大数目。设置此限制是防止其他I/O事件“挨饿”,得不到响应。每个工作线程都单独建立了libevent事件触发。(调优参数,一般不需要调整) -C&&& Disable use of CAS 关闭'CAS'指令。意思是说如果这个值我最后一次取的没有被修改的话才存储这个值,比如我先获取一个key为”update_time”的值,然后有其他进程修改了这个值,此时我再调用cas设置这个值时则会返回一个EXSISTS的错误表示修改失败。默认支持cas指令。则每次value的修改,都会记录一个CAS序列号(CAS_UNIQUE)。gets指令会返回CAS_UNIQUE。 -b& &指定监听队列长度(listen()的参数)。默认为1024。(调优参数。不需要调整,内核对监听队列长度有个上限) -B&&& 指定绑定的memcached协议。包括:ascii: 文本协议;binary: 二进制协议;auto: 自动检测(默认选项) -I &&&改变slab page的容量大小,以调整ITEM容量的最大值,默认为1MB。设置参数:&number&[k|K|m|M]不能少于1024bytes(即1K),不能大于128MB。memcached不推荐大于1MB,大于1MB增加了最低的内存要求,并会减少记忆效率。调优参数)注:低版本memcached 如memcached-1.2.6不支持该参数,1.4以上可以;测试时,我分配了2M的Page,但是实际上缓存的数据大小仍不能大于1M,其他资料说memcached缓存的item不能大于1M -S&& Turn on Sasl authentication &&&& 启动SSL认证。需要在编译支持SSL。使用SSL认证时,只能使用二进制协议,不能使用文本协议。
Java使用Memcached的例子 许多语言都实现了连接memcached的客户端,其中以Perl、PHP为主。仅仅memcached网站上列出的语言就有 lPerl
lLua lJava 等等。
解压,获取jar包。建立一个基本的Java工程吧。引入jar包。如图示:
java.io.FileW
java.util.ArrayL
java.util.D
java.util.L t java.util.M
com.danga.MemCached.MemCachedC
com.danga.MemCached.SockIOP
class MemCachedManager { //
protected static MemCachedClient mcc = new MemCachedClient();
protected static MemCachedManager memCachedManager = new MemCachedManager();&&
static {&&
String[] servers = { "192.168.1.107:11211","127.0.0.1:11211" };&&
Integer[] weights = { 3 };
SockIOPool pool = SockIOPool.getInstance();&&
pool.setServers(servers);&&
pool.setWeights(weights);&&
pool.setInitConn(5);&&
pool.setMinConn(5);&&
pool.setMaxConn(250); //设置最大空闲时间为6小时 pool.setMaxIdle(1000 * 60 * 60 * 6);&&
pool.setMaintSleep(30);&&
//&Tcp的规则就是在发送一个包之前,本地机器会等待远程主机对上一次发送的包的确认信息到来;这个方法就可以关闭套接字的缓存,以至这个包准备好了就发; pool.setNagle(false);&&
//连接建立后对超时的控制 &&&&&& pool.setSocketTO(3000);
//连接建立时对超时的控制 pool.setSocketConnectTO(0);&&
//&initialize&the&connection&pool,初始化一些值并与MemcachedServer段建立连接 pool.initialize();&&
mcc.setCompressEnable(true);&&
mcc.setCompressThreshold(64 * 1024);&&
protected MemCachedManager() {&&
* @return&
public static MemCachedManager getInstance() {&&
return memCachedM&&
* @param key&
* @param value&
* @return&
public boolean add(String key, Object value) {&&
return mcc.add(key, value);&&
public boolean add(String key, Object value, Date expiry) {&&
return mcc.add(key, value, expiry);&&
&public boolean set(String key,Object value){ &&&&&& return mcc.add(key, value); } public boolean replace(String key, Object value) {&&
return mcc.replace(key, value);&&
public boolean replace(String key, Object value, Date expiry) {&&
return mcc.replace(key, value, expiry);&&
* @param key * @param value * @param expiry * @return */ public boolean delete(String key, Date expiry){ &&&&&& return mcc.delete(key, expiry); }
&&* @param key&
* @return&
public Object get(String key) { return mcc.get(key); } &public Map&String,Object& get(String[] keys){ &&&&&& return mcc.getMulti(keys); }
public static void main(String[] args) {&&
&&&&&&try { &&&&&& MemCachedManager cache = MemCachedManager.getInstance(); List&String& list = new ArrayList&String&();//List &// File file = new File("E:\\my.txt"); if (!file.exists()) { file.createNewFile(); }else{ file.delete(); } // FileWriter fw = new FileWriter(file);&
// for (int i = 0; i & 40000; i++) { &&&&&& &String s = "abcderghijklmn"+i; &&&&&& fw.write(s,0,s.length()); // &&&&&&&&&&&&&&&&&&&& list.add(s);& // &&&&&&&&&&&&& } fw.flush();
cache.add("hello", 23445,new Date(20000)); cache.add("list", list,new Date(20000));
System.out.println("get value : " + cache.get("hello")); List lst = (List)cache.get("list"); System.out.println("get Size:" + lst.size());
} catch (Exception e) { e.printStackTrace(); } }&&
向memcached保存数据的方法有 1.add 2.replace 3.
add(String key, Object value) {&&
return mcc.add(key, value);&&
add(String key, Object value, Date expiry) {&&
return mcc.add(key, value, expiry);&&
set(String key,Object value){ return mcc.add(key, value);
replace(String key, Object value) {&&
return mcc.replace(key, value);&&
replace(String key, Object value, Date expiry) {&&
return mcc.replace(key, value, expiry);&&
& 向memcached保存数据时可以指定期限(秒)。不指定期限时,memcached按照LRU算法保存数据。这三个方法的区别如下:
Object get(String key) { return mcc.get(key);
Map&String,Object& get(String[] keys){ & return mcc.getMulti(keys);
& 一次取得多条数据时使用get_multi。get_multi可以非同步地同时取得多个键值,其速度要比循环调用get快数十倍。
删除数据使用delete方法,不过它有个独特的功能。 public boolean delete(String key, Date expiry){ &&&&&& return mcc.delete(key, expiry); }
删除第一个参数指定的键的数据。第二个参数指定一个时间值,在指定的时间内可以禁止使用同样的键保存新数据。此功能可以用于防止缓存数据的不完整。但是要注意,set函数忽视该阻塞,照常保存数据
阅读(7647)|
用微信&&“扫一扫”
将文章分享到朋友圈。
用易信&&“扫一扫”
将文章分享到朋友圈。
历史上的今天
在LOFTER的更多文章
loftPermalink:'',
id:'fks_',
blogTitle:'Memcached缓存技术',
blogAbstract:'文章来源:http://dev.jizhiinfo.net/?post=36Memcached介绍
{elseif x.moveFrom=='iphone'}
{elseif x.moveFrom=='android'}
{elseif x.moveFrom=='mobile'}
${a.selfIntro|escape}{if great260}${suplement}{/if}
{list a as x}
推荐过这篇日志的人:
{list a as x}
{if !!b&&b.length>0}
他们还推荐了:
{list b as y}
转载记录:
{list d as x}
{list a as x}
{list a as x}
{list a as x}
{list a as x}
{if x_index>4}{break}{/if}
${fn2(x.publishTime,'yyyy-MM-dd HH:mm:ss')}
{list a as x}
{if !!(blogDetail.preBlogPermalink)}
{if !!(blogDetail.nextBlogPermalink)}
{list a as x}
{if defined('newslist')&&newslist.length>0}
{list newslist as x}
{if x_index>7}{break}{/if}
{list a as x}
{var first_option =}
{list x.voteDetailList as voteToOption}
{if voteToOption==1}
{if first_option==false},{/if}&&“${b[voteToOption_index]}”&&
{if (x.role!="-1") },“我是${c[x.role]}”&&{/if}
&&&&&&&&${fn1(x.voteTime)}
{if x.userName==''}{/if}
网易公司版权所有&&
{list x.l as y}
{if defined('wl')}
{list wl as x}{/list}基本问题1、memcached的基本设置&1)启动Memcache的服务器端&# /usr/local/bin/memcached -d -m 10 -u root -l 192.168.0.200 -p 12000 -c 256 -P /tmp/memcached.pid-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,2)如果要结束Memcache进程,执行:# kill `cat /tmp/memcached.pid`哈希算法&将&任意长度的二进制值映射为固定长度的较小二进制值,这个小的二进制值称为哈希值。哈希值是一段数据唯一且极其紧凑的数值表示形式。如果散列一段明文而且哪怕只更改该段落的一个字母,随后的哈希都将产生不同的值。要找到散列为同一个值的两个不同的输入,在计算上是不可能的。2、一致性Hash算法的目的有两点:一是节点变动后其他节点受影响尽可能小;二是节点变动后数据重新分配尽可能均衡 。3、为什么要运行 memcached ?如果网站的高流量很大并且大多数的访问会造成数据库高负荷的状况下,使用 memcached 能够减轻数据库的压力。4、适用memcached的业务场景?1)如果网站包含了访问量很大的动态网页,因而数据库的负载将会很高。由于大部分数据库请求都是读操作,那么memcached可以显著地减小数据库负载。2)如果数据库服务器的负载比较低但CPU使用率很高,这时可以缓存计算好的结果( computed objects )和渲染后的网页模板(enderred templates)。3)利用memcached可以缓存&session数据&、临时数据以减少对他们的数据库写操作。4)缓存一些很小但是被频繁访问的文件。5)缓存Web 'services'(非IBM宣扬的Web Services,译者注)或RSS feeds的结果.。5、不适用memcached的业务场景?1)缓存对象的大小大于1MBMemcached本身就不是为了处理庞大的多媒体(large media)和巨大的二进制块(streaming huge blobs)而设计的。2)key的长度大于250字符3)虚拟主机不让运行memcached服务&&&& 如果应用本身托管在低端的虚拟私有服务器上,像vmware, xen这类虚拟化技术并不适合运行memcached。Memcached需要接管和控制大块的内存,如果memcached管理的内存被OS或 hypervisor交换出去,memcached的性能将大打折扣。4)应用运行在不安全的环境中Memcached为提供任何安全策略,仅仅通过telnet就可以访问到memcached。如果应用运行在共享的系统上,需要着重考虑安全问题。5)业务本身需要的是持久化数据或者说需要的应该是database6、能够遍历memcached中所有的item吗?不能,这个操作的速度相对缓慢且阻塞其他的操作(这里的缓慢时相比memcached其他的命令)。memcached所有非调试(non-debug)命令,例如add, set, get, fulsh等无论memcached中存储了多少数据,它们的执行都只消耗常量时间。任何遍历所有item的命令执行所消耗的时间,将随着memcached中数据量的增加而增加。当其他命令因为等待(遍历所有item的命令执行完毕)而不能得到执行,因而阻塞将发生。集群的相关问题7、memcached是怎么工作的?Memcached的高性能源于两阶段哈希(two-stage hash)结构。Memcached就像一个巨大的、存储了很多&key,value&对的哈希表。通过key,可以存储或查询任意的数据。 客户端可以把数据存储在多台memcached上。当查询数据时,客户端首先参考节点列表计算出key的哈希值(阶段一哈希),进而选中一个节点;客户端将请求发送给选中的节点,然后memcached节点通过一个内部的哈希算法(阶段二哈希),查找真正的数据(item)并返回给客户端。从实现的角度看,memcached是一个非阻塞的、基于事件的服务器程序。8、memcached最大的优势是什么?Memcached最大的好处就是它带来了极佳的水平可扩展性,特别是在一个巨大的系统中。由于客户端自己做了一次哈希,那么我们很容易增加大量memcached到集群中。memcached之间没有相互通信,因此不会增加 memcached的负载;没有多播协议,不会网络通信量爆炸(implode)。9、memcached和MySQL的query cache相比,有什么优缺点?缺点:1)相比MySQL的query cache,把memcached引入应用中需要不少的工作量。MySQL的query cache,可以自动地缓存SQL查询的结果,被缓存的SQL查询可以被反复、快速的执行。优点:1)当修改表时,MySQL的query cache会立刻被刷新(flush)。当写操作很频繁时,MySQL的query cache会经常让所有缓存数据都失效。2)在多核CPU上,MySQL的query cache会遇到扩展问题(scalability issues)。在多核CPU上,query cache会增加一个全局锁(global lock), 由于需要刷新更多的缓存数据,速度会变得更慢。3)在MySQL的query cache中,是不能存储任意的数据的(只能是SQL查询结果)。利用memcached,我们可以搭建出各种高效的缓存。比如,可以执行多个独立的查询,构建出一个用户对象(user object),然后将用户对象缓存到memcached中。而query cache是SQL语句级别的,不可能做到这一点。在小的网站中,query cache会有所帮助,但随着网站规模的增加,query cache的弊将大于利。4)query cache能够利用的内存容量受到MySQL服务器空闲内存空间的限制。给数据库服务器增加更多的内存来缓存数据,固然是很好的。但是,有了memcached,只要您有空闲的内存,都可以用来增加memcached集群的规模,然后您就可以缓存更多的数据。10、memcached和服务器的local cache(比如PHP的APC、mmap文件等)相比,有什么优缺点?1)首先,local cache面临着严重的内存限制,能够利用的内存容量受到(单台)服务器空闲内存空间的限制。2)local cache有一点比memcached和query cache都要好,那就是它不但可以存储任意的数据,而且没有网络存取的延迟。因此,local cache的数据查询更快。考虑把highlycommon的数据放在local cache中吧。如果每个页面都需要加载一些数量较少的数据,可以考虑把它们放在local cached。3)local cache缺少集体失效(group invalidation)的特性。在memcached集群中,删除或更新一个key会让所有的观察者觉察到。但是在local cache中, 我们只能通知所有的服务器刷新cache(很慢,不具扩展性)或者仅仅依赖缓存超时失效机制。11、memcached的cache机制是怎样的?Memcached主要的cache机制是LRU(最近最少用)算法+超时失效。当您存数据到memcached中,可以指定该数据在缓存中可以呆多久Which is forever, or some time in thefuture。如果memcached的内存不够用了,过期的slabs会优先被替换,接着就轮到最老的未被使用的slabs。12、memcached如何实现冗余机制?不实现!Memcached应该是应用的缓存层,从设计本身来京就不带有任何冗余机制。如果一个memcached节点失去了所有数据,应该可以从数据源(比如数据库)再次获取到数据。应用系统应该可以容忍节点的失效。如果担心节点失效会大大加重数据库的负担,那么可以采取一些办法。比如您可以&增加更多的节点&(来减少丢失一个节点的影响),热备节点&(在其他节点down了的时候接管IP)等等。13、memcached如何处理容错的?在节点失效的情况下,集群没有必要做任何容错处理。如果发生了节点失效,应对的措施完全取决于用户。节点失效时,下面列出几种方案供您选择:1)忽略它! 在失效节点被恢复或替换之前,还有很多其他节点可以应对节点失效带来的影响。2)把失效的节点从节点列表中移除。做这个操作千万要小心!在默认情况下(余数式哈希算法),客户端添加或移除节点,会导致所有的缓存数据不可用!因为哈希参照的节点列表变化了,大部分key会因为哈希值的改变而被映射到(与原来)不同的节点上。3)启动热备节点,接管失效节点所占用的IP。这样可以防止哈希紊乱(hashing chaos)。4)如果希望添加和移除节点,而不影响原先的哈希结果,可以使用一致性哈希算法(consistent hashing)。5)两次哈希(reshing)。当客户端存取数据时,如果发现一个节点down了,就再做一次哈希(哈希算法与前一次不同),重新选择另一个节点(需要注意的时,客户端并没有把down的节点从节点列表中移除,下次还是有可能先哈希到它)。如果某个节点时好时坏,两次哈希的方法就有风险了,好的节点和坏的节点上都可能存在脏数据(stale data)。14、如何将memcached中item批量导入导出?不应该这样做!Memcached是一个非阻塞的服务器。任何可能导致memcached暂停或瞬时拒绝服务的操作都应该值得深思熟虑。向memcached中批量导入数据往往不是您真正想要的!想象看,如果缓存数据在导出导入之间发生了变化,您就需要处理脏数据了;如果缓存数据在导出导入之间过期了,您又怎么处理这些数据呢?因此,批量导出导入数据并不像想象中的那么有用。不过在一个场景倒是很有用。如果您有大量的从不变化 的数据,并且希望缓存很快热(warm)起来,批量导入缓存数据是很有帮助的。15、但是我确实需要把memcached中的item批量导出导入,怎么办??如果需要批量导出和导入,最可能的原因一般是重新生成缓存数据需要消耗很长的时间或者数据库坏了让您饱受痛苦。如果一个memcached节点down了让您很痛苦,那么必须对数据库做一些优化工作。比如处理&惊群&问题( memcached节点都失效了,反复的查询让数据库不堪重负)或者存在优化不好的查询等。Memcached 并不是逃避优化查询的借口和方案。这里给出一些提示:使用MogileFS(或者CouchDB等类似的软件)在存储item,把item计算出来并dump到磁盘上。MogileFS可以很方便地覆写item,并提供快速地访问。甚至可以把MogileFS中的item缓存在memcached中,这样可以加快读取速度。 MogileFS+Memcached的组合可以加快缓存不命中时的响应速度,提高网站的可用性。重新使用MySQL。MySQL的 InnoDB主键查询速度非常快。如果大部分缓存数据都可以放到VARCHAR字段中,那么主键查询的性能将更好。从memcached中按key查询几乎等价于MySQL的主键查询:将key 哈希到64-bit的整数,然后将数据存储到MySQL中。您可以把原始(不做哈希)的key存储都普通的字段中,然后建立二级索引来加快查询...key被动地失效,批量删除失效的key,等等。16、memcached是如何做身份验证的?没有身份认证机制!memcached是运行在应用下层的软件(身份验证应该是应用上层的职责)。memcached的客户端和服务器端之所以是轻量级的,部分原因就是完全没有实现身份验证机制。这样,memcached可以很快地创建新连接,服务器端也无需任何配置。如果您希望限制访问,您可以使用防火墙,或者让memcached监听unix domain socket。17、memcached的多线程是什么?如何使用它们?线程就是定律(threads rule)!在Steven Grimm和Facebook的努力下,memcached 1.2及更高版本拥有了多线程模式。多线程模式允许memcached能够充分利用多个CPU,并在CPU之间共享所有的缓存数据。memcached使用一种简单的锁机制来保证数据更新操作的互斥。相比在同一个物理机器上运行多个memcached实例,这种方式能够更有效地处理multigets。如果系统的负载并不重,那么不需要启用多线程工作模式。如果您在运行一个拥有大规模硬件的、庞大的网站,将体验到看到多线程的好处。更多信息请参见:简单地总结一下:命令解析(memcached在这里花了大部分时间)可以运行在多线程模式下。memcached内部对数据的操作是基于很多全局锁的(因此这部分工作不是多线程的)。未来对多线程模式的改进,将移除大量的全局锁,提高memcached在负载极高的场景下的性能。18、memcached能接受的key的最大长度是多少?memcached能接受的key的最大长度是250个字符。需要注意的是,250是memcached服务器端内部的限制。如果使用的Memcached客户端支持&key的前缀&或类似特性,那么key(前缀+原始key)的最大长度是可以超过250个字符的。推荐使用较短的key,这样可以节省内存和带宽。19、memcached对item的过期时间有什么限制?item对象的过期时间最长可以达到30天。memcached把传入的过期时间(时间段)解释成时间点后,一旦到了这个时间点,memcached就把item置为失效状态,这是一个简单但obscure的机制。20、memcached最大能存储多大的单个item?memcached最大能存储1MB的单个item。如果需要被缓存的数据大于1MB,可以考虑在客户端压缩或拆分到多个key中。21、为什么单个item的大小被限制在1M byte之内?简单的回答:因为内存分配器的算法就是这样的。详细的回答:1)Memcached的内存存储引擎,使用slabs来管理内存。内存被分成大小不等的slabs chunks(先分成大小相等的slabs,然后每个slab被分成大小相等chunks,不同slab的chunk大小是不相等的)。chunk的大小依次从一个最小数开始,按某个因子增长,直到达到最大的可能值。如果最小值为400B,最大值是1MB,因子是1.20,各个slab的chunk的大小依次是:slab1 - 400B;slab2 - 480B;slab3 - 576B ...slab中chunk越大,它和前面的slab之间的间隙就越大。因此,最大值越大,内存利用率越低。Memcached必须为每个slab预先分配内存,因此如果设置了较小的因子和较大的最大值,会需要为Memcached提供更多的内存。2)不要尝试向memcached中存取很大的数据,例如把巨大的网页放到mencached中。因为将大数据load和unpack到内存中需要花费很长的时间,从而导致系统的性能反而不好。如果确实需要存储大于1MB的数据,可以修改slabs.c:POWER_BLOCK的值,然后重新编译memcached;或者使用低效的malloc/free。另外,可以使用数据库、MogileFS等方案代替Memcached系统。22、可以在不同的memcached节点上使用大小不等的缓存空间吗?如果这么做之后,memcached能够更有效地使用内存吗?Memcache客户端仅根据哈希算法来决定将某个key存储在哪个节点上,而不考虑节点的内存大小。因此,可以在不同的节点上使用大小不等的内存作为缓存空间。但是一般可以这样做:拥有较多内存的节点上可以运行多个memcached实例,每个实例使用的内存跟其他节点上的实例相同。23、什么是二进制协议,是否需要关注?二进制协议尝试为端提供一个更有效的、可靠的协议,减少客户端/服务器端因处理协议而产生的CPU时间。根据Facebook的测试,解析ASCII协议是memcached中消耗CPU时间最多的环节。24、memcached的内存分配器是如何工作的?为什么不适用malloc/free!?为何要使用slabs?实际上,这是一个编译时选项。默认会使用内部的slab分配器,而且确实应该使用内建的slab分配器。最早的时候,memcached只使用malloc/free来管理内存。然而,这种方式不能与OS的内存管理以前很好地工作。反复地malloc/free造成了内存碎片,OS最终花费大量的时间去查找连续的内存块来满足malloc的请求,而不是运行memcached进程。slab分配器就是为了解决这个问题而生的。内存被分配并划分成chunks,一直被重复使用。因为内存被划分成大小不等的slabs,如果item的大小与被选择存放它的slab不是很合适的话,就会浪费一些内存。25、memcached是原子的吗?所有的被发送到memcached的单个命令是完全原子的。如果您针对同一份数据同时发送了一个set命令和一个get命令,它们不会影响对方。它们将被串行化、先后执行。即使在多线程模式,所有的命令都是原子的。然是,命令序列不是原子的。如果首先通过get命令获取了一个item,修改了它,然后再把它set回memcached,系统不保证这个item没有被其他进程(process,未必是操作系统中的进程)操作过。memcached 1.2.5以及更高版本,提供了gets和cas命令,它们可以解决上面的问题。如果使用gets命令查询某个key的item,memcached会返回该item当前值的唯一标识。如果客户端程序覆写了这个item并想把它写回到memcached中,可以通过cas命令把那个唯一标识一起发送给memcached。如果该item存放在memcached中的唯一标识与您提供的一致,写操作将会成功。如果另一个进程在这期间也修改了这个item,那么该item存放在memcached中的唯一标识将会改变,写操作就会失败。性能和客户端库方面的问题26、memcached没有我的database快,为什么?在一对一比较中,memcached可能没有SQL查询快。但是,这不是memcached的设计目标。Memcached的目标是可伸缩性。当连接和请求增加的时候,memcached的性能将比大多数数据库查询好。可以先在高负载的环境(并发的连接和请求)中测试您的代码,然后再决定memcached是否适合您。27、使用不同的客户端库,可以访问到memcached中相同的数据吗?从技术上说,是可以的。但是可能会遇到下面三个问题:1)不同的库采用不同的方式序列化数据。举个例子,perl的Cache::Memcached使用Storable来序列化结构复杂的数据(比如hash references, objects, 等)。其他语言的客户端库很可能不能读取这种格式的数据。如果您要存储复杂的数据并且想被多种客户端库读取,那么您应该以简单的string格式来存储,并且这种格式可以被JSON、XML等外部库解析。2)从某个客户端来的数据被压缩了,从另一个客户端来的却没被压缩。3)各个客户端库可能使用不同的哈希算法(阶段一哈希)。在连接到多个memcached服务器端的情况下,客户端库根据自身实现的哈希算法把key映射到某台memcached上。正是因为不同的客户端库使用不同的哈希算法,所以被Perl客户端库映射到memcached A的key,可能又会被Python客户端库映射到memcached B,等等。Perl客户端库还允许为每台memcached指定不同的权重(weight),这也是导致这个问题的一个因素。28、什么是一致性哈希的客户端?客户端可以通过&前缀&来给key设置一个域(命名空间)。例如,在一个共享主机的环境中,可以将客户姓名作为&前缀&,为key创建一个特定的域。在存储数据的时候,&前缀&可以用在key上,但是不应该参与哈希计算。目前,memcached自己还没有实现针对复杂结构数据的序列化方法,JSON则是一种被广泛使用的对象序列化格式。哈希 / 键分布29、什么时候失效的数据项会从缓存中删除?memcached 使用懒失效,当客户端请求数据项时, memcached 在返回数据前会检查失效时间来确定数据项是否已经失效。同样地,当添加一个新的数据项时,如果缓存已经满了, memcached 就会先替换失效的数据项,然后才是缓存中最少使用的数据项。命名空间30、memcached 不支持命名空间。以下提供几种模仿命名空间的方式:1)用键的前缀模仿命名空间:在真实的键之前加入有意义的前缀。2)用命名空间删除数据项:尽管 memcached 不支持使用任何类型的通配符或命名空间来完成删除操作,但是可以采用一些技巧来替代:在 PHP 中使用一个叫 foo 的命名空间:$ns_key = $memcache-&get(&foo_namespace_key&);// if not set, initialize itif($ns_key=false) $memcache-&set(&foo_namespace_key&, rand(1, 10000));$my_key = &foo_&.$ns_key.&_12345&;清除命名空间:$memcache-&increment(&foo_namespace_key&);应用设计31、在设计应用时,可以通过Memcached缓存那些内容?1)缓存简单的查询结果:&查询缓存存储了给定查询语句对应的整个结果集,最合适缓存那些&经常被用到,但不会改变的 SQL 语句对查询到的结果集,比如载入特定的过滤内容。$key = md5('SELECT * FROM rest_of_sql_statement_goes_here');if ($memcache-&get($key)) {&&&&& ` return $memcache-&get($key);`}else {&&& ` // Run the query and transform the result data into your final dataset form`&&& ` $result = $query_results_mangled_into_most_likely_an_array`&&&& ` $memcache-&set($key, $result, TRUE, 86400); // Store the result of the query for a day`&&& ` return $`}记住,如果查询语句对应的结果集改变,该结果集不会展现出来。这种方法不总是有用,但它确实让工作变得比较快。2)缓存简单的基于行的查询结果:&基于行的缓存会检查缓存数据key的列表,那些在缓存中的行可以直接被取出,不在缓存中的行将会从数据库中取出并以唯一的键为标识缓存起来,最后加入到最终的数据集中返回。随着时间的推移,大多数数据都会被缓存,这也意味着相比与数据库,查询语句会更多地从 memcached 中得到数据行。如果数据是相当静态的,我们可以设置一个较长的缓存时间。基于行的缓存模式对下面这种搜索情况特别有用&:数据集本身很大或是数据集是从多张表中得到,而数据集取决于查询的输入参数但是查询的结果集之间的有重复部分。比如,如果你有用户 A , B , C , D , E 的数据集。你去点击一张显示用户 A , B , E 信息的页面。首先, memcached 得到 3 个不同的键,每个对应一个用户去缓存中查找,全部未命中。然后就到数据库中用 SQL 查询得到 3 个用户的数据行,并缓存他们。现在,你又去点击另一张显示显示 C , D , E 信息的页面。当你去查找 memcached 时, C , D 的数据并没有被命中,但我们命中了 E 的数据。然后从数据库得到 C , D 的行数据,缓存在 memcached 中。至此以后,无论这些用户信息怎样地排列组合,任何关于 A , B , C , D , E 信息的页面都可以从 memcached 得到数据了。3)缓存的不只是 SQL 数据,可以缓存最终完成的部分显示页面,以节省CPU计算时间例如正在制作一张显示用户信息的页面,你可能得到一段关于用户的信息(姓名,生日,家庭住址,简介),然后你可能会将 XML 格式的简介信息转化为 HTML 格式或做其他的一些工作。相比单独存储这些属性,你可能更愿意&存储经过渲染的数据块&。那时你就可以简单地取出被预处理后的 HTML 直接填充在页面中,这样节省了宝贵的 CPU 时间。32、使用分层的缓存memcached 可以高速处理大量的缓存数据,但是还是要根据系统的情况考虑维护多层的缓存结构。例如除了memcached缓存之外,还可以通过本地缓存(如ehcache、oscache等)建立起多级缓存。例如,可以采用本地缓存缓存一些基本数据,例如少量但访问频繁的数据(如产品分类,连接信息,服务器状态变量,应用配置变量等),缓存这些数据并让他们尽可能的接近处理器是有意义的 , 这样可以帮助减少生成页面的时间,并且在 memcached 失效的情况下可以增加可靠性。33、当数据更新时需要更新缓存用户编辑了自己的信息,当保存信息到数据库时,需要更新缓存中的数据或是简单地删除老的数据。如果马上更新数据,要防止从数据库读取那些刚刚更新过的数据。当用户习惯性地重新载入自己的用户信息来确认是否修改成功时,数据将从缓存中直接取出,这时他们获得了最新的数据。34、模拟带锁的添加命令如果你实在需要锁,你可以通过“添加”命令模仿锁的功能。尽管在未命中的情况下它不是那么有用,但如果你用它缓存平常的数据(应用服务器池的元数据)那还是有用的。比如,你要更新键 A 。1. 添加一个 &lock:A& 的键,这个键有一个持续几秒的过期时间(足够长以使你能完成计算和更新,也不要很长,因为如果锁进程挂了,这个键不会立即释放)2. 如果添加操作成功了,你就拥有了锁:从缓存获取键 A 的数据;利用客户端程序更改数据;更新缓存键 A 的数据;删除键 &lock:A& 。如果你不需要立即再次更新,就让它存活直到失效。3. 如果添加操作失败,说明有人获取了锁。这时让应用做些合适的事,比如返回老数据,等待后重试,或是其他的。以上这些操作类似 MySQL 将 GET_LOCK 的 timeout 值设置成 0 。没有办法在 memcached 中通过互斥锁模拟 GET_LOCK() 的 timeout 操作。35、预热你的缓存如果你有一个很高访问率的站点,并且你正想加入故障恢复功能或是其他全新的功能,你最终可能会碰到空缓存的问题。一开始缓存是空的,然后一大群人点击你的站点,在填充缓存的过程中,你的数据库可能会承受不住压力。为了解决这一问题,你可以试试任何可行的方法来 & 温暖 & 你的Memcached。方法:可以写一些脚本来缓存通用的页面;也可以写一个命令行工具来填充缓存。你可以在高峰时刻在缓存里填充一些内容。Memcached最佳实践二&1、memcached的优势是什么?1) 分布式& 。2)相对应用服务器的内存而言,可以进行单点访问。3)性能强。2、不太适合采用Memcached缓存的情况?1) 如果Value特别大,不太适合。默认编译下Memcache只支持1M的Value。事实上由于存在序列化反序列化的过程,所以从实践的角度来说也不建议把非常大的数据保存在Memcache中。Memcache适合面向输出的内容缓存,而不是面向处理的数据缓存,也就是不太适合把大块数据放进去拿出来 处理之后再放回去,而是适合拿出来就直接给输出了或是拿出来不需要处理直接使用。2) 如果不允许过期,不太适合。Memcache在默认情况下最大30天过期,而且在内存达到使用限制后它也会回收最近最少使用的数据。3、清除部分缓存数据的过程?可采用命名空间(在Memcache的语境下可采用Key前缀的办法代替,例如设置Key为“子系统名称+实体名+实体的ID”)的办法来实现,用以区分不同类型的缓存内容,以便在需要的时候可以清除某一类缓存。4、Value的组织问题?主要涉及被缓存的数据的颗粒度,比如要保存一个数据表,是一行数据保存在一个键值还是统一保存为一个键值。如果数据保存的粒度很小的话最好是在获取的时候能够批量获取,在保存的时候也能够批量保存,也就是说对于跨网络的调用次数越少越好。5、memcache中Key的约定和命名规范?第一种:一般是项目名称+字符常量(实体名或表名等)+返回PO的id(或者唯一标示都可以)。这种方法代码一般会嵌入到Service中,从而破坏service的业务逻辑,耦合性较高。可以考虑在action层与service层中间加入一层,来降低耦合性。第二种:可以用spring aop来拦截你要缓存的service,唯一key可以通过类名+方法名+参数名等来组成;这种方法适用于分模块开发 ,因为调用的都是同一个类中的方法,但是拦截器也会在一定程度上影响性能。但是可以提高开发的效率,还有就是不会破坏service层的业务逻辑。第三种:用sql语句+id(或者查询条件)。这种方法不是很好。

我要回帖

更多关于 清理memcache缓存 的文章

 

随机推荐