Memcached监控与调试 #

一、监控概述 #

1.1 为什么需要监控 #

text
监控的重要性:

1. 性能优化
   - 发现性能瓶颈
   - 优化配置参数

2. 故障预警
   - 提前发现问题
   - 避免服务中断

3. 容量规划
   - 了解资源使用
   - 合理规划扩容

4. 问题排查
   - 快速定位问题
   - 提供诊断信息

1.2 监控指标 #

text
关键监控指标:

1. 性能指标
   - QPS(每秒查询数)
   - 命中率
   - 响应时间

2. 资源指标
   - 内存使用率
   - 连接数
   - CPU使用率

3. 业务指标
   - 数据量
   - 淘汰次数
   - 错误率

二、stats命令详解 #

2.1 stats - 基本信息 #

bash
# 查看所有统计信息
stats

# 输出示例
STAT pid 1234                    # 进程ID
STAT uptime 123456               # 运行时间(秒)
STAT time 1704067200             # 当前时间(Unix时间戳)
STAT version 1.6.29              # 版本号
STAT libevent 2.1.12-stable      # libevent版本
STAT pointer_size 64             # 指针大小(位)
STAT rusage_user 123.456         # 用户态CPU时间
STAT rusage_system 234.567       # 内核态CPU时间
STAT max_connections 1024        # 最大连接数
STAT curr_connections 10         # 当前连接数
STAT total_connections 1000      # 总连接数
STAT connection_structures 20    # 连接结构数
STAT cmd_get 10000               # get命令次数
STAT cmd_set 5000                # set命令次数
STAT cmd_flush 10                # flush命令次数
STAT cmd_touch 100               # touch命令次数
STAT get_hits 8000               # 命中次数
STAT get_misses 2000             # 未命中次数
STAT delete_misses 100           # delete未命中次数
STAT delete_hits 50              # delete命中次数
STAT incr_misses 20              # incr未命中次数
STAT incr_hits 80                # incr命中次数
STAT decr_misses 10              # decr未命中次数
STAT decr_hits 40                # decr命中次数
STAT cas_misses 5                # cas未命中次数
STAT cas_hits 15                 # cas命中次数
STAT cas_badval 3                # cas失败次数
STAT touch_hits 50               # touch命中次数
STAT touch_misses 10             # touch未命中次数
STAT auth_cmds 0                 # 认证命令次数
STAT auth_errors 0               # 认证失败次数
STAT bytes_read 1000000          # 读取字节数
STAT bytes_written 2000000       # 写入字节数
STAT limit_maxbytes 67108864     # 最大内存限制
STAT accepting_conns 1           # 是否接受连接
STAT listen_disabled_num 0       # 监听禁用次数
STAT threads 4                   # 线程数
STAT conn_yields 0               # 连接让出次数
STAT hash_power_level 16         # 哈希表大小级别
STAT hash_bytes 524288           # 哈希表大小
STAT hash_is_expanding 0         # 哈希表是否扩展
STAT slab_reassign_rescues 0     # Slab重新分配救援次数
STAT slab_reassign_chunk_rescues 0
STAT slab_reassign_evictions_nomem 0
STAT slab_reassign_inline_reclaim 0
STAT slab_reassign_busy_items 0
STAT slab_reassign_busy_deletes 0
STAT slab_reassign_running 0     # Slab重新分配是否运行
STAT slabs_moved 0               # 移动的Slab数
STAT lru_hits 0                  # LRU命中次数
STAT lru_tail_repairs 0          # LRU尾部修复次数
STAT moves_to_cold 0             # 移动到冷数据次数
STAT moves_to_warm 0             # 移动到热数据次数
STAT moves_within_lru 0          # LRU内部移动次数
STAT direct_reclaims 0           # 直接回收次数
STAT lru_bumps_dropped 0         # LRU丢弃次数
END

2.2 stats slabs - Slab统计 #

bash
# 查看Slab统计
stats slabs

