设为首页 收藏本站
查看: 1453|回复: 0

[经验分享] Memcached数据被踢(evictions>0)现象分析

[复制链接]

尚未签到

发表于 2018-12-25 06:24:32 | 显示全部楼层 |阅读模式
  很多同学可能熟知Memcached的LRU淘汰算法,它是在slab内部进行的,如果所有空间都被slabs分配,即使另外一个slab里面有空位,仍然存在踢数据可能。你可以把slab理解为教室,如果你的教室满了,即使别的教室有空位你的教室也只能踢人才能进人。
DSC0000.gif

  本文介绍的却是另外一种现象。今天监控发现线上一memcached发生数据被踢现象,用stats命令看evictions>0,因为以前也出现过此问题,后来对这个参数增加了一个监控,所以这次主动就发现了。由于给memcached分配的内存远大于业务存储数据所需内存,因此初步判断是“灵异现象”。
  第一步,netstat查看所有连接,排除是否被一些未规划的client使用,经排查后断定无此可能。
  第二步,用tcpdump抽样检查set的指令,排除是否有忘记设cache过期时间的client,初步检查所有典型的业务都有expire time。
  第三步,Google,未果
  第四步,看源代码,了解evictions计数器增加时的具体细节,oh, no…
  in items.c, memcached-1.2.8,


125         for (search = tails[id]; tries > 0 && search != NULL; tries--, search=search->prev) {
126             if (search->refcount == 0) {
127                 if (search->exptime == 0 || search->exptime > current_time) {
128                     itemstats[id].evicted++;
129                     itemstats[id].evicted_time = current_time - search->time;
130                     STATS_LOCK();
131                     stats.evictions++;
132                     STATS_UNLOCK();
133                 }
134                 do_item_unlink(search);
135                 break;
136             }
137         }
  从源代码发现踢数据只判断一个条件,if (search->refcount == 0),这个refcount是多线程版本计数用,在当前服务器未启用多线程情况下,refcount应该始终为0,因此初步判断memcached是从访问队列尾部直接踢数据。
  为了证实想法,设计以下场景:


  • 部署一个memcached测试环境,分配比较小的内存,比如8M
  • 设置1条永远不过期的数据到memcached中,然后再get一次,这条数据后续应该存在LRU队尾。
  • 每隔1S向memcached set(并get一次) 1,000条数据,过期时间设为3秒。
  • 一段时间后,stats命令显示evictions=1
  按我以前的理解,第2步的数据是永远不会被踢的,因为有足够过期的数据空间可以给新来的数据用,LRU淘汰算法应该跳过没过期的数据,但结果证实这种判断是错误的。以上业务的服务器发生被踢的现象是由于保存了大量存活期短的key/value,且key是不重复的。另外又有一业务保存了小量不过期的数据,因此导致不过期的数据惨遭被挤到队列踢出。
  本来这个问题就告一段落了,但在写完这篇文章后,顺便又看了新一代memcached 1.4.1的源代码,很惊喜发现以下代码被增加。
  items.c, memcached 1.4.1


107     /* do a quick check if we have any expired items in the tail.. */
108     int tries = 50;
109     item *search;
110
111     for (search = tails[id];
112          tries > 0 && search != NULL;
113          tries--, search=search->prev) {
114         if (search->refcount == 0 &&
115             (search->exptime != 0 && search->exptime < current_time)) {
116             it = search;
117             /* I don't want to actually free the object, just steal
118              * the item to avoid to grab the slab mutex twice
119              */
120             it->refcount = 1;
121             do_item_unlink(it);
122             /* Initialize the item block: */
123             it->slabs_clsid = 0;
124             it->refcount = 0;
125             break;
126         }
127     }
  重复进行上述测试,未发生evictions。
  9/8 Update: 注意到L108的tries=50没有?试想把测试第2步设置51条不过期数据到cache中,情况会怎样?因此新版的Memcached也同样存在本文描述问题。
  几条总结:


  • 过期的数据如果没被显式调用get,则也要占用空间。
  • 过期的不要和不过期的数据存在一起,否则不过期的可能被踢。
  • 从节约内存的角度考虑,即使数据会过期,也不要轻易使用随机字符串作为key,尽量使用定值如uid,这样占用空间的大小相对固定。
  • 估算空间大小时候请用slab size计算,不要按value长度去计算。
  • 不要把cache当作更快的key value store来用, cache不是storage。




运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-655405-1-1.html 上篇帖子: linux下memcached的启动/结束的方式 下篇帖子: CentOS下安装memcached
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表