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

[经验分享] 再说memcache的multiget hole(无底洞)

[复制链接]

尚未签到

发表于 2015-8-31 09:09:32 | 显示全部楼层 |阅读模式
关键词:multiget hole,memcache
适用于:java,php


基础知识背景:
1)multiget 是什么:
    multiget 指的是从 memcache(或其他分布式缓存) 一次性获得多个键值,一般由 memcached client 自行实现。如 PHP-memcache-client 提供了 Memcached::getMulti 函数。调用示范如下:



<?php
$items = array(
    'key1' => 'value1',
    'key2' => 'value2',
    'key3' => 'value3'
);
$m->setMulti($items);
$result = $m->getMulti(array('key1', 'key3', 'badkey'), $cas);
var_dump($result, $cas);
?>


2)”multiget hole“详解:
    火丁在2012年描述了 multiget  无底洞:

『让我们来模拟一下案发经过,看看到底发生了什么:  我们使用 Multiget 一次性获取100个键对应的数据。
  系统最初只有一台 Memcached 服务器,随着访问量的增加,系统负载捉襟见肘,于是我们又增加了一台 Memcached 服务器,数据散列到两台服务器上。
  开始那100个键在两台服务器上各有50个。
  问题就在这里:原本只要访问一台服务器就能获取的数据,现在要访问两台服务器才能获取;服务器加的越多,需要访问的服务器就越多,所以问题不会改善,甚至还会恶化。
  不过,作为被告方,Memcached官方开发人员对此进行了辩护:
  请求多台服务器并不是问题的症结,真正的原因在于客户端在请求多台服务器时是并行的还是串行的!问题是很多客户端,包括Libmemcached在内,在处理Multiget多服务器请求时,使用的是串行的方式!也就是说,先请求一台服务器,然后等待响应结果,接着请求另一台,结果导致客户端操作时间累加,请求堆积,性能下降
  如何解决这个棘手的问题呢?只要保证 Multiget 中的键只出现在一台服务器上即可!(注:事实上这可不容易做到。)

  3)以前郑昀在文章里说过,spymemcached 某版本又是如何实现 Multiget(即getBulk)的


  • 给一组 key,[1,2,3,4,5]。
  • 先算一下这些key都落在哪些节点上(通过 KetamaNodeLocator 的 public Iterator<MemcachedNode> getSequence(String k)。Now that we know how many servers it breaks down into.);
  • 此时,得到一个map:<Node1,[1,3]>;<Node2,[2,4]>;<Node3,[5]>;
  • 遍历这个map,从每一个 mc node 读出对应的 keys(即单节点的 multiget 操作);一个Node一个Node串行的;
  • 拼成一个大map<key,value>返回。


这样就是一个 node 复一个 node 串行检索的,虽然做了优化,但是如果涉及的 mc nodes 数量多,线程势必长时间阻塞在等待网络资源返回上。
(注:
spymemcached 后来的版本不再按 node 串行轮询,而是并行:第一步,将本次操作构造成一个针对每个 node 的 Operation 对象,加入连接对象中;第二步,在连接对象中,将所有的 node 操作放入 addedQueue 队列,然后触发 Selector 方式异步非阻塞的执行。)



现象:
    某中心每天很多个读取 memcache 键值超时,报错如下:

Caused by: java.util.concurrent.ExecutionException: net.spy.memcached.internal.CheckedOperationTimeoutException: Operation timed out. - failing node: mcN.domain.name  at net.spy.memcached.internal.OperationFuture.get(OperationFuture.java:172)
  at net.spy.memcached.internal.GetFuture.get(GetFuture.java:62)

分析:
    在 memcache 集群节点较多情况下,
    特别是在一次性获取成百上千键值的极端场景面前,

    服务端轻则请求超时,重则宕机

    无论是先计算 keys 都散列到哪些 mc nodes 上了,还是直接轮询 memcached::get ,或者说并行提交给各个 mc nodes 然后异步等待,
    假设每个 mc get 耗时2~3毫秒,一次性取 2000 个keys,都将阻塞线程长达2~6秒之久,这是身为服务所不能容忍的。

    所以,必须约定,适度使用批量获取键值功能,100个键值就到顶了,别因小失大。
   
    当然,也有业务场景绕不开 multiget,那么,一是按照 facebook 所说,此时需要的是更多的 CPU,把缓存数据复制一份到另一个 memcache 集群上,一个集群负责读一半的 keys;二是按照火丁所说,最好保证批量查的这批键值都在同一个 mc node 上。

参考资源:
1)火丁,2012,memcache 二三事儿;
2)郑昀,2013,关于 Multiget hole:spymemcached对此的实现方法;
3)iteye,2012,通过NIO实现Memcached multi get;
4)facebook,2009,Facebook's Memcached Multiget Hole: More machines != More Capacity ;
赠图几枚:
死锁分析
DSC0000.jpg

运维网声明 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-106623-1-1.html 上篇帖子: Memcache的安全 下篇帖子: Linux下php安装memcache扩展
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

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

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

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

扫描微信二维码查看详情

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


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


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


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



合作伙伴: 青云cloud

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