# 输出示例
STAT 1:chunk_size 96             # Chunk大小
STAT 1:chunks_per_page 10922     # 每页Chunk数
STAT 1:total_pages 1             # 总页数
STAT 1:total_chunks 10922        # 总Chunk数
STAT 1:used_chunks 100           # 已用Chunk数
STAT 1:free_chunks 10822         # 空闲Chunk数
STAT 1:free_chunks_end 0         # 末尾空闲Chunk数
STAT 1:get_hits 5000             # get命中次数
STAT 1:cmd_set 2000              # set命令次数
STAT 1:delete_hits 50            # delete命中次数
STAT 1:incr_hits 10              # incr命中次数
STAT 1:decr_hits 5               # decr命中次数
STAT 1:cas_hits 3                # cas命中次数
STAT 1:cas_badval 2              # cas失败次数
STAT 1:touch_hits 20             # touch命中次数
STAT active_slabs 1              # 活跃Slab数
STAT total_malloced 1048576      # 已分配内存
END

2.3 stats items - Item统计 #

bash
# 查看Item统计
stats items

# 输出示例
STAT items:1:number 100          # Item数量
STAT items:1:age 3600            # 最老Item年龄
STAT items:1:evicted 0           # 淘汰次数
STAT items:1:evicted_nonzero 0   # 非零过期淘汰次数
STAT items:1:evicted_time 0      # 最后淘汰时间
STAT items:1:outofmemory 0       # 内存不足次数
STAT items:1:tailrepairs 0       # 尾部修复次数
STAT items:1:reclaimed 0         # 回收次数
STAT items:1:expired_unfetched 0 # 过期未获取次数
STAT items:1:evicted_unfetched 0 # 淘汰未获取次数
STAT items:1:evicted_active 0    # 活跃淘汰次数
STAT items:1:crawler_reclaimed 0 # 爬虫回收次数
STAT items:1:crawler_items_checked 0
STAT items:1:lrutail_reflocked 0
STAT items:1:moves_to_cold 0
STAT items:1:moves_to_warm 0
STAT items:1:moves_within_lru 0
STAT items:1:direct_reclaims 0
STAT items:1:hits_to_hot 0
STAT items:1:hits_to_warm 0
STAT items:1:hits_to_cold 0
STAT items:1:hits_to_temp 0
END

2.4 stats sizes - 数据大小分布 #

bash
# 查看数据大小分布
stats sizes

# 输出示例
STAT 96 50                       # 96字节的数据有50个
STAT 120 30                      # 120字节的数据有30个
STAT 152 20                      # 152字节的数据有20个
STAT 192 10                      # 192字节的数据有10个
END

2.5 stats conns - 连接统计 #

bash
# 查看连接统计(需要启用)
stats conns

# 输出示例
STAT 10:addr_tcp 127.0.0.1:12345
STAT 10:state conn_read
STAT 10:secs_since_last_cmd 0
END

三、监控工具 #

3.1 memcached-tool #

bash
# 查看统计信息
memcached-tool 127.0.0.1:11211 stats

# 查看Slab信息
memcached-tool 127.0.0.1:11211 display

# 输出示例
  #  Item_Size  Max_age   Pages   Count   Full?  Evicted Evict_Time OOM
  1     96B      3600s       1     100     no        0        0    0
  2     120B     3600s       1      50     no        0        0    0
  3     152B     3600s       1      30     no        0        0    0

# 导出数据
memcached-tool 127.0.0.1:11211 dump

# 输出示例
add key1 0 3600 5
hello
add key2 0 3600 5
world

3.2 memcstat #

bash
# 查看统计信息
memcstat --servers=127.0.0.1:11211

# 查看多个服务器
memcstat --servers=127.0.0.1:11211,127.0.0.1:11212

# 输出示例
Server: 127.0.0.1 (11211)
     pid: 1234
     uptime: 123456
     time: 1704067200
     version: 1.6.29
     ...

3.3 nc命令 #

bash
# 发送命令
echo "stats" | nc 127.0.0.1 11211

# 获取特定统计
echo "stats slabs" | nc 127.0.0.1 11211

