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

[经验分享] Memcached使用点滴 2

[复制链接]

尚未签到

发表于 2018-12-25 06:12:30 | 显示全部楼层 |阅读模式
  可以看到其实pool才是最终连接服务端的配置,看看pool0,它会连接10.2.225.210:13000,10.2.225.210:13001,10.2.225.210:13002这些机器和他们的端口,但是对于使用pool0的mclient0来说它仅仅只是知道有一个叫做mclient0的cache可以保存数据。此时slab就有三个:10.2.225.210:13000和10.2.225.210:13001和10.2.225.210:13002。
  当一个key:value要被放入到Memcached中,首先Memcached会根据key的hash算法获取到hash值来选择被分配的slab,然后根据value选择适合的dump区。所谓dump区其实就是根据value的大小来将内存按照存储单元内容大小分页。这个是可以配置Memcached的,例如Memcached将slab中的内存划分成4个dump,第一dump区存储0-50k大小的数据,第二dump区存储50-100k的数据,第三dump区存储100-500k的数据,第四dump区存储500-1000K的数据。那么当key:value需要被写入的时候,很容易定位到value所处的dump,分配内存给value。这种分dump模式简化内存管理,加速了内存回收和分配。但是这里需要注意的几点就是,首先当你的应用场景中保存的数据大小离散度很高,那么就不是很适合Memcached的这种分配模式,容易造成浪费,例如第一dump区已经满了,第二第三dump区都还是只有一个数据,那么第二第三dump区不会被回收,第二第三dump区的空间就浪费了。同时Memcached对于value的大小支持到1M,大于1M的内容不适合Memcached存储。其实在Cache的设计中这样的情况发生本来就证明设计有问题,Cache只是加速,一般保存都是较小的id或者小对象,用来验证以及为数据定位作精准细化,而大数据量的内容还是在数据库等存储中。
  知道了基本的分配机制以后再回过头来看看代码:
  Map slabs = getCacheClient().statsItems();//获取所有的slab
  //用来收集所有slab的dump号
  while(itemsItr.hasNext())
  {
  String server = itemsItr.next().toString();
  Map itemNames = (Map) slabs.get(server);
  Iterator itemNameItr = itemNames.keySet().iterator();
  while(itemNameItr.hasNext())
  {
  String itemName = itemNameItr.next().toString();
  // itemAtt[0] = itemname
  // itemAtt[1] = number
  // itemAtt[2] = field
  String[] itemAtt = itemName.split(":");
  // 如果是itemName中是:number来表示,那么证明是一个存储数据的dump,还有一些是age的部分
  if (itemAtt[2].startsWith("number"))
  dumps.put(itemAtt[1], Integer.parseInt(itemAtt[1]));
  }
  }
  //根据收集到的dump来获取keys
  if (!dumps.values().isEmpty())
  {
  Iterator dumpIter = dumps.values().iterator();
  while(dumpIter.hasNext())
  {
  int dump = dumpIter.next();
  // statsCacheDump支持三个参数String[],int,int,第一个参数可以省略,默认填入null,表示从那些slab中获取dump号为第二个参数的keys,如果是null就从当前所有的slab中获取。第二个参数表示dump号,第三个参数表示返回最多多少个结果。
  Map cacheDump = statsCacheDump(dump,limit);
  Iterator entryIter = cacheDump.values().iterator();
  while (entryIter.hasNext())
  {
  Map items = (Map)entryIter.next();
  Iterator ks = items.keySet().iterator();
  while(ks.hasNext())
  {
  String k = (String)ks.next();
  try
  {
  //这里为什么要作decode,因为其实在我使用的这个java客户端存储的时候,默认会把key都作encoding一次,所以必须要做,不然会出现问题。
  k = URLDecoder.decode(k,"UTF-8");
  }
  catch(Exception ex)
  {
  Logger.error(ex);
  }
  if (k != null && !k.trim().equals(""))
  {
  //这里的fast参数是在方法参数中传入,作用是什么,其实采用这种搜索slab以及dump的方式获取keys会发现返回的可能还有一些已经移除的内容的keys,如果觉得需要准确的keys,就在做一次contains的检查,不过速度就会有一定的影响。
  if (fast)
  keys.add(k);
  else
  if (containsKey(k))
  keys.add(k);
  }
  }
  }
  }
  }
  至此,整个keySet的问题解决了,对于即时监控也基本都作好了,这里需要把过程中的两件小事情说一下。
  1.    statsCacheDump始终不能用。
  刚开始的时候statsCacheDump方法始终报错说连接超时,跟踪到了java客户端代码中发现并不是什么连接超时,只是服务端返回了错误信息,而客户端认为还没有结束一直等待,导致超时。我就顺手给java客户端的开发人员mail了信息求助(代码里面有email)。再仔细看了看出错信息,返回的是不认识该指令的错误,因此就去解压memcached的服务端,看了看它的协议说明,这个Stat方法还是有的,很奇怪,没有办法了,虽然自己对于c不是很懂,但起码大致看懂逻辑还是不难,下载了Memcached的源码一看,发现居然对于StatsCacheDump这个方法调用必须还有一个参数limit,在我手头的客户端代码里面就没有这个参数,所以错误了,本来想扩展一下那个方法,但是那个方法中实现的不是很好,都是private的不容易扩展,这时候居然收到其中一个客户端开发者的回复邮件,说我手头的代码太老了,同时不建议去实现keyset,认为这样比较低效。我去下载了一个新版本,看了看源码果然已经修复了,我就回了邮件表示感谢,同时也和他说明了这么做的原因。因此大家如果要和我一样写上面的代码,就需要它2.0.1的那个版本。这里对那些国外的开源工作者表示敬佩,对于开发者是很负责任的。
  2.关于fast那个选项
  这个是我加上去的,做了一下测试,例如我先执行如下代码:
  Cache.set(“key1”,”value1”);
  Cache.set(“key2”,”value2”);
  Cache.flushAll(null);
  Cache.set(“key3”,”value3”);
  Cache.set(“key4”,”value4”);
  Boolean fast = true;
  Set keys = Cache.keySet(fast);
  system.out.println(keys);
  Fast = false;
  keys = Cache.keySet(fast);
  system.out.println(keys);
  得到的结果为:
  Key1,key2,key3,key4
  Key3,key4
  可以看到其实如果通过StatsCacheDump来获取得到的keys会参杂一些已经失效的keys,只是没有回收,本来尝试获取时间戳来做判断,不过还不如使用containsKey来的有效。
  同时这里采用containsKey而不是用get,就是因为counter是不能用get获得的,即使counter存在。


运维网声明 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-655398-1-1.html 上篇帖子: memcached的通讯层分析 下篇帖子: Memcached 工作原理介绍
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

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

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

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

扫描微信二维码查看详情

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


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


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


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



合作伙伴: 青云cloud

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