用PHP Pecl memcache的哥们应该都知道,memcache client的add和set方法中第三个参数是表示是否用压缩存储的
bool Memcache::add ( string key, mixed var [, int flag [, int expire]] )
bool Memcache::set ( string key, mixed var [, int flag [, int expire]] )
flag
Use MEMCACHE_COMPRESSED to store the item compressed (uses zlib).
还有一个比较重要的函数,是设置要压缩阀值的
bool Memcache::setCompressThreshold ( int threshold [, float min_savings] )
threshold
Controls the minimum value length before attempting to compress automatically.
min_saving
Specifies the minimum amount of savings to actually store the value compressed. The supplied value must be between 0 and 1. Default value is 0.2 giving a minimum 20% compression savings.
其中,threshold是设置开始压缩的最小长度,大于这个长度的串才会尝试自动压缩;
min_saving是使用压缩存储的最小节省百分比。当压缩后长度 < 原长度 * (1 - min_saving) 时,才会使用压缩存储
废话太多了,看源代码最快了
- int mmc_pool_store(mmc_pool_t *pool, const char *command, int command_len, const char *key, int key_len, int flags, int expire, const char *value, int value_len TSRMLS_DC) /* {{{ */
- {
- mmc_t *mmc;
- char *request;
- int request_len, result = -1;
- char *key_copy = NULL, *data = NULL;
- if (key_len > MMC_KEY_MAX_SIZE) {
- key = key_copy = estrndup(key, MMC_KEY_MAX_SIZE);
- key_len = MMC_KEY_MAX_SIZE;
- }
- /* autocompress large values */
- if (pool->compress_threshold && value_len >= pool->compress_threshold) {
- flags |= MMC_COMPRESSED;
- }
- if (flags & MMC_COMPRESSED) {
- unsigned long data_len;
- if (!mmc_compress(&data, &data_len, value, value_len TSRMLS_CC)) {
- mmc_server_seterror(mmc, "Failed to compress data", 0);
- return -1;
- }
- /* was enough space saved to motivate uncompress processing on get */
- if (data_len < value_len * (1 - pool->min_compress_savings)) {
- value = data;
- value_len = data_len;
- }
- else {
- flags &= ~MMC_COMPRESSED;
- efree(data);
- data = NULL;
- }
- }
- request = emalloc(
- command_len
- + 1 /* space */
- + key_len
- + 1 /* space */
- + MAX_LENGTH_OF_LONG
- + 1 /* space */
- + MAX_LENGTH_OF_LONG
- + 1 /* space */
- + MAX_LENGTH_OF_LONG
- + sizeof("/r/n") - 1
- + value_len
- + sizeof("/r/n") - 1
- + 1
- );
- request_len = sprintf(request, "%s %s %d %d %d/r/n", command, key, flags, expire, value_len);
- memcpy(request + request_len, value, value_len);
- request_len += value_len;
- memcpy(request + request_len, "/r/n", sizeof("/r/n") - 1);
- request_len += sizeof("/r/n") - 1;
- request[request_len] = '/0';
- while (result < 0 && (mmc = mmc_pool_find(pool, key, key_len TSRMLS_CC)) != NULL) {
- if ((result = mmc_server_store(mmc, request, request_len TSRMLS_CC)) < 0) {
- mmc_server_failure(mmc TSRMLS_CC);
- }
- }
- if (key_copy != NULL) {
- efree(key_copy);
- }
- if (data != NULL) {
- efree(data);
- }
- efree(request);
- return result;
- }
- /* }}} */
- static int mmc_compress(char **result, unsigned long *result_len, const char *data, int data_len TSRMLS_DC) /* {{{ */
- {
- int status, level = MEMCACHE_G(compression_level);
- *result_len = data_len + (data_len / 1000) + 25 + 1; /* some magic from zlib.c */
- *result = (char *) emalloc(*result_len);
- if (!*result) {
- return 0;
- }
- if (level >= 0) {
- status = compress2((unsigned char *) *result, result_len, (unsigned const char *) data, data_len, level);
- } else {
- status = compress((unsigned char *) *result, result_len, (unsigned const char *) data, data_len);
- }
- if (status == Z_OK) {
- *result = erealloc(*result, *result_len + 1);
- (*result)[*result_len] = '/0';
- return 1;
- }
- switch (status) {
- case Z_MEM_ERROR:
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Not enough memory to perform compression");
- break;
- case Z_BUF_ERROR:
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Not enough room in the output buffer to perform compression");
- break;
- case Z_STREAM_ERROR:
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid compression level");
- break;
- default:
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown error during compression");
- break;
- }
- efree(*result);
- return 0;
- }
- /* }}}*/
来,做个小测试
- <?php
- $memObj = new memcache();
- $memObj->connect("127.0.0.1", 12121);
- $memObj->set("test1", str_repeat("a", 13), MEMCACHE_COMPRESSED);
- $memObj->set("test2", str_repeat("a", 14), MEMCACHE_COMPRESSED);
- ?>
然后,telnet上服务器看效果
$telnet 127.0.0.1 12121
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
get test1
VALUE test1 0 13
aaaaaaaaaaaaa
END
get test2
VALUE test2 2 11
某些乱码
END
可以看到,13个重复的a没有被压缩,因为压缩后的长度太大,没有到达节省20%空间的阀值。
14个重复的a被压缩了,因为压缩后长度为11, 11 < 14 * (1 - 0.2)
其中,VALUE test 2 11含义如下
VALUE key flag length
flag为用二进制表示,第1位表示序列化,第2位表示压缩,其他保留