# 获取数据
echo "get key" | nc 127.0.0.1 11211

四、监控脚本 #

4.1 基础监控脚本 #

bash
#!/bin/bash
# monitor_memcached.sh

HOST="127.0.0.1"
PORT="11211"

# 获取统计信息
stats=$(echo "stats" | nc $HOST $PORT)

# 解析数据
get_hits=$(echo "$stats" | grep "STAT get_hits" | awk '{print $3}')
get_misses=$(echo "$stats" | grep "STAT get_misses" | awk '{print $3}')
curr_connections=$(echo "$stats" | grep "STAT curr_connections" | awk '{print $3}')
bytes=$(echo "$stats" | grep "STAT bytes " | awk '{print $3}')
limit_maxbytes=$(echo "$stats" | grep "STAT limit_maxbytes" | awk '{print $3}')
cmd_get=$(echo "$stats" | grep "STAT cmd_get" | awk '{print $3}')
cmd_set=$(echo "$stats" | grep "STAT cmd_set" | awk '{print $3}')
evictions=$(echo "$stats" | grep "STAT evictions" | awk '{print $3}')

# 计算指标
if [ $((get_hits + get_misses)) -gt 0 ]; then
    hit_rate=$(echo "scale=2; $get_hits * 100 / ($get_hits + $get_misses)" | bc)
else
    hit_rate=0
fi

mem_usage=$(echo "scale=2; $bytes * 100 / $limit_maxbytes" | bc)

# 输出结果
echo "================================"
echo "Memcached监控报告"
echo "================================"
echo "时间: $(date '+%Y-%m-%d %H:%M:%S')"
echo "--------------------------------"
echo "性能指标:"
echo "  命中率: ${hit_rate}%"
echo "  GET请求数: $cmd_get"
echo "  SET请求数: $cmd_set"
echo "--------------------------------"
echo "资源指标:"
echo "  内存使用率: ${mem_usage}%"
echo "  已用字节: $bytes"
echo "  最大字节: $limit_maxbytes"
echo "  当前连接数: $curr_connections"
echo "--------------------------------"
echo "业务指标:"
echo "  淘汰次数: $evictions"
echo "================================"

4.2 持续监控脚本 #

bash
#!/bin/bash
# continuous_monitor.sh

HOST="127.0.0.1"
PORT="11211"
INTERVAL=5

echo "开始监控Memcached (每${INTERVAL}秒刷新一次)"
echo "按Ctrl+C停止"
echo ""

while true; do
    # 获取统计信息
    stats=$(echo "stats" | nc $HOST $PORT)
    
    # 解析数据
    get_hits=$(echo "$stats" | grep "STAT get_hits" | awk '{print $3}')
    get_misses=$(echo "$stats" | grep "STAT get_misses" | awk '{print $3}')
    curr_connections=$(echo "$stats" | grep "STAT curr_connections" | awk '{print $3}')
    bytes=$(echo "$stats" | grep "STAT bytes " | awk '{print $3}')
    limit_maxbytes=$(echo "$stats" | grep "STAT limit_maxbytes" | awk '{print $3}')
    
    # 计算指标
    if [ $((get_hits + get_misses)) -gt 0 ]; then
        hit_rate=$(echo "scale=2; $get_hits * 100 / ($get_hits + $get_misses)" | bc)
    else
        hit_rate=0
    fi
    
    mem_usage=$(echo "scale=2; $bytes * 100 / $limit_maxbytes" | bc)
    
    # 输出
    clear
    echo "Memcached实时监控"
    echo "时间: $(date '+%Y-%m-%d %H:%M:%S')"
    echo "--------------------------------"
    echo "命中率: ${hit_rate}%"
    echo "内存使用率: ${mem_usage}%"
    echo "当前连接数: $curr_connections"
    echo "--------------------------------"
    
    sleep $INTERVAL
done

4.3 Python监控脚本 #

python
#!/usr/bin/env python3
# monitor_memcached.py

import time
import socket
from datetime import datetime

