首页 / 资讯中心 / 文章详情

Memcached stats命令全解:从命中率告警到容量排查实战

Memcached stats命令全解:从命中率告警到容量排查实战 ★ FEATURED ARTICLE
凌晨两点告警群弹出一条消息订单服务的缓存命中率从 98% 掉到了 60%。登录线上机器第一件事就是执行stats命令屏幕上刷刷刷吐出一整屏字段。很多人这个时候就懵了——get_hits、get_misses、evictions、curr_items都认识但这一堆数字到底怎么串起来看哪些字段才是这次故障的关键线索这篇就把 Memcached 的 stats 命令从头到尾拆一遍。我不打算只给你念字段注释而是结合我实际排查线上问题的经验告诉你每个指标背后的运行逻辑、字段之间的因果关系、遇到具体症状该先看哪几个数顺便从源码角度说说这些计数器是怎么累加的。适合刚接触 Memcached 的运维、后端开发也适合那些已经用了很久但只靠命中率过日子、想深入一点的朋友。1. 一次命中率告警stats 输出里的第一个信号先把那次故障的真实场景放出来。那是一个典型的电商订单缓存集群4 个 Memcached 节点每个 8GB 内存跑了半年多一直很稳。命中率突然下跌不是那种 95% 到 93% 的小波动而是直接腰斩到 60%业务方的第一反应是缓存坏了。我登录上去敲了stats拿到这样一份输出字段做了脱敏但结构真实STAT pid 28314 STAT uptime 864002 STAT time 1710751234 STAT version 1.6.21 STAT libevent 2.1.12-stable STAT pointer_size 64 STAT rusage_user 186.277410 STAT rusage_system 422.175696 STAT max_connections 2048 STAT curr_connections 156 STAT total_connections 8902341 STAT rejected_connections 0 STAT connection_structures 289 STAT reserved_fds 20 STAT cmd_get 482901234 STAT cmd_set 78012345 STAT cmd_flush 12 STAT cmd_touch 88421 STAT get_hits 458990123 STAT get_misses 23911111 STAT get_expired 334567 STAT get_flushed 112 STAT delete_misses 2112 STAT delete_hits 98123 STAT incr_misses 123 STAT incr_hits 4567 STAT decr_misses 45 STAT decr_hits 890 STAT cas_misses 0 STAT cas_hits 0 STAT cas_badval 0 STAT touch_hits 1234 STAT touch_misses 567 STAT auth_cmds 0 STAT auth_errors 0 STAT bytes_read 4321098765 STAT bytes_written 9876543210 STAT limit_maxbytes 1073741824 STAT accepting_conns 1 STAT listen_disabled_num 0 STAT threads 8 STAT conn_yields 42 STAT hash_power_level 28 STAT hash_bytes 134217728 STAT hash_is_expanding 0 STAT slab_reassign_running 0 STAT slabs_scanned 128 STAT lru_crawler_starts 863 STAT lru_maintainer_juggles 0 STAT malloc_fails 0 STAT log_worker_dropped 0 STAT log_worker_written 0 STAT log_watcher_queued 0 STAT log_watchers 0 STAT expired_unfetched 512000 STAT evicted_unfetched 34500 STAT evicted_active 8900 STAT evicted_nonactive 25600 STAT evictions 69000 STAT reclaimed 12800000 STAT reclaimed_from_cache 3456 STAT crawler_reclaimed 456000 STAT expired 990000 STAT bytes 812345678 STAT curr_items 18023456 STAT total_items 456789012 STAT direct_reclaims 0 STAT lrutail_reflocked 77 STAT total_lru_segments 1024 STAT lru_segments_bytes 536870912 STAT bytes_per_worker_thread 109 STAT time_internal 1710751234 END第一次见到这堆东西的人很容易把所有字段按顺序过一遍然后更加困惑。我的习惯是先按模块分组再挑关键字段看。裸stats输出虽然只有几十行但它几乎覆盖了 Memcached 的所有运行维度运行状态、连接、请求量、内存、LRU 淘汰、内部锁和哈希表。每一条都有意义但不是每条都值得在日常巡检里盯。回到那次故障我第一眼重点看了三个数get_misses在总cmd_get里的占比、evictions是不是在涨、curr_items和expired_unfetched的变化趋势。结果发现get_misses占比确实异常升高但evictions并没有突然暴涨说明淘汰导致 miss这个最常见的剧本不成立。顺着get_expired一看这个值飙升到了三十多万——问题出在过期不是内存不足。后来查日志确认那批订单数据的 key 过期时间设成了统一的 24 小时凌晨两点整大批量过期自然全部 miss。这就是 stats 命令的用法本质它不是给你一个好/坏的结论而是给一组互相印证的计数器你要做的是找到哪几个数一起不正常再顺藤摸瓜。1.1 为什么 stats 能成为第一排查手段我遇到过不少同事喜欢直接上memcached-tool、prometheus或者各种管理平台看图表。图表当然好但stats命令有几个不可替代的优势零依赖直连只要 TCP 能通telnet或nc敲一行就能拿到不依赖任何 agent 和 exporter。实时性图表通常有采集周期prometheus 默认 15 秒到 1 分钟但故障现场你要的是当下这一刻的真实状态。原生语义所有指标就是 Memcached 进程自己的计数器不存在采样偏差和口径转换stats给 1 就是 1。所以我不建议完全抛弃 stats 裸命令去依赖监控平台。监控平台负责长时间趋势和告警stats 负责现场取证两者配合才是完整的排查手段。1.2 stats 命令的响应格式细心的读者会发现输出以STAT key value的格式逐行返回最后以END结束。如果你用stats items、stats slabs这些变体行的前缀会变成STAT items:1:number或者STAT 1:chunk_size这种带分组的格式。理解这个格式对写脚本解析很有帮助后面第 6 章我会给一个实际可用的采集脚本。2. 六个 stats 变体命令先搞清楚手里有哪些工具很多文章会把 stats 当成一个命令讲完就结束但实际生产环境里裸 stats 经常不够用。你看到evictions涨了想知道是哪个 slab class 在淘汰你看到内存还有余额但curr_items涨不动了想确认是不是 chunk 分配不均——这些都要靠变体命令。2.1 裸 stats全局体检裸 stats 是入口给你一个整体画像。它的核心价值在于快速回答三个问题进程活着吗、内存满没满、读多写多的基本盘是什么样。别小看这三个问题我处理过好几起事故最后发现 root cause 只是某个节点进程被 OOM killer 杀了客户端还连着一个半死不活的端口。2.2 stats items按 slab class 拆解条目状态stats items的输出长这样STAT items:1:number 12345 STAT items:1:age 34567 STAT items:1:evicted 12 STAT items:1:evicted_nonzero 3 STAT items:1:evicted_time 0 STAT items:1:outofmemory 0 STAT items:1:tailrepairs 0 STAT items:1:reclaimed 2345 STAT items:1:expired_unfetched 67 STAT items:1:evicted_unfetched 8 STAT items:1:crawler_reclaimed 345 ... END这里的信息比裸 stats 细得多。比如items:1:evicted和items:1:evicted_time可以告诉你这个 slab class 多久前发生过淘汰age则反映了这个 class 里条目最老的存活时间。排查热 key 和过期风暴时stats items是仅次于裸 stats 的第二个必看命令。2.3 stats slabs内存分配的核心视图stats slabs输出每个 slab class 的 chunk 大小、页面数、使用情况STAT 1:chunk_size 96 STAT 1:chunks_per_page 10922 STAT 1:total_pages 256 STAT 1:total_chunks 2796032 STAT 1:used_chunks 123456 STAT 1:free_chunks 2672576 STAT 1:free_chunks_end 0 STAT 1:mem_requested 11851776 ... STAT active_slabs 76 STAT total_malloced 201326592如果你发现bytes没到上限但写入开始抖动多半是某个 slab class 的free_chunks耗尽而另一个 class 有一堆空闲 chunk。这就是 slab 分配不均问题。Memcached 1.4.x 时代只能靠重启解决1.5 有了自动 reassign但也不总尽如人意。stats slabs就是判断这类问题的直接证据。2.4 其他变体cachedump、sizes、reset 与调试类命令这几个变体使用频率低但特定场景很关键stats cachedump slab_id limit导出某个 slab class 里的 key 列表。它是排查 key 分布的工具但有一个大坑——它会锁住被遍历的 item生产环境高并发下慎用我一般只在低峰期针对单个 slab 用而且 limit 控制在 100 以内。stats sizes输出 item 大小分布。注意这个命令不是所有版本默认可用有些发行版需要编译期或启动参数开启线上没有就不要硬试。stats reset重置部分计数器。注意它只能重置部分字段具体哪些不同版本不完全一样而且会清掉你排障时需要的现场累积数据所以我基本不在事故中用它。stats settings返回当前运行配置包括maxbytes、maxconns、threads、evictions开关策略等。做容量评估和配置核对时很有用。stats conns和stats hash前者看每条连接的状态后者看哈希表的扩张情况属于运维深水区的工具日常用不到。我整理了一张速查表方便对照命令核心用途生产环境风险上手难度stats全局状态、快速体检低低stats items条目状态、热 key、过期分析低中stats slabs内存分配、chunk 碎片分析低中stats cachedump导出指定 slab 的 key 列表高阻塞遍历中stats sizesitem 大小分布依版本而定低stats reset重置计数器高破坏现场数据低stats settings查看运行时配置低低3. 核心字段逐项拆解这些数字背后对应的是哪个模块这一章我把裸 stats 的字段按模块拆开讲。不追求一个不落地全列而是讲懂那些真正影响诊断判断的以及容易被误读的。3.1 运行状态组pid 到 timepid、version、ptr_size、uptime、time这五个是一眼就能确认这进程是不是我认识的那个的字段。我见过有人在多实例环境下搞混了端口对应的进程看了pid才发现连错了节点。uptime和time要配合看uptime是从启动到现在的秒数但如果uptime很小说明进程刚重启过之前的计数器全部清零很多指标异常其实只是重启后的低基数效应。rusage_user和rusage_system是 CPU 累积时间不能直接看成进程当前 CPU 占用要看趋势变化。libevent版本也很值得扫一眼因为 libevent 的 bug 曾经在不同版本上引发过连接异常版本不匹配时排查链路会被带偏。3.2 连接与线程curr_connections 到 threadcurr_connections是当前活动连接数total_connections是历史累计rejected_connections是被拒绝的连接数。注意max_connections是配置上限但裸 stats 里通常不直接给要看stats settings里的maxconns。这里最容易踩的坑是curr_connections正常不代表没问题。如果有客户端反复创建短连接total_connections会涨得飞快curr_connections反而不高这种模式下 TCP 握手开销会把 CPU 打满。所以两个数要一起看。reserved_fds是 Memcached 为内部用途保留的文件描述符数量。listen_disabled_num是一个被我称为沉默杀手的字段当连接数达到maxconns时Memcached 会暂时关闭监听客户端表现为连接超时而它对应的计数器就是这个值在涨。如果你看到listen_disabled_num从 0 变成正数别犹豫连接数已经撞顶了。threads是 worker 线程数默认 4波动正常。conn_yields表示连接让出 CPU 的次数它偏高说明有连接长期占用 worker 线程常见原因是单个超大 value 的读取或输出缓冲挤压导致其他请求排队但表面上看不见只能从conn_yields和平均响应时间变差来反推。3.3 命令统计与命中率cmd_get 到 cas_badvalcmd_get、cmd_set、cmd_flush、cmd_touch分别记录各类命令的执行次数。这组数据直接反映了读写比例。如果一个缓存集群cmd_set和cmd_get几乎一样多先别高兴这意味着缓存层没有发挥什么读加速作用业务可能把 Memcached 当成存储而不是缓存用。get_hits和get_misses是所有人最熟的两个字段组合起来就是命中率命中率 get_hits / (get_hits get_misses)我见过有人直接拿cmd_get当分母算命中率这是错的——cmd_get是所有 get 类命令的总和包括 gets、touch 等不同版本统计口径可能不一样最稳妥的算法就是用get_hits/(get_hitsget_misses)。get_expired是 1.5 新增的字段专门统计 get 时发现 key 已过期的次数。这个字段用处极大如果你看到命中率跌但evictions没涨同时get_expired在涨那基本可以断定是大量 key 同时过期导致的过期雪崩不需要怀疑内存和淘汰逻辑。delete_hits/delete_misses、incr_hits/incr_misses、cas_*、touch_*这一系列可以当状况指示灯。比如cas_misses突然涨说明业务用 CAS 做并发控制时 key 频繁被改或过期业务逻辑要查。auth_cmds和auth_errors只在启用 SASL 认证后有意义没启用的话一直是 0。3.4 内存与条目bytes 到 total_itemslimit_maxbytes是内存上限单位字节。bytes是当前用于存储的字节数注意它不完全等于 Memcached 进程的 RSS因为进程还要为了元数据、空闲 chunk 预留空间。curr_items是当前存储的 key 条数total_items是历史累计写入成功次数。这两个的配合价值在于判断剩余空间的质量。bytes接近limit_maxbytes但curr_items不高可能是有很多大 value 存在反过来curr_items涨不动但bytes也没满常见原因是被删除或过期的 item 还没被后台线程真正回收内存呈假性空闲。hash_power_level和hash_bytes描述哈希表大小。当curr_items很大时哈希表会自动扩容hash_is_expanding表示正在扩容中。这两个字段异常通常意味着条目规模远超预期配合curr_items一起看才算完整。我记得有一次某台机器hash_bytes占了 300MB一查curr_items已经上亿业务其实根本不该把那么多 key 塞进缓存。3.5 淘汰、过期与 LRU 回收进出之间的生死账这一组是我最喜欢的部分也是最能体现 Memcached 内部设计的地方。evictions是历史淘汰总次数。注意了淘汰不等于过期。Memcached 内存满后即使 item 还没过期也会按 LRU 策略把最久没访问的 item 腾出来给新数据用那次腾挪就记一次evictions。evictions持续增长几乎可以肯定是内存不足。reclaimed表示新数据写入时直接复用了某一个已经被标记删除或已过期 item 的内存。这个字段很多人忽略但它是 Memcached 的高效之处内存满了也可以不淘汰而通过回收过期 item 续命。crawler_reclaimed是 LRU 爬虫后台线程主动扫描并回收的过期条目数。expired是累计过期的条目数包括还没被访问但已经被后台线程判定过期的。evicted_active和evicted_nonactive是 1.5 才明确区分开的淘汰计数evicted_active表示被淘汰的条目在被淘汰前还在被访问热数据被误伤evicted_nonactive表示淘汰的是很久没人碰的冷数据。这个区分太重要了。如果evicted_active占比高说明缓存容量已经小到连热数据都留不住扩容是唯一解如果大部分是evicted_nonactive说明你的热数据集合和内存容量根本不匹配更可能是 key 设计或 TTL 策略问题。expired_unfetched和evicted_unfetched则指那些过期了或淘汰了但从未被读取过的条目。这两个值巨高意味着大量写进去的 key 从生到死没人读过一次——业务在往缓存里写垃圾。lrutail_reflocked是 LRU 尾部 item 被引用锁定的次数偏高说明存在长尾竞态多数情况下不需要处理但你可以知道它不是故障直接原因。3.6 内部机制与冷门字段slab_reassign_running表示 slab 自动重分配是否正在执行slabs_scanned统计扫描过的 slab 数量。lru_crawler_starts是 LRU 爬虫自启动以来的执行次数。malloc_fails如果大于 0说明系统内存严重不足malloc 都失败了这个值出现就别分析了准备迁移或扩容。1.6.x 还多了total_lru_segments、lru_segments_bytes、bytes_per_worker_thread这类字段它们描述的是新 LRU 分段机制的运行状态日常监控不需要盯知道是干嘛的就行。accepting_conns只有 1 或 01 表示正常接受连接0 表示因为达到 maxconns 而暂停监听。这和listen_disabled_num是同一个故事的两种表达。用一张表把核心字段和模块对应关系收一下模块关键字段一句话判断运行状态uptime, version, rusage_user进程是否活着是否刚重启连接curr_connections, rejected_connections, listen_disabled_num连接是否撞上限命令/命中cmd_get, cmd_set, get_hits, get_misses, get_expired命中率与请求构成内存/条目bytes, limit_maxbytes, curr_items容量水位淘汰/过期evictions, evicted_active, reclaimed, crawler_reclaimed, expired是内存不足还是过期风暴4. 用 stats 做诊断四个高频问题的定位链路这一章是全文的核心实操部分。我挑四个最常见的线上症状把完整的排查链路走一遍每步先说看什么再说怎么看最后给结论和处置思路。4.1 症状一命中率突然下跌开场那个订单服务案例就是典型。完整链路应该是先用裸 stats 算当前命中率确认不是误报get_hits/(get_hitsget_misses)。再看evictions。如果evictions也在涨且bytes非常接近limit_maxbytes基本可以判断是内存不足导致的被动淘汰跳到 4.2 处理。如果evictions没涨再看get_expired。这个值突然飙升说明大量 key 在同一时间窗口过期业务侧检查 TTL 设置是不是齐刷刷的一刀切。如果get_expired也没有异常看delete_hits和delete_misses。delete_hits突然变多可能是有个定时任务在批量删 key。以上都不是用stats items看具体哪个 slab class 的expired_unfetched在涨定位到底是哪类 value 大小的 key 出了问题。我在实际处理中发现第 2 步和第 3 步可以覆盖大约 80% 的命中率下降场景。剩下的 20% 里有一半是业务代码改了 key 命名规则导致缓存形同虚设另一半才是稀奇古怪的内部问题。4.2 症状二evictions 持续上涨内存见顶evictions持续上涨是最典型的容量告警。先算空间账剩余可用内存 limit_maxbytes - bytes但这个账有个坑bytes只统计了数据部分Memcached 的 slab 分配器已经把内存按 chunk 切好了所以即使bytes看起来还有富余你也不一定能写进新的 item——你得看stats slabs里对应 slab class 的free_chunks是不是已经归零。完整链路裸 stats 看evictions、bytes、curr_items。stats slabs看全局active_slabs和各 slab class 的free_chunks分布。如果总内存明明没满但某个 class 满了看evicted_active占比判断淘汰的是热数据还是冷数据。配置了自动 slab reassign 的情况下观察slab_reassign_running是不是长期为 1——长期为 1 说明重分配线程一直在忙但可能收益不大。处置上如果热数据被淘汰扩容优先如果只是冷数据被淘汰那缓存可能还没到真正危险的时候但需要规划 key 的 TTL 和容量。这里有个常见误判看到evictions涨就以为要扩容。其实可以先手动执行lru_crawler相关操作触发爬虫扫描把已经过期但还占着内存的条目清掉。Memcached 的爬虫默认周期可能偏长如果你发现expired值和crawler_reclaimed之间存在巨大差额说明过期条目积压了这时候让爬虫跑一轮往往能腾出不少空间扩容可以再等等。4.3 症状三连接数异常攀升连接数问题不像内存问题那么显眼但破坏力更大。我遇到过一次total_connections每分钟涨上千最后把maxconns打满新请求全部超时。完整链路裸 stats 看curr_connections、total_connections、rejected_connections。如果rejected_connections和listen_disabled_num都在涨说明已经触顶。stats conns可以列出每条连接的状态看看是不是有大量连接处于closing或者长时间活跃。再看看conn_yields。如果这个值持续增长说明连接处理在频繁让出 CPU大 value 读写的嫌疑很大。处置上客户端连接池必须设置合理的最小/最大连接数禁止每次请求都新建连接。像 Memcached 这种内存缓存本来吞吐就高短连接的开销是不可接受的。关于阈值我的经验是curr_connections到了maxconns的 80% 就要开始关注了因为 Memcached 的连接处理是事件驱动模型峰值到来时连接数会瞬间再上一个台阶真等到撞顶再处理业务已经被拖垮了。4.4 症状四热 key 与 slab 分配不均这一类属于慢性病平时不致命但会在某个流量高峰突然爆发。链路如下stats items看每个 slab class 的age。age很大比如几十万秒的 class 里大概率躺着热 key因为只有反复被访问的 key 才会在 LRU 里活那么久。stats cachedump进一步导出这个 slab 的 key 列表找出那几个明显异常的 key。这里再次提醒生产环境高并发下慎用尽量低峰期快速操作。stats slabs看各 slab class 的used_chunks和free_chunks比例。如果某个 class 分配了大量页面但used_chunks很低说明 chunk 尺寸设计不合理。处置上热 key 的常规解法是本地缓存分层比如应用内再套一层 Caffeine/LRU Map把高频读挡在进程内部而不是反复打 Memcached。slab 分配不均则需要分析 value 大小分布必要时在业务侧统一 value 尺寸或者干脆调整-Islab 页面大小等启动参数。5. 源码层面的印证计数器在哪里累加、版本为什么有差异光会看字段还不够理解这些数字在源码里怎么攒出来的能帮你避免很多误判。这一章我结合 Memcached 源码以 1.6.x 为主讲几个关键点。5.1 process_stats_command一次 stats 请求的处理路径当你敲下stats命令服务端走的是process_stats_command这个函数。它在stats.c里逻辑不算复杂根据命令子类型裸 stats、items、slabs 等调用不同的收集函数把结果写到输出缓冲最后追加END标识。这里有个值得知道的细节Memcached 为了性能计数器不是每线程一个全局锁互斥更新的而是使用了按线程划分的本地计数器thread_stats请求处理线程各自累加自己的副本在stats命令需要输出时会进行处理和汇总。这意味着你在高并发瞬间抓取的 stats 数值可能有一两秒级别的窗口误差但它本身也是最终一致汇总的结果不影响诊断判断。5.2 几个核心计数器的累加位置cmd_get、get_hits和get_misses的累加发生在请求处理函数中。process_get_command在收到 get 请求后先查找哈希表再由do_item_get判断 item 是否存在、是否过期。命中和未命中就在这两个函数的不同分支里分别加一。这个顺序解释了为什么get_expired这个字段有意义Memcached 在检查 item 时发现 key 已过期会额外记录一次expired_unfetched并在 get 层面记为 miss。evictions的累加位置比较隐蔽——它不在 get 路径上而在内存分配路径上。当新的 item 要分配内存而 slab 分配器找不到可用 chunk 时会从 LRU 尾部踢掉一个 item这个踢人的动作才让evictions加一。所以看到evictions上涨真正的含义是写请求触发了内存回收这和我们直觉中的缓存满了其实是同一个意思。reclaimed和crawler_reclaimed的区别在于回收者不同。reclaimed是普通写路径上顺手回收的过期/可复用 itemcrawler_reclaimed是后台 LRU 爬虫线程主动扫描回收的。理解这个区别就知道为什么两者差距大时要注意——说明过期条目积压了后台线程有点跟不上。5.3 版本差异从 1.4 到 1.6 你看到的字段为什么不一样如果你有台老机器跑 1.4.x另一台跑 1.6.x同一个stats命令输出字段差很多这不是配置问题。1.4.x 的字段里没有get_expired、evicted_active、evicted_nonactive、expired_unfetched、log_*这些排查时只能靠更间接的信号去猜。1.5.x 是字段大扩展的分水岭引入了更细的 LRU 统计和过期统计官方终于承认过期和淘汰是两回事并把这层区别呈现在字段上。1.6.x 又加了日志模块的计数器和 LRU 分段相关字段。所以如果你要写监控脚本强烈建议按版本号做字段适配不要指望同一个解析脚本跑所有节点。我用过最省心的方式是先取version再用条件分支解析。线上混用多版本时这一步能省掉一大堆告警误报。6. 监控和告警落地把 stats 变成自动化巡检的依据最后讲落地。手动排查救急是一回事日常要靠自动化巡检提前发现苗头。6.1 一条命令拿到全部核心指标如果不想引入额外依赖用 nc 就能拉数据。下面这个脚本我实际在用的简化版会在每次采样时抓取关键字段并做简单计算#!/bin/bash MEMCACHED_HOST127.0.0.1 MEMCACHED_PORT11211 stats$(printf stats\r\n | nc -w 2 $MEMCACHED_HOST $MEMCACHED_PORT) get_stat() { echo $stats | awk -v key$1 $2 key {print $3} } get_hits$(get_stat get_hits) get_misses$(get_stat get_misses) evictions$(get_stat evictions) bytes$(get_stat bytes) limit_maxbytes$(get_stat limit_maxbytes) curr_items$(get_stat curr_items) listen_disabled_num$(get_stat listen_disabled_num) hit_rate$(awk -v hits$get_hits -v misses$get_misses BEGIN { if (hits misses 0) print 100; else printf %.2f, hits / (hits misses) * 100 }) mem_usage$(awk -v bytes$bytes -v limit$limit_maxbytes BEGIN { if (limit 0) print 0; else printf %.2f, bytes / limit * 100 }) echo hit_rate$hit_rate mem_usage$mem_usage curr_items$curr_items evictions$evictions listen_disabled_num$listen_disabled_num采集端还能用memcached-tool这类现成工具它对stats items和stats slabs的格式化输出做得不错适合人工阅读但如果你要的是稳定时间序列还是自己解析或上导出器更合适。6.2 该盯哪些指标、阈值怎么定阈值不是随便拍脑袋要跟你自己的业务形态对齐。我给出一个默认起点你可以按实际调整指标计算方式建议阈值说明命中率get_hits/(get_hitsget_misses)低于 90% 持续 5 分钟告警读多写少的缓存不应低于这个数内存水位bytes/limit_maxbytes超过 80% 关注90% 告警给扩容留出操作时间窗口evictions 增量两次采样的数值差连续 3 轮大于 0 告警持续淘汰说明内存已经周期性见顶连接水位curr_connections/maxconns看 settings达到 80% 关注连接暴涨通常很突然listen_disabled_num绝对值大于 0 告警已经撞顶立即处理提醒一点curr_items这个值本身不建议直接设阈值。不同业务的 key 大小差异巨大同样是 1000 万个 key可能占 1GB 也可能占 8GB直接对数量做阈值意义不大。更可靠的做法是对bytes/limit_maxbytes设阈值再辅以evictions增量这两个组合基本能覆盖容量问题。6.3 告警脚本与 prometheus 采集如果是 Prometheus 生态用现成的memcached_exporter就能省掉自己解析 stats 的工作。它默认会抓取裸 stats 和 stats items还提供memcached_command_hits、memcached_command_misses、memcached_evictions_total这些指标直接用 PromQL 算命中率很顺手memcached_get_hits_total / (memcached_get_hits_total memcached_get_misses_total) 0.9不过我个人会保留一个裸脚本做兜底因为当 Memcached 本身都已经出现连接问题或资源耗尽时exporter 也可能采样失败那时远程裸连接反而更能反映真实故障状态。两手准备老话在运维场景永远适用。我个人在把 stats 纳入监控体系之后的体会是告警的价值不在告诉你坏了而在帮你把故障定性从全乱变成是哪一类。命中率跌和 evictions 涨是两种完全不同的处置路径前者多半查业务 TTL后者多半看容量规划。知道先看哪个字段、先做哪个动作比背一百个字段定义都管用。最后再分享一个小技巧每次做完线上排障把当时完整的 stats 输出、做了什么操作、哪个字段先变的、最终根因是什么存成一个文本归档。攒上四五次你就会发现自己对 Memcached 的直觉准了很多——因为 stats 的每个数字背后都是真实运行中的一幕场景见得多了自然就熟了。
阅读完成 · 觉得有帮助?
咨询建站