今天上线后发现一台MYSQL的从库连接数突然变高,发现有一条SQL语句反复在执行,跟程序后发现应该走memcache缓存的,但是没写进去,DEBUG后发现要存储的内容达到8M,而memcache最大允许1m的数据
采用最新的PHP的memcached扩展,最新的扩展会把数据进行压缩
$cache = new memcahed(); $data = str_repeat('a', 1024* 1024); //1M的数据 $r = $cache->set('key', $data, 9999); //或者 $data = str_repeat('a', 1024* 1024*100);//100M的数据 $r = $cache->set('key', $data, 9999);
不论是1M的数据还是100M的数据,都能set成功。memcachedset数据的时候是默认压缩的。由于这个这个是重复的字符串,压缩率高达1000倍。因此100M的数据压缩后实际也就100k而已。
如果程序是这样
$cache->setOption(memcahed::OPT_COMPRESSION,0); //不压缩存储数据。 $data = str_repeat('a', 1024* 1024); //1M数据 $r = $cache->set('key', $data, 9999);//1M的数据set不成功。
也就是说memcached server不能存储超过1M的数据,但是经过客户端压缩数据后,只要小于1M的数据都能存储成功。
单个item的大小被限制在1M byte之内
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提供更多的内存。
不要尝试向memcached中存取很大的数据,因为将大数据load和unpack到内存中需要花费很长的时间,从而导致系统的***能反而不好。如果确实需要存储大于1MB的数据,可以修改 slabs.c:POWER_BLOCK的值,然后重新编译memcached;或者使用低效的malloc/free。另外,可以使用数据库、 MogileFS等方案代替Memcached系统。
memcached能接受的key的最大长度是250个字符
memcached能接受的key的最大长度是250个字符。需要注意的是,250是memcached服务器端内部的限制。如果使用的 Memcached客户端支持"key的前缀"或类似特***,那么key(前缀+原始key)的最大长度是可以超过250个字符的。推荐使用较短的key, 这样可以节省内存和带宽。
memcached对item的过期时间有什么限制?
一个item对象的过期时间最长可以达到30天。memcached把传入的过期时间(时间段)解释成时间点后,一旦到了这个时间点,memcached就把item置为失效状态,这是一个简单但obscure的机制。
memcached的内存分配器是如何工作的?为什么不适用malloc/free!?为何要使用slabs?
实际上,这是一个编译时选项。默认会使用内部的slab分配器,而且确实应该使用内建的slab分配器。最早的时候,memcached只使用 malloc/free来管理内存。然而,这种方式不能与OS的内存管理以前很好地工作。反复地malloc/free造成了内存碎片,OS最终花费大量 的时间去查找连续的内存块来满足malloc的请求,而不是运行memcached进程。slab分配器就是为了解决这个问题而生的。内存被分配并划分成 chunks,一直被重复使用。因为内存被划分成大小不等的slabs,如果item的大小与被选择存放它的slab不是很合适的话,就会浪费一些内存。
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中的唯一标识将会改变,写操作就会失败。
不能够遍历memcached中所有的item
这 个操作的速度相对缓慢且阻塞其他的操作(这里的缓慢时相比memcached其他的命令)。memcached所有非调试(non-debug)命令,例 如add, set, get, fulsh等无论memcached中存储了多少数据,它们的执行都只消耗常量时间。任何遍历所有item的命令执行所消耗的时间,将随着 memcached中数据量的增加而增加。当其他命令因为等待(遍历所有item的命令执行完毕)而不能得到执行,因而阻塞将发生。