class MemcachedMonitor:
    def __init__(self, host='127.0.0.1', port=11211):
        self.host = host
        self.port = port
    
    def get_stats(self):
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.connect((self.host, self.port))
        sock.send(b"stats\n")
        
        stats = {}
        while True:
            line = sock.recv(1024).decode()
            if line.startswith('END'):
                break
            
            if line.startswith('STAT'):
                parts = line.split()
                key = parts[1]
                value = parts[2]
                stats[key] = value
        
        sock.close()
        return stats
    
    def calculate_metrics(self, stats):
        get_hits = int(stats.get('get_hits', 0))
        get_misses = int(stats.get('get_misses', 0))
        bytes_stored = int(stats.get('bytes', 0))
        limit_maxbytes = int(stats.get('limit_maxbytes', 1))
        
        # 计算命中率
        if get_hits + get_misses > 0:
            hit_rate = get_hits / (get_hits + get_misses) * 100
        else:
            hit_rate = 0
        
        # 计算内存使用率
        mem_usage = bytes_stored / limit_maxbytes * 100
        
        return {
            'hit_rate': round(hit_rate, 2),
            'mem_usage': round(mem_usage, 2),
            'curr_connections': int(stats.get('curr_connections', 0)),
            'cmd_get': int(stats.get('cmd_get', 0)),
            'cmd_set': int(stats.get('cmd_set', 0)),
            'evictions': int(stats.get('evictions', 0))
        }
    
    def print_report(self, metrics):
        print("=" * 50)
        print(f"Memcached监控报告 - {datetime.now()}")
        print("=" * 50)
        print(f"命中率: {metrics['hit_rate']}%")
        print(f"内存使用率: {metrics['mem_usage']}%")
        print(f"当前连接数: {metrics['curr_connections']}")
        print(f"GET请求数: {metrics['cmd_get']}")
        print(f"SET请求数: {metrics['cmd_set']}")
        print(f"淘汰次数: {metrics['evictions']}")
        print("=" * 50)

def main():
    monitor = MemcachedMonitor()
    
    while True:
        stats = monitor.get_stats()
        metrics = monitor.calculate_metrics(stats)
        
        # 清屏
        print("\033[2J\033[H")
        
        monitor.print_report(metrics)
        
        time.sleep(5)

if __name__ == '__main__':
    main()

五、告警配置 #

5.1 告警规则 #

bash
#!/bin/bash
# alert_memcached.sh

HOST="127.0.0.1"
PORT="11211"

# 获取统计信息
stats=$(echo "stats" | nc $HOST $PORT)

# 解析数据
get_hits=$(echo "$stats" | grep "STAT get_hits" | awk '{print $3}')
get_misses=$(echo "$stats" | grep "STAT get_misses" | awk '{print $3}')
bytes=$(echo "$stats" | grep "STAT bytes " | awk '{print $3}')
limit_maxbytes=$(echo "$stats" | grep "STAT limit_maxbytes" | awk '{print $3}')
evictions=$(echo "$stats" | grep "STAT evictions" | awk '{print $3}')
curr_connections=$(echo "$stats" | grep "STAT curr_connections" | awk '{print $3}')
max_connections=$(echo "$stats" | grep "STAT max_connections" | awk '{print $3}')

# 计算指标
if [ $((get_hits + get_misses)) -gt 0 ]; then
    hit_rate=$(echo "scale=2; $get_hits * 100 / ($get_hits + $get_misses)" | bc)
else
    hit_rate=0
fi

mem_usage=$(echo "scale=2; $bytes * 100 / $limit_maxbytes" | bc)
conn_usage=$(echo "scale=2; $curr_connections * 100 / $max_connections" | bc)

# 告警检查
ALERTS=()

# 命中率告警
if [ $(echo "$hit_rate < 80" | bc) -eq 1 ]; then
    ALERTS+=("警告:命中率低于80% (当前: ${hit_rate}%)")
fi

# 内存使用率告警
if [ $(echo "$mem_usage > 90" | bc) -eq 1 ]; then
    ALERTS+=("警告:内存使用率超过90% (当前: ${mem_usage}%)")
