Memcached
Memcached简介
Memcached是一款开源的、高性能的、分布式的内存对象缓存系统
Memcached能干什么 最主要的功能就是:在内存中缓存数据,以减轻数据库负载。
它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提高动
态、数据库驱动网站的速度。
Memcached特点
在内存中以键/值对存储,性能好 协议简单(基于文本行),功能强大 基于libevent的事件处理,无阻塞通信,对内存读写速度非常快 基于客户端的分布式,服务端多个Memcached之间不互相通信 服务端以守护进程运行,客户端可以用任何语言来编写
Memcached的基本原理
Memcached基本的工作原理 Memcached是以守候程序的方式运行于一个或者多个服务器,随时等待客户
端的链接,通过启动memcached服务器端,配置相应的监听IP、端口内存大小等 参数,客户端可通过指定的服务器端IP,将数据以key-value的方式存储
Memcached的两阶段哈希 客户端存取数据时,首先参考节点列表计算出key的哈希值(阶段一哈希),进而选中一个节点;客户端将请求发送给选中的节点,然后Memcached节 点通过一个内部的哈希算法(阶段二哈希),进行真正的数据(item)存取
Memcached的服务器客户端通信并不使用复杂的XML等格式,而使用简单的基于文 本行的协议。因此,通过telnet也能在memcached上保存数据、取得数据
Memcached的操作命令 (数据)
标准协议:Memcached所有的标准协议包含在对item执行命令过程中,
一个item包含两行:
第一行:Key Flags ExpirationTime Bytes
Key:Key 用于查找缓存值
Flags:一个32位的标志值,客户机使用它存储关于键值对的额外信息
Expiration time:在缓存中保存键值对的时长(以秒为单位,0表示永远)
Bytes:在缓存中存储的字节数
第二行:Value:存储的值(始终位于第二行)
noreply:可以在命令的第一行后面加入noreply,以避免在处理交互命令的时候,等待服务端的返回
向Memcached写入值命令有:set、add、replace、append、prepend、cas
1:set:用于向缓存添加新的键值对,如果键已经存在,则之前的值将被替换
2:add:仅当缓存中不存在键时,add命令才会向缓存中添加一个键值对,如果缓存中已经存 在键,则之前的值将仍然保持,服务器响应 NOT_STORED
3:replace:仅当键已经存在时,replace命令才会替换缓存中的键。如果缓存中不存在键,服务器响应NOT_STORED
4:append:是在现有缓存数据后面新增数据。如果key不存在,服务器响应 NOT_STORED
5:prepend:是在现有缓存数据前面新增数据。如果key不存在,服务器响应 NOT_STORED
6:cas(Check And Set ):检查和更新,只有从你读取数据后,别人没有更新这 个数据,才能够正确保存。就是版本控制,通常和gets配合使用
获取数据的命令有:get 、 gets get用来获取数据,gets获取的是数据+版本号
删除数据的命令:delete
incr/decr命令:如果缓存数据中存储的是数字形式的字符串,则可以使用
incr/decr 对数据进行递增和递减操作,操作后的值不会为负数
Memcached的操作命令 (运行)
stats命令:查询服务器的运行状态和其他内部数据,包含如下这些:
1:pid :服务器进程 ID
2:uptime :服务器运行时间,单位秒
3:time:服务器当前的 UNIX 时间
4:version :服务器的版本号
5:libevent:libevent的版本
6:pointer_size :服务器操作系统位数
7:rusage_user:该进程累计的用户时间
8:rusage_system:该进程累计的系统时间
9:curr_connections :当前连接数
10:total_connections :服务器启动后总连接数
11:connection_structures :服务器分配的连接结构的数量
12:reserved_fds:内部使用的misc fds 数量
13:cmd_get :获取请求数量
14:get_hits :获取成功的总次数,命中次数
15:get_misses :获取失败的总次数
16:cmd_set :存储请求数量
17:cmd_flush :flush请求的数量
18:cmd_touch:touch请求的数量
19:delete_misses :删除失败次数
20:delete_hits :删除命中
21:incr_misses :递增失败次数
22:incr_hits :递增命中次数
23:decr_misses :递减命中次数
24:decr_hits :递减失败次数
25:cas_misses :Cas 原子设置操作失败次数
26:cas_hits :Cas 命中次数
27:cas_badval :Cas 操作找到 key, 但是版本过期,没有设置成功
28:touch_hits:touch命中次数
29:touch_misses:touch失败次数
30:auth_cmds :认证次数(包括成功和失败)
31:auth_errors :认证失败次数
32:bytes :已用缓存空间
33:bytes_read :总共获取的数据量
34:bytes_written :总写入数量数
35:limit_maxbytes :总允许写入的数据量,和分配的内存有关
36:accepting_conns:允许的总连接数
37:listen_disabled_num :监听失败的次数
38:threads:需要的工作线程数
39:hash_bytes:当前使用的Hash table容量大小
40:hash_is_expanding:指定Hash table是否自动增长
41:malloc_fails:malloc内存分配失败的次数
42:curr_items :当前缓存 item 数量
43:total_items :从服务启动后,总的存储缓存 item 数量
44:evictions :通过删除 item 释放内存的次数
这些数据隐含的几个基本关系:
1:缓存命中率 = get_hits/cmd_get * 100%
2:get_misses的数字加上get_hits应该等于cmd_get
stats sizes命令:输出所有Item的大小和个数,注意:会锁定服务,暂停处理请求
flush_all命令:使内存中所有的item失效。加入参数则表示在N秒后失效。这个操作并不会真的释放内存空间,而是标志所有的item为失效
version命令:查看版本
stats settings查看设置
maxbytes:最大字节数限制,0无限制
maxconns:允许最大连接数
tcpport:TCP端口
udpport:UDP端口
verbosity:日志0=none,1=som,2=lots
oldest:最老对象过期时间
evictions:on/off,是否禁用LRU
domain_socket:socket的domain
umask:创建Socket时的umask
growth_factor:增长因子
chunk_size:key+value+flags大小
num_threads:线程数,可以通过-t设置,默认4
stat_key_prefix:stats分隔符
detail_enabled:yes/no,显示stats细节信息
reqs_per_event:最大IO吞吐量(每event)
cas_enabled:yes/no,是否启用CAS,-C禁用
tcp_backlog:TCP监控日志
auth_enabled_sasl:yes/no,是否启用SASL验证
stats slabs区块统计
chunk_size:chunk大小,byte
chunks_per_page:每个page的chunk数量
total_pages:page数量
total_chunks:chunk数量*page数量
get_hits:get命中数
cmd_set:set数
delete_hits:delete命中数
incr_hits:incr命中数
decr_hits:decr命中数
cas_hits:cas命中数
cas_badval:cas数据类型错误数
used_chunks:已被分配的chunk数
free_chunks:剩余chunk数
free_chunks_end:分完page浪费chunk数
mem_requested:请求存储的字节数
active_slabs:slab数量
total_malloced:总内存数量
被浪费内存数=((total_chunks或者used_chunks) * chunk_size) - mem_requested,如果太大,需要调整factor
Memcached的数据存储方式
1:先把内存分成很多个Slab,这个大小是预先规定好的,以解决内存碎片的问题.分配给Slab的内存空间被称为Page,默认是1M。一个Slab下可以有多个Page。
2:然后把一个Page分成很多个chunk块,chunk块是用于缓存记录的空间。Chunk的大小是先有一个基本值,然后根据增长因子来增大。
3:slab class:内存区类别(48byte-1M),每个类别有一个slab classId
4:Memcached里面保存着slab内空闲的chunk列表,当收到要保存的item的时候,它会根据item的大小,去选择一个最合适的slab,然后找到空闲的chunk,把数据 存放进去
新建Item分配内存过程
1:快速定位slab classid,先计算Item长度 key键长+flag+suffix(16字节)+value值长+结构大小(32字节),如90byte .如果>1MB,无法存储丢弃 取最小冗余的slab class 如:有48,96,120,存90会选择96
2:按顺序寻找可用chunk
(1)slot:检查slab回收空间slot里是否有剩余chunk
delete:delete时标记到slot
exptime:get时检查的过期对象标记到slot
(2)end_page_ptr:检查page中是否有剩余chunk
(3)memory:内存还有剩余空间可以用于开辟新的slab
(4)LRU
Memcached的数据存储方式的缺点 由于chunk的大小是预先分配好的特定长度,因此如果数据不能完全填满
chunk,那么剩余的空间就浪费了
Memcached的数据过期方式
Lazy Expiration(延迟/惰性 过期) Memcached不会监控记录是否过期,而是在外部来获取数据的时候,才检查记录的时间戳,因此称为Lazy Expiration。
LRU(Least Recently Used 最近最少使用) 当空间不足的时候,Memcached会优先使用已经过期的数据空间,如果还不够,那么就会把最近最少使用的对象的空间释放出来使用。
懒惰删除机制删除item对象时,不释放内存,作删除标记,指针放入slot回收插槽,下次分配的时候直接使用要特别注意:Memcached的LRU不是全局的,而是针对slab的,可以说是区域性的
Memcached的Java客户端
Memcached的守护进程是用C写的,但是客户端可以用任何语言来编写,并通过memcached协议与守护进程通信
Memcached的Java客户端可以查看http://code.google.com/p/memcached/wiki/Clients,
大致有: Java memcached client/danga、spymemcached、Xmemcached
官方的Memcached的Java客户端API,主要提供的调用类是SockIOPool和MemCachedClient SockIOPool
public static SockIOPool getInstance()
获得连接池的单态方法。这个方法有一个重载方法getInstance( String poolName ),每个 poolName只构造一个SockIOPool实例。缺省构造的poolName是default。 如果在客户端配置多个 memcached服务,一定要显式声明poolName。
public void setServers( String[] servers )
设置连接池可用的cache服务器列表,server的构成形式是IP:PORT(如:127.0.0.1:1111)
public void setWeights( Integer[] weights )
设置连接池可用cache服务器的权重,和server数组的位置一一对应。其实现方法是通过根据每个权重在连接池的bucket中放置同样数目的server,因此所有权重的最大公约数应该是1,不然会引起 bucket资源的浪费。
public void setInitConn( int initConn )
设置开始时每个cache服务器的可用连接数
public void setMinConn( int minConn )
设置每个服务器最少可用连接数
public void setMaxConn( int maxConn )
设置每个服务器最大可用连接数 public void setMaxIdle( long maxIdle ) 设置可用连接池的最长等待时间
public void setMaintSleep( long maintSleep )
设置连接池维护线程的睡眠时间 ,设置为0,维护线程不启动。维护线程主要通过log输出socket的运行状况,监测连接数目及空闲等待时间等参数以控制连接创建和关闭。
public void setNagle( boolean nagle )
设置是否使用Nagle算法,因为我们的通讯数据量通常都比较大(相对TCP控制数据)而且要求响 应及时,因此该值需要设置为false(默认是true)
ublic void setSocketTO( int socketTO )
设置socket的读取等待超时值
public void setSocketConnectTO( int socketConnectTO )
设置socket的连接等待超时值
public void setAliveCheck( boolean aliveCheck )
设置连接心跳监测开关。 设为true则每次通信都要进行连接是否有效的监测,造成通信次数倍
增,加大网络负载,因此该参数应该在对HA要求比较高的场合设为TRUE,默认状态是false。
public void setFailback( boolean failback )
设置连接失败恢复开关 ,设置为TRUE,当宕机的服务器启动或中断的网络连接后,这个socket 连接还可继续使用,否则将不再使用,默认状态是true,建议保持默认。
public void setFailover( boolean failover ) 设置容错开关,设置为TRUE,当前socket不可用时,程序会自动查找可用连接并返回,否则返回 NULL,默认状态是true,建议保持默认。
public void setHashingAlg( int alg )
设置hash算法
alg=0 使用String.hashCode()获得hash code,该方法依赖JDK,可能和其他客户端不兼容,建议不使用 alg=1 使用original 兼容hash算法,兼容其他客户端
alg=2 使用CRC32兼容hash算法,兼容其他客户端,性能优于original算法
alg=3 使用MD5 hash算法
采用前三种hash算法的时候,查找cache服务器使用余数方法。采用最后一种hash算法查找cache 服务时使用一致性hash方法
public void initialize()
设置完pool参数后最后调用该方法,启动pool。
MemCachedClient
public void setCompressEnable( boolean compressEnable )
设定是否压缩放入cache中的数据,默认值是ture,如果设定该值为true,需要设定 CompressThreshold
public void setCompressThreshold( long compressThreshold )
设定需要压缩的cache数据的阈值 ,默认值是30k
public void setPrimitiveAsString( boolean primitiveAsString )
设置cache数据的原始类型是String ,默认值是false。只有在确定cache的数据类型是string的情况下才设为true,这样可以加快处理速度。
public void setDefaultEncoding( String defaultEncoding )
当primitiveAsString为true时使用的编码转化格式 ,默认值是utf-8 。如果确认主要写入数据 是中文等非ASCII编码字符,建议采用GBK等更短的编码格式
set方法 :将数据保存到cache服务器,如果保存成功则返回true 如果cache服务器存在同样的key,则替换
add方法 :将数据添加到cache服务器,保存成功则返回true。如果存在同样key,则返回false replace方法 :将数据替换cache服务器中相同的key,如果保存成功则返回true。
get方法 :获取一个数据,如果写入时是压缩的或序列化的,则get的返回会自动解压缩及反序列化。 getMulti方法:从cache服务器获取一组数据
get方法的数组实现,输入参数keys是一个key数组,返回是一个map
gets方法 gets除了会返回缓存值外,还会返回当前缓存的版本号,一般是用于协同CAS完成原
子操作使用
getMultiArray方法 :返回缓存的数组 cas方法原子设置缓存操作,通过版本号casUnique保证设置的唯一性,如果发现服务器的缓 存版本与传入的不同,则放弃设置缓存,返回false
storeCounter方法 : 初始化一个计数器
getCounter方法 : 获取当前的计数器值
incr方法: 对计数器增量操作
decr方法: 对计数器减量操作
addOrIncr,addOrDecr:key存在则与incr和decr相同,不存在则相当于storeCounter
在Maven工程中使用的时候
1:先要把jar包添加到本地仓库,方法如下:
mvn install:install-file -Dfile=java_memcached-release_2.6.6.jar - DgroupId=com.danga -DartifactId=memcached -Dversion=2.6.6 - Dpackaging=jar -DgeneratePom=true
2:然后:在pom中添加lib依赖: <dependency>
<groupId>com.danga</groupId>
<artifactId>memcached</artifactId>
<version>2.6.6</version>
</dependency>
例子:
public class CacheHelper {
private static MemCachedClient mcc = new MemCachedClient();
private CacheHelper() { }
static {
String[] servers = { "192.168.1.106:2222" };
Integer[] weights = { 2 };
SockIOPool pool = SockIOPool.getInstance();
pool.setServers(servers);
pool.setWeights(weights);
pool.setInitConn(5);
pool.setMinConn(5);
pool.setMaxConn(250);
pool.setMaxIdle(1000 * 60 * 60 * 6);
pool.setMaintSleep(30);
pool.setNagle(false);// 禁用nagle算法
pool.setSocketConnectTO(0);
pool.setSocketTO(3000);// 3秒超时
pool.setHashingAlg(3);//设置为一致性hash算法
pool.initialize();
}
public static MemCachedClient getMemCachedClient(){
return mcc;
}
}
Memcached和Spring集成开发
<!--memcached 客户端 SocketPool-->
<bean id="memcachedPool" class="com.danga.MemCached.SockIOPool" factory- method="getInstance" init-method="initialize" destroy-method="shutDown">
<constructor-arg>
<value>neeaMemcachedPool</value>
</constructor-arg>
<property name="servers">
<list>
<value>192.168.1.106:2222</value>
<value>192.168.1.106:2223</value>
</list>
</property>
<property name="weights">
<list>
<value>1</value>
<value>2</value>
</list>
</property>
<property name="initConn">
<value>5</value>
</property>
<property name="minConn">
<value>5</value>
</property>
<property name="maxConn">
<value>250</value>
</property>
<property name="maintSleep">
<value>30</value>
</property>
<property name="nagle">
<value>false</value>
</property>
<property name="maxIdle">
<value>6000</value>
</property>
<property name="socketTO">
<value>3000</value>
</property>
</bean>
<!--memcached client-->
<bean id="memCachedClient" class="com.danga.MemCached.MemCachedClient">
<constructor-arg>
<value>neeaMemcachedPool</value>
</constructor-arg>
</bean>
Memcached的分布式方式
Memcached尽管是“分布式”的缓存系统,但服务器端并没有分布式功能。各个 Memcached不会互相通信以共享信息。那么,怎样进行分布式呢?这完全取决于客户 端的实现
Memcached的分布式客户端 客户端可以通过配置SockIOPool的servers参数保存服务器地址列表,通过
weight参数配置每台服务器的权重。SockIOPool提供了连接池的服务,可以通过 SockIOPool来配置memcahce服务器相关信息,如最大连接数,最小连接数等。
一个key只能存放在一台Memcache服务器上,是不会在多个服务器上有多份拷贝 的,这样的话既可以防止出现刷新不同步的情况,也可以避免磁盘空间的浪费
Memcached的分布式特点
1:服务器端不关心分布式
2:依靠客户端来实现分布式
3:客户端存储着可以访问到的Memcached服务器列表
4:在客户端用算法来保证,对同样key值的数据,读写都操作同一个服务器
分布式中根据余数计算分散的方式
Memcached的分布式方法简单来说,就是“根据服务器台数的余数进行分散”。求得键的整数哈希值,再除以服务器台数,根据其余数来选择服务器。
根据余数计算分散的缺点 余数计算的方法简单,数据的分散性也相当优秀,但也有其缺点。那就是当添加或移除服务器时,缓存重组的代价相当巨大。添加服务器后,余数就会产生巨变,这样就无法获取与保存时相同的服务器,从而影响缓存的命中率
分布式中的一致性Hash算法
Consistent Hashing方式如下:首先求出Memcached服务器(节点)的哈希值, 并将其配置到0~2的32次方的圆上。然后用同样的方法求出存储数据的键的哈希 值,并映射到圆上。然后从数据映射到的位置开始顺时针查找,将数据保存到找 到的第一个服务器上。如果超过232仍然找不到服务器,就会保存到第一台 memcached服务器上 。如果要添加一台memcached服务器。余数分布式算法由于保存键的服务器会发生 巨大变化而影响缓存的命中率,但Consistent Hashing中,只有在continuum上 增加服务器的地点逆时针方向的第一台服务器上的键会受到影响。
从上面的分析可知,Consistent Hashing最大限度地抑制了键的重新分布。而且,有的Consistent Hashing的实现方法还采用了虚拟节点的思想。使用一般的 hash函数的话,服务器的映射地点的分布非常不均匀。因此,使用虚拟节点的思 想,为每个物理节点(服务器)在continuum上分配100~200个点。这样就能抑 制分布不均匀,最大限度地减小服务器增减时的缓存重新分布。
使用Consistent Hashing算法的memcached客户端函数库进行测试的结果是,由 服务器台数(n)和增加的服务器台数(m)计算增加服务器后的命中率计算公式 如下: (1 - n/(n+m)) * 100
Memcached内存调优建议
调优的目标 提高内存利用率,减少内存浪费 提高命中率
调优方法:
1:f参数: factor增长因子,默认为1.25,曾经为2,值越小,slab中chunk size差距越小,内存浪费越小。1.25适合缓存几百字节的对象。
2:n参数:chunk初始值,根据数据分布调整factor 建议:计算一下数据的预期平均长度,调整factor,以获得最恰当的设置。
1:非均匀分布,即数据长度集中在几个区域内,如保存用户Session
2:更极端的状态是等长数据,如定长键值,定长数据,多见于访问、在线统计等
其它常见的问题
1:slab尾部剩余空间 解决办法:规划slab=chunk*n整数倍
2:slab中chunk利用率低:申请的slab只存放了一个Item 解决办法:规划slab=chunk
3:chunk存储Item浪费 如Item是100,存到128字节chunk,就有28字节浪费 解决办法:规划chunk=Item
memcached-tool的Perl脚本
获得slab的使用情况,可以从下面的地址获得脚本: https://raw.github.com/memcached/memcached/master/scripts/memcached- tool
使用方法也极其简单:
$ perl memcached-tool.pl 主机名:端口 选项
可用的选项有:不写,display,move, dump, stats, settings, sizes
查看slabs使用状况时无需指定选项,默认就是这个,基本列的含义如下:
1:#
2:Item_Size
3:Max_age
4:1MB_pages
5:Count
6:Full?
slab class编号
Chunk大小 LRU内最旧的记录的生存时间 分配给Slab的页数 Slab内的记录数 Slab内是否含有空闲chunk
Memcached的限制和使用建议
在Memcached中可以保存的item数据量是没有限制的,只要内存足够
Memcached单进程最大使用内存为2G,要使用更多内存,可以分多个端口开启多个Memcached进程
Memcached设置Item为最大30天的过期时间,设置为永久的也会在这个时间过期,
常量REALTIME_MAXDELTA为60*60*24*30控制
Memcached缺乏认证以及安全管制,应该将Memcached服务器放置在防火墙后
Memcached本身是为缓存而设计的服务器,因此并没有过多考虑数据的永久性问题,当内容容量达到指定值之后,就基于LRU(Least Recently Used)算法自动删除不使用的缓存.最大键长为250字节,大于该长度无法存储,常量KEY_MAX_LENGTH 250控制 n 单个item最大数据是1MB,超过1MB数据不予存储,使用常量POWER_BLOCK 1048576进行控制,它是默认的slab大小,修改后需要重新编译
最大同时连接数是200,通过 conn_init()中的freetotal进行控制,最大软连接数是1024,通过settings.maxconns=1024 进行控制
Memcached不实现冗余机制,也不做任何的容错处理,在节点失效的情况下,集群没有必要做任何容错处理。如果发生了节点失效,应对的措施完全取决于用户。节点失效时,
下面列出几种方案供您选择:
1:忽略它!在失效节点被恢复或替换之前,还有很多其他节点可以应对节点失效带来的影响
2:把失效的节点从节点列表中移除。做这个操作千万要小心!在余数式哈希算法下,客户端添加或移除节点,会导致所有的缓存数据不可用!因为哈希参照的节点列表变化了,大部分key会因为哈希值的改变而被映射到不同的节点上
3:启动热备节点,接管失效节点所占用的IP。这样可以防止哈希紊乱
4:如果希望添加和移除节点,而不影响原先的哈希结果,可以使用一致性哈希算法
5:两次哈希(reshing)。当客户端存取数据时,如果发现一个节点down了,就再
做一次哈希(哈希算法与前一次不同),重新选择另一个节点(需要注意的时, 客户端并没有把down的节点从节点列表中移除,下次还是有可能先哈希到它)。 如果某个节点时好时坏,两次哈希的方法就有风险了,好的节点和坏的节点上都 可能存在脏数据
通常使用Memcached的目的是,通过缓存数据库查询结果,减少数据库访问次数;还有就是缓存热点数据,以提高Web应用的速度、提高可扩展性,比如:
1:缓存简单的查询结果:查询缓存存储了给定查询语句对应的整个结果集,最合适缓存那些经常被用到,但不会改变的SQL语句对应查询到的结果集,比如载入特定的过滤内容
2:缓存简单的基于行的查询结果
3:缓存的不只是SQL数据,可以缓存常用的热点数据,比如页面,以节省CPU时间
使用分层的缓存 Memcached可以高速处理大量的缓存数据,但是还是要根据系统的情况考虑维护多层的缓存结构。除了Memcached缓存之外,还可以通过本地缓存(如 ehcache、oscache等)建立起多级缓存。
例如,可以采用本地缓存缓存一些基本数据,例如少量但访问频繁的数据 (如产品分类,连接信息,服务器状态变量,应用配置变量等),缓存这些数据 并让他们尽可能的接近处理器是有意义的 , 这样可以帮助减少生成页面的时 间,并且在 memcached 失效的情况下可以增加可靠性
特别注意:当数据更新时需要更新缓存
预热你的缓存 如果有一个很高访问率的站点,一开始缓存是空的,然后一大群人点击站点,在填充缓存的过程中,数据库可能会承受不住压力。
解决:可以先把常用的需要缓存的数据想办法填充到Memcached里,比如:可以写一些脚本来缓存通用的页面;也可以写一个命令行工具来填充缓存
Memcached的典型适用场景
1:分布式应用
2:数据库前段缓存
3:服务器间数据共享
4:变化频繁,查询频繁的数据,但是不一定写入数据库,比如:用户在线状态
5:变化不频繁,查询频繁,不管是否入库,都比较适合使用
不适合使用Memcached的场景
1:变化频繁, 一变化就要入库类的应用,比如股票,金融
2:那些不需要“分布”的,不需要共享的,或者干脆规模小到只有一台服务器的应用,memcached不会带来任何好处,相反还会拖慢系统效率,因为网络连接同样需要资源
3:缓存对象的大小大于1MB
4:key的长度大于250字符
5:虚拟主机不让运行memcached服务,如果应用本身托管在低端的虚拟私有服务器上,像vmware, xen这类虚拟化技术 并不适合运行memcached。Memcached需要接管和控制大块的内存,如果memcached管理的内存被OS交换出去,memcached的性能将大打折扣。
6:应用运行在不安全的环境中 Memcached为提供任何安全策略,仅仅通过telnet就可以访问到memcached。如果应用运行在共享的系统上,需要着重考虑安全问题。
7:业务本身需要的是持久化数据或者说需要的应该是database
Memcached的批量导入导出
通常,不应该对Memcached中的item进行批量导入导出 因为Memcached是一个非阻塞的服务器。任何可能导致memcached暂停或瞬时拒绝服务的操作都应该值得深思熟虑。想象看,如果缓存数据在导出导入之间发生了变化,您就需要处理脏数据了;如果缓存数据在导出导入之间过期了,您又怎么处理这些数据呢?
不过在一个场景倒是很有用。如果您有大量的从不变化的数据,并且希望缓存很快热(warm)起来,批量导入缓存数据是很有帮助的。
如果确实需要把memcached中的item批量导出导入,怎么办? 在某些场景下,确实需要批量导出和导入,比如处理“惊群”问题( 节点都失效了,反复的查询让数据库不堪重负),或者存在优化不好的查询等。 一种可行的解决方案是:使用MogileFS(或者CouchDB等类似的软件)来存储item,然后把item计算出来并dump到磁盘上。MogileFS可以很方便地覆写 item,并提供快速地访问。甚至可以把MogileFS中的item缓存在memcached中, 这样可以加快读取速度。MogileFS+Memcached的组合可以加快缓存不命中时的响应速度,提高应用的可用性。