论——memcached真的有工具可以dump出所有key嘛?


声明:本文转载自https://my.oschina.net/feicuigu/blog/1595841,转载目的在于传递更多信息,仅供学习交流之用。如有侵权行为,请联系我,我会及时删除。

插播一条广告→2021 ByteDance字节跳动内推←各城市、各方向的岗位都有,大量招人!


众所周知,memcached并没有像redis那样提供了类似 keys * 的命令来获取所有key,也没有数据持久化,因此memcached想要dump所有的key,需要使用额外的命令组合或工具来实现,但有时命令和工具……也不一定会满足需求。下面是我最近对找到的几种方法进行的分析。

一、命令组合方式

我在git上发现如下工具: https://github.com/gnomeby/memcached-itool

使用该工具的dumpkeys可以将memcached的key进行dump,查看其实现方式发现也是使用了 stats itemsstats cachedump 等命令组合实现的,下面介绍下这种方式的实现及原理。

1. 原理实现

首先需要明白memcached的内存管理方式:Slab Allocator

  • memcached内存分为多个chunk组,即多个slab;
  • 每个组的chunk有不同的大小规格,如slab 1中chunk大小均为96B,slab 2中chunk大小均为120B,以此类推;
  • key根据其大小分别分配到不同的slab组的chunk中存储;

具体的内存分配机制不再展开描述,有兴趣的可以参考如下链接: https://www.cnblogs.com/zhoujinyi/p/5554083.html

2. 具体操作

1)stats items、stats slabs命令获取各slabs id以及slab的具体信息

stats items  STAT items:1:number 39       # slab中的key数量 STAT items:1:age 693911 STAT items:1:evicted 0 STAT items:1:evicted_nonzero 0 STAT items:1:evicted_time 0 STAT items:1:outofmemory 0 STAT items:1:tailrepairs 0 STAT items:1:reclaimed 7 STAT items:1:expired_unfetched 4 STAT items:1:evicted_unfetched 0 STAT items:1:crawler_reclaimed 0 STAT items:1:crawler_items_checked 0 STAT items:1:lrutail_reflocked 0 ... 
stats slabs  STAT 1:chunk_size 96        # slab中的chunk大小规格 STAT 1:chunks_per_page 10922 STAT 1:total_pages 1 STAT 1:total_chunks 10922 STAT 1:used_chunks 39 STAT 1:free_chunks 10883 STAT 1:free_chunks_end 0 STAT 1:mem_requested 3656 STAT 1:get_hits 3666 STAT 1:cmd_set 569 STAT 1:delete_hits 1 STAT 1:incr_hits 0 STAT 1:decr_hits 0 STAT 1:cas_hits 0 STAT 1:cas_badval 0 STAT 1:touch_hits 0 ... 
  • STAT后的数字即slab的标识id

2)stats cachedump {slab_id} {limit_num} 获取slab下的key信息

stats cachedump 1 5 ITEM seller_shop_im_phone_122 [1 b; 1513935640 s]       # key名称 ITEM seller_shop_im_phone_11542 [1 b; 1513935346 s] ITEM user_third_userid_35543020 [2 b; 1516523664 s] ITEM seller_shop_im_phone_12331 [1 b; 1513933986 s] ITEM user_third_userid_70086126 [4 b; 1516517439 s] END 
  • slab_id 即各slab组的标识id
  • limit_num 即key的数量,0表示所有key

3. 问题缺陷

cachedump每次返回的数据只有2M;

而且在memcached源码中是写死的数值。

这个问题很严重。

网上并没有找到相关源码,于是我在官网下载了memcached-1.5.3的源码并查找,发现确实如此:

########## # 源码位置:memcached-1.5.3/items.c ########## char *item_cachedump(const unsigned int slabs_clsid, const unsigned int limit, unsigned int *bytes) {     unsigned int memlimit = 2 * 1024 * 1024;   /* 2MB max response size */     char *buffer;     unsigned int bufcurr;     item *it;     unsigned int len;     unsigned int shown = 0;     char key_temp[KEY_MAX_LENGTH + 1];     char temp[512];     unsigned int id = slabs_clsid;     id |= COLD_LRU;      pthread_mutex_lock(&lru_locks[id]);     it = heads[id];      buffer = malloc((size_t)memlimit);     if (buffer == 0) {         return NULL;     }     bufcurr = 0;      while (it != NULL && (limit == 0 || shown < limit)) {         assert(it->nkey <= KEY_MAX_LENGTH);         if (it->nbytes == 0 && it->nkey == 0) {             it = it->next;             continue;         }         /* Copy the key since it may not be null-terminated in the struct */         strncpy(key_temp, ITEM_key(it), it->nkey);         key_temp[it->nkey] = 0x00; /* terminate */         len = snprintf(temp, sizeof(temp), "ITEM %s [%d b; %llu s]\r\n",                        key_temp, it->nbytes - 2,                        it->exptime == 0 ? 0 :                        (unsigned long long)it->exptime + process_started);         if (bufcurr + len + 6 > memlimit)  /* 6 is END\r\n\0 */             break;         memcpy(buffer + bufcurr, temp, len);         bufcurr += len;         shown++;         it = it->next;     }      memcpy(buffer + bufcurr, "END\r\n", 6);     bufcurr += 5;      *bytes = bufcurr;     pthread_mutex_unlock(&lru_locks[id]);     return buffer; } 

可以看到:

  • 函数第一句定义了 memlimit 参数来限制大小为2M;
  • 之后通过 malloc((size_t)memlimit) 申请了名为buffer的2M空间;
  • 循环获取slab中的item直到达到2M上限;
  • 最后copy到buffer中并return;

由此可以明白,上述命令组合的方式虽然可以批量获取key,但每个slab最大只能dump 2M,数据量超过2M则无法获得所有的key

当然,可以尝试将源码中的memlimit参数调大后重新编译,但是这样也没法从根本上解决问题,因为不可能每次数据量超过后都重新编译一次,而如果直接设置一个很大的值的话————cachedump会不会直接把memcached搞挂掉我也保不准啊!毕竟源码中可是直接 malloc((size_t)memlimit) 一次申请了整个内存的!

感兴趣的大兄弟可以试一下,然后告诉我结果。

本文发表于2017年12月28日 12:32
(c)注:本文转载自https://my.oschina.net/feicuigu/blog/1595841,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。如有侵权行为,请联系我们,我们会及时删除.

阅读 1013 讨论 0 喜欢 0

抢先体验

扫码体验
趣味小程序
文字表情生成器

闪念胶囊

你要过得好哇,这样我才能恨你啊,你要是过得不好,我都不知道该恨你还是拥抱你啊。

直抵黄龙府,与诸君痛饮尔。

那时陪伴我的人啊,你们如今在何方。

不出意外的话,我们再也不会见了,祝你前程似锦。

这世界真好,吃野东西也要留出这条命来看看

快捷链接
网站地图
提交友链
Copyright © 2016 - 2021 Cion.
All Rights Reserved.
京ICP备2021004668号-1