用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) 时,才会使用压缩存储

废话太多了,看源代码最快了

  1. 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) /* {{{ */
  2. {
  3.     mmc_t *mmc;
  4.     char *request;
  5.     int request_len, result = -1;
  6.     char *key_copy = NULL, *data = NULL;
  7.  
  8.     if (key_len > MMC_KEY_MAX_SIZE) {
  9.         key = key_copy = estrndup(key, MMC_KEY_MAX_SIZE);
  10.         key_len = MMC_KEY_MAX_SIZE;
  11.     }
  12.  
  13.     /* autocompress large values */
  14.     if (pool->compress_threshold && value_len >= pool->compress_threshold) {
  15.         flags |= MMC_COMPRESSED;
  16.     }
  17.  
  18.     if (flags & MMC_COMPRESSED) {
  19.         unsigned long data_len;
  20.  
  21.         if (!mmc_compress(&data, &data_len, value, value_len TSRMLS_CC)) {
  22.             mmc_server_seterror(mmc, "Failed to compress data", 0);
  23.             return -1;
  24.         }
  25.  
  26.         /* was enough space saved to motivate uncompress processing on get */
  27.         if (data_len < value_len * (1 - pool->min_compress_savings)) {
  28.             value = data;
  29.             value_len = data_len;
  30.         }
  31.         else {
  32.             flags &= ~MMC_COMPRESSED;
  33.             efree(data);
  34.             data = NULL;
  35.         }
  36.     }
  37.  
  38.     request = emalloc(
  39.         command_len
  40.         + 1                /* space */
  41.         + key_len
  42.         + 1                /* space */
  43.         + MAX_LENGTH_OF_LONG
  44.         + 1             /* space */
  45.         + MAX_LENGTH_OF_LONG
  46.         + 1             /* space */
  47.         + MAX_LENGTH_OF_LONG
  48.         + sizeof("/r/n") - 1
  49.         + value_len
  50.         + sizeof("/r/n") - 1
  51.         + 1
  52.         );
  53.  
  54.     request_len = sprintf(request, "%s %s %d %d %d/r/n", command, key, flags, expire, value_len);
  55.  
  56.     memcpy(request + request_len, value, value_len);
  57.     request_len += value_len;
  58.  
  59.     memcpy(request + request_len, "/r/n", sizeof("/r/n") - 1);
  60.     request_len += sizeof("/r/n") - 1;
  61.  
  62.     request[request_len] = '/0';
  63.  
  64.     while (result < 0 && (mmc = mmc_pool_find(pool, key, key_len TSRMLS_CC)) != NULL) {
  65.         if ((result = mmc_server_store(mmc, request, request_len TSRMLS_CC)) < 0) {
  66.             mmc_server_failure(mmc TSRMLS_CC);
  67.         }
  68.     }
  69.  
  70.     if (key_copy != NULL) {
  71.         efree(key_copy);
  72.     }
  73.  
  74.     if (data != NULL) {
  75.         efree(data);
  76.     }
  77.  
  78.     efree(request);
  79.  
  80.     return result;
  81. }
  82. /* }}} */
  83.  
  84. static int mmc_compress(char **result, unsigned long *result_len, const char *data, int data_len TSRMLS_DC) /* {{{ */
  85. {
  86.     int status, level = MEMCACHE_G(compression_level);
  87.  
  88.     *result_len = data_len + (data_len / 1000) + 25 + 1; /* some magic from zlib.c */
  89.     *result = (char *) emalloc(*result_len);
  90.  
  91.     if (!*result) {
  92.         return 0;
  93.     }
  94.  
  95.     if (level >= 0) {
  96.         status = compress2((unsigned char *) *result, result_len, (unsigned const char *) data, data_len, level);
  97.     } else {
  98.         status = compress((unsigned char *) *result, result_len, (unsigned const char *) data, data_len);
  99.     }
  100.  
  101.     if (status == Z_OK) {
  102.         *result = erealloc(*result, *result_len + 1);
  103.         (*result)[*result_len] = '/0';
  104.         return 1;
  105.     }
  106.  
  107.     switch (status) {
  108.         case Z_MEM_ERROR:
  109.             php_error_docref(NULL TSRMLS_CC, E_WARNING, "Not enough memory to perform compression");
  110.             break;
  111.         case Z_BUF_ERROR:
  112.             php_error_docref(NULL TSRMLS_CC, E_WARNING, "Not enough room in the output buffer to perform compression");
  113.             break;
  114.         case Z_STREAM_ERROR:
  115.             php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid compression level");
  116.             break;
  117.         default:
  118.             php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown error during compression");
  119.             break;
  120.     }
  121.  
  122.     efree(*result);
  123.     return 0;
  124. }
  125. /* }}}*/

来,做个小测试

  1. <?php
  2. $memObj = new memcache();
  3. $memObj->connect("127.0.0.1", 12121);         
  4. $memObj->set("test1", str_repeat("a", 13), MEMCACHE_COMPRESSED);
  5. $memObj->set("test2", str_repeat("a", 14), MEMCACHE_COMPRESSED);
  6. ?>

然后,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位表示压缩,其他保留