• 进入"运维那点事"后,希望您第一件事就是阅读“关于”栏目,仔细阅读“关于Ctrl+c问题”,不希望误会!

理解memcached为什么会丢数据?

Memcached 彭东稳 9年前 (2016-06-01) 28734次浏览 已收录 0个评论

分享一个memcached丢失数据后的解决办法

在看这篇文章之前,最起码要知道memcached系列前三篇的知识,最重要的就是memcached的命令以及memcached内存管理策略,这是理解memcached为什么会丢数据的基础。

01-Memcached缓存数据库介绍

02-Memcached安装使用详解

03-Memcached内存分配策略

04-Memcached缓存使用实例(PHP)

05-Memcached分布式机制

需要你知道的memcached的相关命令:

stats – 查看memcached状态信息的命令

stats slabs – 查看memcached各个slab的状态信息命令

需要你知道的memcached的相关知识:

1)Memcached的内存分配策略是按slab需求分配page,每一个page是1G,各slab按需使用chunk存储key。

2)各个slab之间chunk大小的增长因子倍数是1.25倍。

3)Key存储的方式是只会存储在离自己最近且大于或等于自己的slab中,不会存储到其他slab。

4)Memcached分配出去的page不会被回收或者重新分配的。

5)每一个slab空闲的chunk不会借给任何其他slab使用。

大概知道了上面这些,下面开始言归正传

由于公司使用了很多memcached缓存服务器,一直也都没有什么问题。最近业务出了一些问题,开发说是memcached中缓存的那个大key(大概25K)丢失了导致了业务出了问题(其实这里需要说一下,memcached只是缓存不可用来保证数据安全性的,开发使用姿势有问题)。当时跟他确认是否真的存进去了,根据开发的描述那个key肯定是存进去了(缓存是3天),但是不到5秒钟就消失了。。。。。。

当时我唯一能想到的就是内存满了,memcached使用了LRU算法把旧的key清除了(默认开启LRU算法),这是一个很合理的解释。于是看了对memcached的监控,一个memcached实例给的是18G内存。

理解memcached为什么会丢数据?

晕菜了,最高只用了3点多个G而已,我的一个实例可是有18G内存可用的啊。既然内存没有用完,为什么会丢Key呢?我开始怀疑是不是memcached有问题了。网上找了一通也没有找到有说数据丢失的问题。

第二天,跟公司的几个同事一通讨论,由于从监控上面看到的内存确实没有用完,所以刚开始重心也就没有往LRU剔除数据上面想。想过说可能因为key太多,准备调整各个slabs之间的增长因子,但以我对memcached的简单了解,slabs的调整只是为了节省内存而已。如果你要存储的key都普遍很小,slabs就调小一点,但最小不能小于1;如果你的key普遍都很大,slabs就调大一点,都可能会节省内存。后来也想过说关闭memcached的LRU功能,不让剔除旧的key,都让key自动过期,但风险就是如果内存写满了,再次写入key时就会报错。

后来又是一番讨论,应了那句话人多力量大啊。既然memcached对于申请过的内存不会释放,最终决定先把memcached中所有的slabs的Page加起来,看一下到底用了多少内存。其实这里有一个非常简便的方法就是使用ps或top命令看memcached进程占用了多少内存,当时没有想到,后来才去看这个线索。

VSZ:虚拟内存集

RSS:常驻内存集

刚好使用了18G内存。

但是当时我没有看进程,而是用了最传统的方式(其实就算使用ps命令看到了memcached已经把内存占完了也不能够全部解决问题,因为还是要明白memcached的工作原理,为什么内存被全部占用了)。

首先用stats命令看了一下memcached实际占用内存大小就是3个多G。

然后把所有slabs的Page占用给列出来(这里省略了一些),加起来刚好是18G,这就可以理解为什么memcached会丢数据了。

从这个列出的pages可以看出,发现这个19号slabs居然申请过12G内存(12033X1M),然后又把这个19号slabs整体信息给提取出来。

从这个信息可以看出,19号slabs存储的key为5k左右大小,申请过12033个Page,一共有2214072个chunk。但是这些chunk只是使用了97418个,还有2116654个没有使用,比例占20/1左右。我去,也就是说这个存储5k左右key大小的slabs一共申请过12G的内存,但是现在只用了0.5G左右,其余的11.5G都处于某种程度的浪费阶段。

为什么会出现这种情况呢?这个19号slabs竟然申请过12G的内存,那么就说明在某一个阶段内就申请过这么多内存,这个slabs存的都是5k左右大小的key了(每个key加上67-69字节的开销)。由于memcached的一些机制,前面已经说了,对于每个slabs申请过的内存不会再释放。

那么,对于此次memcached丢key的原因简单阐述一下就是,在5k左右大小的key,在某一个时间段内(开发说都是缓存3天)使用到了12G内存,然后又释放了。但是后来就没有再使用了这个19 slabs,所以导致我们看到的实际内存大小一直在3个G左右。当这个18G内存申请完了之后,又由于19号slabs只能存储5k左右大小的key,导致新的稍微大一点的key存储到memcached之后,memcached就开始使用LRU算法剔除旧的Key了。明白了这些之后,回到开始的问题,就可以理解key存5秒就丢失的原因了。

这里最后再使用stats命令看看memcached状态。

其实当你看到evictions参数有值得时候,就说明是memcached已经使用LRU开始剔除旧的key了,单位为字节,这里可以看出已经剔除了15M大小的key了。此参数有数值就是有问题,说明内存满过。

处理方式

1)把memcached重启,释放内存,重新分配slabs,但是注意会清除所有的缓存。

2)查看历史监控,查看在什么时间段写入了大量的key,导致19号slabs一直申请内存。

3)根据进程把memcached真实占用的内存给监控起来。

4)也是最重要的一点,memcached只是个缓存,尽量避免存储对安全性要求高的数据,这类数据可以用redis做缓存。

总结

我自己对于这个问题处理完了之后,对memcached的运行机制可以说是更加理解了,使用起来也更加得心应手了。就花了点时间赶快整理出来分享给大家,写完你看完也能对memcached更加了解,碰到此类问题也能够解决。最后想说,遇到事情多讨论,这是人多力量大。


如果您觉得本站对你有帮助,那么可以支付宝扫码捐助以帮助本站更好地发展,在此谢过。
喜欢 (6)
[资助本站您就扫码 谢谢]
分享 (0)

您必须 登录 才能发表评论!