fi

# 连接数告警
if [ $(echo "$conn_usage > 80" | bc) -eq 1 ]; then
    ALERTS+=("警告:连接数使用率超过80% (当前: ${conn_usage}%)")
fi

# 淘汰告警
if [ $evictions -gt 1000 ]; then
    ALERTS+=("警告:淘汰次数过多 (当前: $evictions)")
fi

# 发送告警
if [ ${#ALERTS[@]} -gt 0 ]; then
    echo "Memcached告警报告 - $(date '+%Y-%m-%d %H:%M:%S')"
    echo "================================"
    for alert in "${ALERTS[@]}"; do
        echo "$alert"
    done
    
    # 这里可以添加发送邮件、短信等通知逻辑
    # send_email "${ALERTS[@]}"
fi

5.2 集成Prometheus #

yaml
# prometheus.yml
scrape_configs:
  - job_name: 'memcached'
    static_configs:
      - targets: ['localhost:9150']

# 使用memcached_exporter
# https://github.com/prometheus/memcached_exporter

5.3 集成Grafana #

text
Grafana Dashboard配置:

1. 数据源:Prometheus
2. 面板配置:
   - 命中率
   - 内存使用率
   - 连接数
   - QPS
   - 淘汰次数

推荐Dashboard:
- https://grafana.com/grafana/dashboards/3746

六、调试技巧 #

6.1 连接调试 #

bash
# 使用telnet连接
telnet 127.0.0.1 11211

# 测试命令
stats
version
quit

# 使用nc连接
nc 127.0.0.1 11211

# 测试UDP连接
nc -u 127.0.0.1 11211

6.2 数据调试 #

bash
# 查看特定键
get key

# 查看键和CAS ID
gets key

# 查看所有键(不推荐,数据量大时会很慢)
stats cachedump 1 0

# 查看特定Slab的键
stats cachedump 1 100

6.3 性能调试 #

bash
# 查看慢查询(需要客户端记录)

# 查看内存使用
stats slabs

# 查看淘汰情况
stats items | grep evicted

# 查看连接状态
stats conns

6.4 日志调试 #

bash
# 启动时开启详细日志
memcached -vv

# 启动时开启最详细日志
memcached -vvv

# 输出到文件
memcached -vv >> /var/log/memcached.log 2>&1

七、故障排查 #

7.1 连接失败 #

bash
# 检查服务是否运行
ps aux | grep memcached

# 检查端口是否监听
netstat -tlnp | grep 11211

# 检查防火墙
sudo ufw status
sudo firewall-cmd --list-all

# 检查SELinux
getenforce

# 测试连接
telnet 127.0.0.1 11211

7.2 性能问题 #

bash
# 查看命中率
stats | grep -E "get_hits|get_misses"

# 查看内存使用
stats | grep -E "bytes|limit_maxbytes"

# 查看淘汰情况
stats items | grep evicted

# 查看连接数
stats | grep -E "curr_connections|max_connections"

# 查看Slab使用
memcached-tool 127.0.0.1:11211

7.3 内存问题 #

bash
# 查看内存使用
stats | grep bytes

# 查看Slab分布
stats slabs

# 查看数据大小分布
stats sizes

# 查看淘汰统计
stats items | grep evicted

# 查看内存碎片
memcached-tool 127.0.0.1:11211

7.4 数据丢失 #

bash
# 检查是否重启
stats | grep uptime

# 检查淘汰
stats items | grep evicted

# 检查过期时间
get key

# 检查flush_all
stats | grep cmd_flush

八、总结 #

监控要点:

指标 命令 说明
基本信息 stats 全局统计
Slab信息 stats slabs 内存分配
Item信息 stats items 数据统计
大小分布 stats sizes 数据大小

最佳实践:

  1. 定期监控关键指标
  2. 设置合理的告警阈值
  3. 使用可视化工具
  4. 保存历史数据
  5. 建立故障排查流程

恭喜你完成了Memcached的学习!

最后更新:2026-03-27