服务公告

服务公告 > 综合新闻 > Memcached:故障排查

Memcached:故障排查

发布时间:2026-04-25 16:01

一、前言

搞过的人都知道,最烦的是Memcached挂了但应用层面才感知到延迟爆炸,等你反应过来都不知道从哪查起。今天说点实际的,不废话,直接告诉你怎么在生产环境里快速定位Memcached故障,从进程状态到内存分配到连接问题,一条链路撸到底。

二、操作步骤

第一步:确认进程还在不在

命令:

ps aux | grep memcached | grep -v grep

预期输出:

memcache 1234 0.2 1.2 524288 45632 ? Sl 10:30 2:45 /usr/bin/memcached -d -p 11211 -u memcache -m 64 -c 8192

如果输出为空,说明进程已经挂了:

systemctl status memcached # CentOS/RHEL 7+ service memcached status # CentOS 6 / Ubuntu

预期输出:

● memcached.service - Memcached Loaded: loaded (/usr/lib/systemd/system/memcached.service; enabled; vendor preset: enabled) Active: active (running) since Tue 2024-01-16 10:30:00 CST; 2h 30min ago Main PID: 1234 (memcached) CGroup: /system.slice/memcached.service └─1234 /usr/bin/memcached -d -p 11211 -u memcache -m 64 -c 8192

第二步:检查端口监听状态

命令:

netstat -tlnp | grep 11211

预期输出:

tcp LISTEN 0 1024 0.0.0.0:11211 0.0.0.0:* 1234/memcached tcp LISTEN 0 1024 [::]:11211 [::]:* 1234/memcached

如果只有IPv6监听,应用连不上,检查是不是绑定问题:

ss -tlnp | grep 11211

第三步:验证基本连接和读写

命令(telnet方式):

telnet localhost 11211

预期输出:

Trying 127.0.0.1... Connected to localhost. Escape character is '^]'.

然后输入stats命令测试:

stats

预期输出(关键指标):

STAT pid 1234 STAT uptime 9025 STAT time 1705401234 STAT version 1.6.12 STAT libevent 2.1.12-stable STAT pointer_size 64 STAT rusage_user 12.345 STAT rusage_system 45.678 STAT curr_connections 15 STAT total_connections 1234 STAT curr_items 4567 STAT bytes 12345678 STAT limit_maxbytes 67108864 STAT evictions 0 ...

或者用nc(Ubuntu常用):

echo "stats" | nc -q 1 127.0.0.1 11211

预期输出:

STAT pid 1234 STAT uptime 9025 ... END

第四步:检查内存使用是否达到上限

在stats输出里重点看这几个指标:

STAT bytes 60000000 STAT limit_maxbytes 67108864 STAT evictions 1234 STAT reclaimed 5678

判断逻辑:

  • bytes ≈ limit_maxbytes:内存满了,会触发evictions导致缓存命中率暴跌
  • evictions > 0且持续增长:说明频繁被踢出缓存对象,这是性能杀手
  • reclaimed > 0:Memcached在回收过期key的空间,说明内存紧张

快速检查命令:

echo "stats items" | nc -q 1 127.0.0.1 11211 | head -20

预期输出:

STAT items:1:number 1234 STAT items:1:number_hot 0 STAT items:1:number_warm 1234 STAT items:1:number_cold 0 STAT items:1:age 3600 STAT items:1:evicted 12 STAT items:1:evicted_time 120 ...

第五步:检查连接数是否超标

命令:

echo "stats" | nc -q 1 127.0.0.1 11211 | grep -E "curr_connections|max_connections"

预期输出:

STAT max_connections 8192 STAT curr_connections 156

如果curr_connections接近max_connections:

  • 应用侧连接池配置有问题
  • 存在大量短连接
  • 连接泄漏(应用代码bug)

查看系统层连接数:

ss -s | grep memcached # 或 netstat -an | grep 11211 | grep ESTABLISHED | wc -l

预期输出:

Total: 158 (kernel 0) TCP: 12 (2) ESTAB: 10 ...

第六步:检查命中率是否正常

命令:

echo "stats" | nc -q 1 127.0.0.1 11211 | grep -E "get_hits|get_misses|cmd_get"

预期输出:

STAT cmd_get 1234567 STAT cmd_set 89012 STAT get_hits 1200000 STAT get_misses 34567 STAT delete_hits 1234 STAT delete_misses 567 ...

计算命中率:

echo "scale=4; 1200000 / 1234567 * 100" | bc

预期输出:

97.2000

低于95%的命中率就要警惕了,可能原因:

  • 缓存key设计不合理
  • 内存不足导致频繁eviction
  • 应用逻辑变化,缓存未预热

第七步:排查网络延迟问题

从应用服务器测试延迟:

echo -e "set test_key 0 60 5\r\nvalue\r\nquit\r\n" | nc -q 1 127.0.0.1 11211

预期输出:

STORED

用python脚本测试多次取平均延迟:

python3 -c " import socket import time s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(('127.0.0.1', 11211)) # 测试set延迟 start = time.time() s.sendall(b'set test_latency 0 60 1\r\nx\r\n') s.recv(1024) print(f'SET延迟: {(time.time()-start)*1000:.2f}ms') # 测试get延迟 start = time.time() s.sendall(b'get test_latency\r\n') s.recv(1024) print(f'GET延迟: {(time.time()-start)*1000:.2f}ms') s.close() "

预期输出:

SET延迟: 0.35ms GET延迟: 0.28ms

延迟超过5ms就要检查:

  • 网络链路
  • CPU竞争(其他进程占用CPU)
  • 大量小对象导致IO次数过多

第八步:检查日志(如果有配置)

CentOS/RHEL默认日志路径:

/var/log/memcached

Ubuntu默认日志路径:

/var/log/memcached.log

或者查看systemd日志:

journalctl -u memcached -n 50 --no-pager

预期输出:

Jan 16 10:30:00 server01 systemd[1]: Started Memcached Server. Jan 16 12:00:00 server01 memcached[1234]: Accepting connections on port 11211

三、常见问题FAQ

Q1:stats命令正常,但应用连不上,报Connection Refused

老手解答:这不是Memcached的问题,是绑定地址的问题。Memcached默认只监听localhost,你从远程连肯定连不上。

检查当前配置:

netstat -tlnp | grep memcached

如果看到:

tcp LISTEN 127.0.0.1:11211 0.0.0.0:* 1234/memcached

说明只监听了127.0.0.1,需要改成监听所有地址或指定IP:

vim /etc/sysconfig/memcached # CentOS/RHEL # 修改 OPTIONS="-l 0.0.0.0" # Ubuntu vim /etc/memcached.conf # 修改 -l 0.0.0.0

⚠️ 警告:监听0.0.0.0之前必须确保iptables/防火墙已配置,否则裸奔!

Q2:Memcached进程突然挂了,没有core dump,怎么查原因?

老手解答:OOM Killer干掉的,先查系统日志:

dmesg | grep -i memcached

预期输出:

[12345.678901] memcached[1234]: segfault at 7f1234567890 ip 00007f1234567890 sp 00007fff12345678 error 4 in libevent-2.1.so.6

或者:

[12345.678901] Out of memory: Killed process 1234 (memcached) total-vm:2048000kB, anon-rss:2048000kB

如果是OOM,解决方案:

  • 减少Memcached的-m参数(内存)
  • 增加系统vm.overcommit_memory=1
  • 或者机器加内存

如果是segfault,升级Memcached版本或者libevent版本。

Q3:内存还有余量,但evictions一直在涨,什么鬼?

老手解答:你设置的max_item_size太小了,大对象直接被拒,客户端那边以为是eviction。

检查当前配置:

memcached -h | grep -i max

默认max_item_size是1MB(1048576 bytes),如果你的对象超过这个大小:

  • 要么分割对象
  • 要么加大限制:启动时加-I参数,如memcached -I 10m

另一个坑:slab预分配问题。查看stats slab:

echo "stats slabs" | nc -q 1 127.0.0.1 11211

看看各slab的利用率是否均衡,如果某个slab 100%利用而其他空闲很多,说明对象大小分布不均,考虑调整-f factor参数重新分配slab。

Q4:服务重启后缓存全空,命中率归零,怎么处理?

老手解答:Memcached设计就是无持久化的,重启即清空,这是正常行为,不是故障。

如果想平滑过渡:

  • 滚动重启:先起新实例,等缓存预热完成再停老实例
  • 或者接受冷启动的峰值,在应用层加本地缓存兜底
  • 长期方案:考虑Redis Cluster或者Memcached集群做高可用

核心原则:Memcached就是用来丢数据的,重启前要想清楚业务能否接受冷启动。

四、总结

核心要点

  • 进程在不在 → ps + systemctl status
  • 端口通不通 → netstat -tlnp
  • 服务健康否 → echo "stats" | nc localhost 11211
  • 内存满了没 → bytes vs limit_maxbytes,evictions是否增长
  • 连接超没超 → curr_connections vs max_connections
  • 命中率正常否 → get_hits / cmd_get,应该在95%以上
  • 延迟大不大 → 本地测试单次操作应该在1ms以内

排障思路总结

从外向内查:网络层(端口监听) → 进程层(进程状态) → 服务层(stats命令) → 资源层(内存/连接/命中率)。大多数问题在前三层就能定位。

延伸阅读

上一篇: Nmap:脚本

已经是最后一篇啦!