memcached使用中踩的一些坑
背景
线上启用memcached(以下简称mc)作为热点缓存组件已经多年,其稳定性和性能都经历住了考验,这里记录一下踩过的几个坑。
大key存储
某年某月某日,观察mysql的读库CPU占比有些异常偏高,去check慢查询log,发现部分应有缓存的慢sql居然存在几秒执行一次情况,不符合缓存数小时的代码逻辑。
查看业务log在每次查询sql之后也确实有将结果set至mc之中:
# python代码
mc.set(cache_key, v, 3600)
而set返回的取值却是False而非正常的True,很快想到mc著名的只可存储不超过1MB大小的key限制,在以往的业务场景中没有出现过这么大的key,所以一直没达到过这个限制,直到这一次撞上。
要解决超过1MB大小的key存储问题有以下几个思路:
- 想办法将cache结果变小
- 换个cache组件
- mc >=1.4.2 版本其实已经支持命令行参数-I指定最大key大小了,线上使用版本支持最小1KB最大128MB的设置
- 将大key拆分为几个子key,通过set_multi和get_multi实现统一的读写。
无论是通过2或3都可以支持更大的key存储,但是更大的key存储对于读写传输其实都更不友好,而思路4需要手动拆分、组装子key略显麻烦,所以优先从思路1着手,意外发现python使用的memcached库其实提供了key压缩功能,在写入时指定min_compress_len参数即可:
mc.set(key, v, time=expires, min_compress_len=1024)
如上表示写入的v对象序列化大小若>=1024则启用压缩存储,库底层会将其压缩后再写入mc,读取时库底层也会自动解压缩后再返回,业务层可以说完全无感,并且压缩后还能极大降低存储和传输成本。
最终通过min_compress_len参数启用大key压缩后,原1MB大小的key直瘦身了4/5。
slab钙化
启用大key压缩后mc度过了好一段岁月静好的日子,直到某一天...
大规模key分布变动导致的钙化
查看zabbix上的相关监控,发现mc的key查询miss比例居然接近50%!这个缓存命中率着实让人深思,进一步check后发现同时异常的指标还有evicted items数,日常取值居然可以达到数百/S的级别。
mc官方文档对evicted items的定义如下:
evicted Number of times an item had to be evicted from the LRU before it expired.
即存储的key在其实际过期前被从LRU强制清理了,这一般说明mc剩余可分配内存不足了,所以新key写入时只能先从LRU淘汰一部分key腾出空间后再给新key使用,但是查看mc的内存使用率,明明还有超过>2GB的剩余内存可用。
最终调查后真相大白:mc明明剩余大量内存可用,写入新key却不断导致旧key被提前清除的现象其实是mc特有的slab钙化问题所致:
Memcached采用LRU(Least Recent Used)淘汰算法,在内存容量满时踢出过期失效和LRU数据,为新数据腾出内存空间。不过该淘汰算法在内存空间不足以分配新的Slab情况下,这时只会在同一类Slab内部踢出数据。即当某个Slab容量满,且不能在内存足够分配新的Slab,只会在相同Slab内部踢出数据,而不会挪用或者踢出其他Slab的数据。这种局部剔除数据的淘汰算法带来一个问题:Slab钙化。
简单来说memcached 使用的不同尺寸slab一旦分配完成就不可变了,所以如果某类slab已用尽,即便其他slab剩余大量空闲内存也无法再对其加以利用。
业务这边之前对使用mc的部分缓存key进行了整合优化,在优化之前单mc的全部5GB内存均已根据key存储情况分配给了特定的slab,而优化之后大大降低了小key的数量,取而代之的是相对更紧凑的大key,key的数量和大小分布都发生了显著的变化,于是原有的适用于大量小key的slab分配就无法满足优化后的key存储了。
最终体现为,中等大小的slab内存已被耗尽,每次写入新key只能先通过LRU淘汰部分旧key腾出空间,体现为evicted数异常偏高,并且直接影响了缓存命中率,而小尺寸的slab却长期大量空闲,体现为mc内存使用剩余空间一直充足。
网上检索解决钙化问题有三个办法:
1) 重启Memcached实例,简单粗暴,启动后重新分配Slab class,但是如果是单点可能造成大量请求访问数据库,出现雪崩现象,冲跨数据库。
2) 随机过期:过期淘汰策略也支持淘汰其他slab class的数据,twitter工程师采用随机选择一个Slab,释放该Slab的所有缓存数据,然后重新建立一个合适的Slab。
3) 通过slab_reassign、slab_authmove参数控制。
方法2看上去应是twitter的定制版mc Twemcache的特有功能,方法3则是线上mc已支持的方案,但首次接触也不敢贸然直接在线上使用。
考虑到mc仅作为热点缓存其数据可丢失,且部署有多台分摊压力,直接采用低峰时段分别重启单个mc的策略解决,重启后evicted item直接降为0,cache命中率升至90%上下。
少量大key变动导致的钙化
首次钙化之后又是一段岁月静好,直到...
某段时间开始一个主要接口偶发耗时会突然飙升一下,对应机器的CPU使用也会瞬间飚高一小阵,查看zabbix监控时,发现mc的 evicted items>0已持续好一段时间,但一直是个位数/S的级别,看着影响不大。
进一步执行stats items命令,发现发生key evict的是最大的chunk_size=1048576 的slab 42,这也就是说存在大小在512KB~1MB之间的大key,同时当前mc分配的1MB slab个数已无法满足其存储,也无法再分配出新的1MB大小的slab,最终体现为对于大key的再次钙化。
由于slab钙化大key会被频繁evict,对应缓存机制基本失效,所幸server端针对该类大key的读取还做了一个短期的本地cache,避免了每次请求都穿透到db。
在某些特定时刻,当mc中对应大key失效且本地cache失效,对应请求又较多的时候,多个独立的请求都会穿透到db获取数据,而后再写入mc,无论是穿透到db获取数据后本地进行相应的数据组装处理逻辑,还是读写mc的压缩、解压缩数据操作,都比较耗CPU,最终会体现为api耗时增加,且CPU使用率也存在飚高的现象。
近期并没有涉及大key读写的改动,那这次的大key slab钙化又是怎么来的?进一步探查原因:触发evict的大key近期确实无相关逻辑改动,但该部分旧key的大小和运营放出的资源多少直接相关,近一段时间放出的资源一直持续增加,旧key原本大小是<512KB,所以使用的是512KB的slab 41,近期持续增大为>512KB后,就只能使用1MB的slab 42存储了,对于slab 42来说相当于在原有支持的大key数量基础上又新的大key存储需要支持,又由于slab钙化无法再分配新的slab 42,最终触发evict,cache命中率降低,api偶发耗时上升。
最终解决方案:还是在业务低峰期逐个重启mc,触发slab重分配即可。
总结
memcached作为一个开源的纯内存kv缓存组件,上手简单、性能、稳定性都有足够保证,但是实际使用时也不可掉以轻心,对其相关监控与关注不能少,对于其特有的最大key存储限制、slab钙化问题要有一定的认识并能及时处理。
转载请注明出处,原文地址:https://www.cnblogs.com/AcAc-t/p/memcached_large_key_slab_calcification.html
参考
https://github.com/memcached/memcached/blob/master/doc/protocol.txt#L637
https://github.com/memcached/memcached/wiki/ReleaseNotes142#configurable-maximum-item-size
https://www.jianshu.com/p/b91a45711460
https://blog.twitter.com/engineering/en_us/a/2012/caching-with-twemcache
https://www.cnblogs.com/AcAc-t/p/memcached_large_key_slab_calcification.html
https://bugwz.com/2020/05/24/memcached-slab-calcification/#2-2-2、Rebalance执行逻辑
https://www.cnblogs.com/Leo_wl/p/3310294.html
memcached使用中踩的一些坑的更多相关文章
- VUE 使用中踩过的坑
vue如今可谓是一匹黑马,github star数已居第一位!前端开发对于vue的使用已经越来越多,它的优点就不做介绍了,本篇是我对vue使用过程中以及对一些社区朋友提问我的问题中做的一些总结,帮助大 ...
- VUE使用中踩过的坑
前言 vue如今可谓是一匹黑马,github star数已居第一位!前端开发对于vue的使用已经越来越多,它的优点就不做介绍了,本篇是我对vue使用过程中以及对一些社区朋友提问我的问题中做的一些总结, ...
- 我用select做多路复用踩到的坑
既然说是用select踩到的坑,那么就先直接贴一段使用select的代码上来瞅一下: bool SocketAction(int fd, const char* buf, size_t len, ui ...
- 项目中踩过的坑之-sessionStorage
总想写点什么,却不知道从何写起,那就从项目中踩过的坑开始吧,希望能给可能碰到相同问题的小伙伴一点帮助. 项目情景: 有一个id,要求通过当前网页打开一个新页面(不是当前页面),并把id传给打开的新页面 ...
- web开发实战--弹出式富文本编辑器的实现思路和踩过的坑
前言: 和弟弟合作, 一起整了个智慧屋的小web站点, 里面包含了很多经典的智力和推理题. 其实该站点从技术层面来分析的话, 也算一个信息发布站点. 因此在该网站的后台运营中, 富文本的编辑器显得尤为 ...
- "开发路上踩过的坑要一个个填起来————持续更新······(7月30日)"
欢迎转载,请注明出处! https://gii16.github.io/learnmore/2016/07/29/problem.html 踩过的坑及解决方案记录在此篇博文中! 个人理解,如有偏颇,欢 ...
- 【转载】Fragment 全解析(1):那些年踩过的坑
http://www.jianshu.com/p/d9143a92ad94 Fragment系列文章:1.Fragment全解析系列(一):那些年踩过的坑2.Fragment全解析系列(二):正确的使 ...
- Redis Cluster踩过的坑
Redis Cluster踩过的坑请参考如下链接:http://www.iteye.com/blogs/subjects/Redis_Cluster_Devops
- 第八篇:web之前端踩的一些坑
前端踩的一些坑 前端踩的一些坑 本节内容 事件代理 清除标签的所有事件 bootstrap的模态框自定义方法 ajax在django里面实现post提交 ajax提交数据嵌套 1.事件代理 之前写 ...
- 使用ffmpeg视频编码过程中踩的一个坑
今天说说使用ffmpeg在写视频编码程序中踩的一个坑,这个坑让我花了好多时间,回头想想,非常多时候一旦思维定势真的挺难突破的.以下是不对的编码结果: ...
随机推荐
- 月光宝盒(vivo流量录制回放平台)正式对外开源
作者:vivo 互联网服务器团队- Liu Yanjiang 月光宝盒是一个基于流量录制回放的自动化测试平台,通过录制回放取代编写脚本进行自动化回归,提升测试效率和覆盖率.因为其解决方案具有很强的通用 ...
- Python3.8环境安装PyHook3
Python3.8环境安装PyHook3 1. 安装python对应版本的pyhook3网 址:https://pypi.org/project/PyHook3/#files如果没有对应版本,请下载 ...
- [Linux]Linux大文件已删除,但df查看已使用的空间并未减少解决【待续】
1 问题描述 X 参考文献 Linux大文件已删除,但df查看已使用的空间并未减少解决 - ChinaUnix linux磁盘空间未及时释放 - 博客园 linux磁盘目录占用空间分析工具之ncdu ...
- [Linux]Xshell连接Centos7能Ping通但无法连接问题[ssh(d)+firewalld/iptables+chkconfig]
一 方案与思路 0 xshell客户端监测是否能够ping通目标服务器. 前提:知晓目标服务器IP地址 Linux: ifconfig -a Windows: ipconfig -a 1 利用fire ...
- pnpm 之降本增效
作者:京东科技 于振京 受众简介 前端研发工程师 还在为npm i安装大量依赖等待时间较长,npm扁平化node_modules依赖版本冲突在苦恼吗,不用苦恼pnpm为你保驾护航 主要影响:安装依赖包 ...
- 开心档之MySQL 连接
MySQL 连接 使用mysql二进制方式连接 您可以使用MySQL二进制方式进入到mysql命令提示符下来连接MySQL数据库. 实例 以下是从命令行中连接mysql服务器的简单实例: [root@ ...
- Appuploader安装指南
转载:http://kxdang.com/topic/appuploader/install.html 下载和安装appuploader IOS开发工具官网地址 http://www.applicat ...
- 【opencv-c++】4.1-4.2 图像和大型数组类型
4.1-4.2 图像和大型数组类型 动态可变的存储 我们将进入大型数组类型的世界,它们之中最主要的当属c v::Mat,这个结构可以视为是OpenCV所有C++实现的核心,OpenCV所有主要函数都或 ...
- 解析草稿-造价管理-工程经济-P190-例4.2.3
原题 计算步骤 需要记忆的概念 excel计算文件 [腾讯文档]例题
- Grafana系列-统一展示-7-ElasticSearch数据源
系列文章 Grafana 系列文章 ElasticSearch 数据源 Grafana内置了对Elasticsearch的支持.你可以进行多种类型的查询,以可视化存储在Elasticsearch中的日 ...