1. 首页 > Memcached教程 > 正文

Memcached教程FG004-Memcached内存管理机制实战

本文档风哥主要介绍Memcached数据库内存管理机制相关知识,包括Memcached数据库内存管理概述、Slab分配机制原理、Chunk与Page概念、内存规划建议、Slab分析、内存优化、Slab调优、内存泄漏排查、内存碎片处理等内容,风哥教程参考Memcached官方文档Data Storage、Slab Allocation等内容编写,适合DBA人员和运维人员在学习和测试中使用,如果要应用于生产环境则需要自行确认。

Part01-基础概念与理论知识

1.1 Memcached数据库内存管理概述

Memcached采用独特的内存管理机制,不同于传统的malloc/free方式,而是使用Slab Allocation机制来管理内存,有效避免了内存碎片问题。更多视频教程www.fgedu.net.cn

1.1.1 传统内存管理的问题

# 传统内存管理方式(malloc/free)的问题

# 问题1:内存碎片
– 频繁的分配和释放导致内存碎片
– 碎片化严重时无法分配大块内存
– 内存利用率降低

# 问题2:性能问题
– malloc/free系统调用开销大
– 需要遍历空闲链表查找合适块
– 多线程环境下锁竞争严重

# 问题3:内存泄漏
– 忘记释放内存导致泄漏
– 难以追踪和定位泄漏点

# Memcached的解决方案:Slab Allocation
– 预先分配大块内存
– 按大小分类管理
– 避免碎片,提高效率

1.1.2 Slab Allocation机制优势

  • 避免内存碎片:通过固定大小的Chunk分配,消除碎片
  • 高效分配:预分配内存,分配速度快
  • 内存复用:数据删除后内存可立即复用
  • 简单管理:按Slab Class分类管理,逻辑简单

1.2 Memcached数据库Slab分配机制原理

Slab Allocation是Memcached的核心内存管理机制,理解其原理对于优化Memcached性能至关重要。学习交流加群风哥微信: itpux-com

1.2.1 Slab Allocation架构

# Slab Allocation架构图

┌─────────────────────────────────────────────────────────────┐
│ Memcached内存空间 │
│ (由-m参数指定) │
└─────────────────────────────────────────────────────────────┘


┌─────────────────────────────────────────────────────────────┐
│ Slab Class 1 │
│ Chunk Size: 96B │
│ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ │
│ │ Chunk │ │ Chunk │ │ Chunk │ │ Chunk │ … │
│ │ 96B │ │ 96B │ │ 96B │ │ 96B │ │
│ └────────┘ └────────┘ └────────┘ └────────┘ │
└─────────────────────────────────────────────────────────────┘


┌─────────────────────────────────────────────────────────────┐
│ Slab Class 2 │
│ Chunk Size: 120B (96 × 1.25) │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Chunk │ │ Chunk │ │ Chunk │ │ Chunk │ … │
│ │ 120B │ │ 120B │ │ 120B │ │ 120B │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
└─────────────────────────────────────────────────────────────┘


┌─────────────────────────────────────────────────────────────┐
│ Slab Class 3 │
│ Chunk Size: 152B (120 × 1.25) │
│ ┌────────────┐ ┌────────────┐ ┌────────────┐ │
│ │ Chunk │ │ Chunk │ │ Chunk │ … │
│ │ 152B │ │ 152B │ │ 152B │ │
│ └────────────┘ └────────────┘ └────────────┘ │
└─────────────────────────────────────────────────────────────┘




┌─────────────────────────────────────────────────────────────┐
│ Slab Class N │
│ Chunk Size: 最大值(默认1MB) │
└─────────────────────────────────────────────────────────────┘

1.2.2 Slab Class概念

# Slab Class概念详解

# Slab Class定义
– 相同大小Chunk的集合
– 每个Slab Class对应一种Chunk大小
– Chunk大小按增长因子递增

# Slab Class编号
– 从1开始编号
– 编号越小,Chunk越小
– 编号越大,Chunk越大

# 默认Slab Class示例
Class 1: Chunk Size = 96B
Class 2: Chunk Size = 120B (96 × 1.25)
Class 3: Chunk Size = 152B (120 × 1.25)
Class 4: Chunk Size = 192B (152 × 1.25)
Class 5: Chunk Size = 240B (192 × 1.25)

Class 42: Chunk Size = 1MB (最大值)

# 增长因子
– 默认值:1.25
– 可通过-f参数调整
– 影响Slab Class数量和Chunk大小分布

1.3 Memcached数据库Chunk与Page概念

1.3.1 Page概念

# Page概念详解

# Page定义
– 内存分配的基本单位
– 默认大小:1MB
– 可通过-I参数调整

# Page特点
– 从操作系统申请内存的最小单位
– 一个Page被切分成多个相同大小的Chunk
– Page一旦分配,不会释放回操作系统

# Page分配过程
1. Memcached启动时,不预先分配所有内存
2. 当需要存储数据时,申请一个Page
3. 将Page切分成对应大小的Chunk
4. 将Chunk分配给数据使用

# Page相关参数
-I 设置Page大小,默认1MB
最小1KB,最大128MB

1.3.2 Chunk概念

# Chunk概念详解

# Chunk定义
– 存储数据的基本单位
– 固定大小,属于某个Slab Class
– 包含数据和元数据

# Chunk结构
┌────────────────────────────────────────────┐
│ Chunk结构 │
├────────────────────────────────────────────┤
│ Item Header (48 bytes, 默认-n参数) │
│ – Key长度 │
│ – Value长度 │
│ – Flags │
│ – 过期时间 │
│ – CAS标识 │
│ – 指针等元数据 │
├────────────────────────────────────────────┤
│ Key数据 │
├────────────────────────────────────────────┤
│ Value数据 │
└────────────────────────────────────────────┘

# Chunk大小计算
Chunk Size = Item Header + Key + Value + 对齐

# Chunk选择规则
– 选择能容纳数据的最小Chunk
– 例如:100字节数据选择120B的Chunk
– 会造成一定的空间浪费

# 空间浪费示例
数据大小:100B
选择Chunk:120B (Class 2)
浪费空间:20B (16.7%)

1.3.3 Chunk大小计算

# Chunk大小计算公式

# 基础公式
Chunk[n] = Chunk[n-1] × GrowthFactor

# 默认参数
-n 48 Item最小空间(Header)
-f 1.25 增长因子
-I 1m Page大小

# 计算示例(默认参数)
Class 1: Chunk = 48 + 48 = 96B
Class 2: Chunk = 96 × 1.25 = 120B
Class 3: Chunk = 120 × 1.25 = 150B → 152B (对齐)
Class 4: Chunk = 152 × 1.25 = 190B → 192B (对齐)
Class 5: Chunk = 192 × 1.25 = 240B

# 内存对齐
– Chunk大小通常按8字节对齐
– 确保内存访问效率

# 查看实际Chunk大小
$ echo “stats slabs” | nc 192.168.1.100 11211 | grep chunk_size
STAT 1:chunk_size 96
STAT 2:chunk_size 120
STAT 3:chunk_size 152
STAT 4:chunk_size 192

Part02-生产环境规划与建议

2.1 Memcached数据库内存规划建议

合理的内存规划是Memcached高效运行的基础。学习交流加群风哥QQ113257174

2.1.1 内存容量规划

# Memcached内存容量规划

# 规划步骤
1. 估算缓存数据总量
2. 考虑数据增长空间
3. 预留系统内存
4. 计算最终内存需求

# 示例计算
缓存数据量:50GB
增长率:20%
预留空间:30%
最终需求:50 × 1.2 × 1.3 = 78GB

# 内存分配建议
总内存:128GB
系统预留:20% = 25.6GB
其他进程:10% = 12.8GB
Memcached:70% = 89.6GB

# 配置参数
-m 92160 # 分配90GB给Memcached

# 不同场景的内存规划
# 小型应用
数据量:10GB
配置:-m 16384 (16GB)

# 中型应用
数据量:50GB
配置:-m 65536 (64GB)

# 大型应用
数据量:200GB
配置:-m 262144 (256GB) 或集群部署

2.1.2 内存参数配置

# Memcached内存相关参数

# 核心参数
-m 最大内存使用量(MB),默认64MB
-M 内存耗尽时返回错误,而不是淘汰数据
-n key+value+flags最小空间,默认48
-f slab大小增长因子,默认1.25
-I 每个slab页大小,默认1MB
-L 使用大内存页

# 生产环境推荐配置
-m 81920 # 80GB内存
-M # 内存不足时报错
-n 48 # 默认值
-f 1.25 # 默认值,可根据数据特点调整
-I 1m # 默认值
-L # 启用大页内存(如果系统支持)

# 大内存页配置
# 查看大页内存设置
$ cat /proc/meminfo | grep Huge
HugePages_Total: 0
HugePages_Free: 0
HugePages_Rsvd: 0
Hugepagesize: 2048 kB

# 配置大页内存(需要root权限)
# 计算需要的大页数量
# 80GB / 2MB = 40960页
$ echo 40960 > /proc/sys/vm/nr_hugepages

# 验证配置
$ cat /proc/meminfo | grep Huge
HugePages_Total: 40960
HugePages_Free: 40960
Hugepagesize: 2048 kB

2.2 Memcached数据库Slab配置建议

2.2.1 增长因子选择

# 增长因子(f参数)选择建议

# 增长因子影响
– 影响Slab Class数量
– 影响Chunk大小分布
– 影响内存利用率

# 不同增长因子的特点

# f = 1.25(默认)
特点:Slab Class较多,内存利用率较高
适用:数据大小分布均匀的场景

# f = 1.5
特点:Slab Class较少,内存利用率稍低
适用:数据大小差异较大的场景

# f = 2.0
特点:Slab Class最少,内存利用率较低
适用:数据大小差异很大的场景

# 选择建议
1. 分析数据大小分布
2. 计算不同增长因子的内存利用率
3. 选择最优增长因子

# 数据大小分析示例
$ echo “stats items” | nc 192.168.1.100 11211 | \
awk ‘{print $2}’ | cut -d: -f2 | sort | uniq -c
5000 1 # Class 1: 5000个item
3000 2 # Class 2: 3000个item
2000 3 # Class 3: 2000个item

2.2.2 Page大小选择

# Page大小(I参数)选择建议

# Page大小影响
– 影响单个Item最大大小
– 影响内存分配粒度
– 影响内存利用率

# 不同Page大小的特点

# I = 1m(默认)
最大Item:1MB
适用:大多数场景

# I = 2m
最大Item:2MB
适用:需要存储较大数据的场景

# I = 8m
最大Item:8MB
适用:存储较大对象的场景

# 注意事项
– Page越大,内存浪费可能越多
– 根据实际数据大小选择
– 不建议设置过大

# 查看最大Item大小
$ echo “stats settings” | nc 192.168.1.100 11211 | grep maxbytes
STAT maxbytes 1048576

2.3 Memcached数据库内存监控建议

2.3.1 关键监控指标

# Memcached内存监控关键指标

# 1. 内存使用率
bytes / limit_maxbytes

# 2. Item数量
curr_items

# 3. 内存淘汰次数
evictions

# 4. 内存回收次数
reclaimed

# 5. Slab使用情况
每个Slab Class的used_chunks / total_chunks

# 监控脚本示例
$ cat > /tmp/memcached_memory_monitor.sh << 'EOF' #!/bin/bash # memcached_memory_monitor.sh # from:www.itpux.com.qq113257174.wx:itpux-com # web: http://www.fgedu.net.cn HOST="192.168.1.100" PORT="11211" STATS=$(echo "stats" | nc $HOST $PORT) bytes=$(echo "$STATS" | grep "^STAT bytes" | awk '{print $3}') limit_maxbytes=$(echo "$STATS" | grep "limit_maxbytes" | awk '{print $3}') curr_items=$(echo "$STATS" | grep "curr_items" | awk '{print $3}') evictions=$(echo "$STATS" | grep "^STAT evictions" | awk '{print $3}') reclaimed=$(echo "$STATS" | grep "reclaimed" | awk '{print $3}') # 计算内存使用率 if [ -n "$bytes" ] && [ -n "$limit_maxbytes" ] && [ $limit_maxbytes -gt 0 ]; then usage=$(echo "scale=2; $bytes * 100 / $limit_maxbytes" | bc) echo "内存使用率: ${usage}%" fi echo "当前Item数: $curr_items" echo "淘汰次数: $evictions" echo "回收次数: $reclaimed" EOF $ chmod +x /tmp/memcached_memory_monitor.sh $ /tmp/memcached_memory_monitor.sh 内存使用率: 75.50% 当前Item数: 50000 淘汰次数: 200 回收次数: 150

2.3.2 Slab监控

# Slab监控脚本

$ cat > /tmp/memcached_slab_monitor.sh << 'EOF' #!/bin/bash # memcached_slab_monitor.sh # from:www.itpux.com.qq113257174.wx:itpux-com # web: http://www.fgedu.net.cn HOST="192.168.1.100" PORT="11211" echo "Slab使用情况分析" echo "==================" # 获取slab统计 echo "stats slabs" | nc $HOST $PORT | while read line; do if [[ $line =~ STAT[[:space:]]([0-9]+):chunk_size[[:space:]]([0-9]+) ]]; then class=${BASH_REMATCH[1]} chunk_size=${BASH_REMATCH[2]} # 获取该class的使用情况 used=$(echo "stats slabs" | nc $HOST $PORT | grep "STAT ${class}:used_chunks" | awk '{print $3}') total=$(echo "stats slabs" | nc $HOST $PORT | grep "STAT ${class}:total_chunks" | awk '{print $3}') if [ -n "$used" ] && [ -n "$total" ] && [ $total -gt 0 ]; then usage=$(echo "scale=2; $used * 100 / $total" | bc) echo "Class $class: Chunk=${chunk_size}B, Used=$used/$total (${usage}%)" fi fi done EOF $ chmod +x /tmp/memcached_slab_monitor.sh $ /tmp/memcached_slab_monitor.sh Slab使用情况分析 ================== Class 1: Chunk=96B, Used=5000/10922 (45.78%) Class 2: Chunk=120B, Used=3000/8738 (34.33%) Class 3: Chunk=152B, Used=2000/6826 (29.30%) Class 4: Chunk=192B, Used=1500/5461 (27.47%) Class 5: Chunk=240B, Used=1000/4369 (22.89%)

Part03-生产环境项目实施方案

3.1 Memcached数据库Slab分析实战

3.1.1 查看Slab统计信息

# 连接Memcached
$ telnet 192.168.1.100 11211
Trying 192.168.1.100…
Connected to 192.168.1.100.
Escape character is ‘^]’.

# 查看Slab统计
stats slabs
STAT 1:chunk_size 96
STAT 1:chunks_per_page 10922
STAT 1:total_pages 1
STAT 1:total_chunks 10922
STAT 1:used_chunks 5000
STAT 1:free_chunks 5922
STAT 1:free_chunks_end 0
STAT 1:get_hits 10000
STAT 1:cmd_set 5000
STAT 1:delete_hits 100
STAT 1:incr_hits 50
STAT 1:decr_hits 20
STAT 1:cas_hits 30
STAT 1:cas_badval 5
STAT 2:chunk_size 120
STAT 2:chunks_per_page 8738
STAT 2:total_pages 1
STAT 2:total_chunks 8738
STAT 2:used_chunks 3000
STAT 2:free_chunks 5738
STAT 2:free_chunks_end 0
STAT 2:get_hits 8000
STAT 2:cmd_set 3000
STAT 2:delete_hits 50
STAT 2:incr_hits 30
STAT 2:decr_hits 10
STAT 2:cas_hits 20
STAT 2:cas_badval 2
STAT 3:chunk_size 152
STAT 3:chunks_per_page 6826
STAT 3:total_pages 1
STAT 3:total_chunks 6826
STAT 3:used_chunks 2000
STAT 3:free_chunks 4826
STAT 3:free_chunks_end 0
STAT 3:get_hits 5000
STAT 3:cmd_set 2000
STAT 3:delete_hits 30
STAT 3:incr_hits 20
STAT 3:decr_hits 10
STAT 3:cas_hits 15
STAT 3:cas_badval 1
STAT active_slabs 3
STAT total_malloced 3145728
END

# 字段说明
chunk_size: Chunk大小(字节)
chunks_per_page: 每个Page的Chunk数量
total_pages: 总Page数
total_chunks: 总Chunk数
used_chunks: 已使用Chunk数
free_chunks: 空闲Chunk数
free_chunks_end: 末尾空闲Chunk数
get_hits: 命中次数
cmd_set: 存储次数
delete_hits: 删除命中次数

3.1.2 查看Item统计信息

# 查看Item统计
stats items
STAT items:1:number 5000
STAT items:1:number_hot 1000
STAT items:1:number_warm 2000
STAT items:1:number_cold 2000
STAT items:1:age 3600
STAT items:1:evicted 100
STAT items:1:evicted_nonzero 50
STAT items:1:evicted_time 1800
STAT items:1:outofmemory 0
STAT items:1:tailrepairs 0
STAT items:1:reclaimed 200
STAT items:1:expired_unfetched 50
STAT items:1:evicted_unfetched 30
STAT items:2:number 3000
STAT items:2:number_hot 600
STAT items:2:number_warm 1200
STAT items:2:number_cold 1200
STAT items:2:age 3600
STAT items:2:evicted 50
STAT items:2:evicted_nonzero 25
STAT items:2:evicted_time 1800
STAT items:2:outofmemory 0
STAT items:2:tailrepairs 0
STAT items:2:reclaimed 100
STAT items:2:expired_unfetched 25
STAT items:2:evicted_unfetched 15
END

# 字段说明
number: 当前Item数量
number_hot: HOT LRU中的Item数
number_warm: WARM LRU中的Item数
number_cold: COLD LRU中的Item数
age: 最老Item的年龄(秒)
evicted: 被淘汰的Item数
evicted_nonzero: 非零过期时间被淘汰的Item数
evicted_time: 最近淘汰Item的时间
outofmemory: 内存不足次数
tailrepairs: 尾部修复次数
reclaimed: 回收的过期Item数

3.1.3 使用memcached-tool分析

# 使用memcached-tool查看Slab信息
$ memcached-tool 192.168.1.100:11211 display
# Item_Size Max_age Pages Count Full? Evicted Evict_Time OOM
1 96B 3600s 1 5000 no 100 1800 0
2 120B 3600s 1 3000 no 50 1800 0
3 152B 3600s 1 2000 no 30 1800 0
4 192B 3600s 1 1500 no 20 1800 0
5 240B 3600s 1 1000 no 10 1800 0
6 304B 3600s 1 800 no 5 1800 0
7 384B 3600s 1 600 no 3 1800 0
8 480B 3600s 1 400 no 2 1800 0
9 600B 3600s 1 200 no 1 1800 0

# 字段说明
Item_Size: Chunk大小
Max_age: 最老Item的年龄
Pages: Page数量
Count: Item数量
Full?: Page是否已满
Evicted: 淘汰次数
Evict_Time: 最近淘汰时间
OOM: 内存不足次数

# 查看详细统计
$ memcached-tool 192.168.1.100:11211 stats
# Item_Size Max_age Pages Count Full? Evicted Evict_Time OOM
96B 3600s 1 5000 no 100 1800 0
120B 3600s 1 3000 no 50 1800 0
152B 3600s 1 2000 no 30 1800 0

3.2 Memcached数据库内存优化实战

3.2.1 分析数据大小分布

# 创建数据大小分析脚本
$ cat > /tmp/analyze_data_size.sh << 'EOF' #!/bin/bash # analyze_data_size.sh # from:www.itpux.com.qq113257174.wx:itpux-com # web: http://www.fgedu.net.cn HOST="192.168.1.100" PORT="11211" echo "数据大小分布分析" echo "=================" # 获取Slab统计 echo "stats slabs" | nc $HOST $PORT | grep "chunk_size" | while read line; do class=$(echo $line | awk -F: '{print $2}') chunk_size=$(echo $line | awk '{print $3}') used=$(echo "stats slabs" | nc $HOST $PORT | grep "STAT ${class}:used_chunks" | awk '{print $3}') if [ -n "$used" ] && [ $used -gt 0 ]; then # 估算实际数据大小范围 min_size=$((chunk_size - 48)) # 减去header max_size=$chunk_size echo "Class $class: Chunk=${chunk_size}B, Items=$used, DataRange=${min_size}-${max_size}B" fi done echo "" echo "内存利用率分析" echo "===============" # 计算内存利用率 total_used=0 total_wasted=0 echo "stats slabs" | nc $HOST $PORT | grep "chunk_size" | while read line; do class=$(echo $line | awk -F: '{print $2}') chunk_size=$(echo $line | awk '{print $3}') used=$(echo "stats slabs" | nc $HOST $PORT | grep "STAT ${class}:used_chunks" | awk '{print $3}') if [ -n "$used" ] && [ $used -gt 0 ]; then # 假设平均使用率为75% avg_usage=0.75 used_memory=$((used * chunk_size)) actual_data=$(echo "$used_memory * $avg_usage" | bc) wasted=$(echo "$used_memory * (1 - $avg_usage)" | bc) echo "Class $class: Used=${used_memory}B, Actual=${actual_data}B, Wasted=${wasted}B" fi done EOF $ chmod +x /tmp/analyze_data_size.sh $ /tmp/analyze_data_size.sh 数据大小分布分析 ================= Class 1: Chunk=96B, Items=5000, DataRange=48-96B Class 2: Chunk=120B, Items=3000, DataRange=72-120B Class 3: Chunk=152B, Items=2000, DataRange=104-152B Class 4: Chunk=192B, Items=1500, DataRange=144-192B Class 5: Chunk=240B, Items=1000, DataRange=192-240B 内存利用率分析 =============== Class 1: Used=480000B, Actual=360000B, Wasted=120000B Class 2: Used=360000B, Actual=270000B, Wasted=90000B Class 3: Used=304000B, Actual=228000B, Wasted=76000B

3.2.2 优化增长因子

# 根据数据大小分布优化增长因子

# 场景1:数据大小集中在某个范围
# 例如:大部分数据在100-200字节

# 使用较小的增长因子
-f 1.15

# 场景2:数据大小分布广泛
# 例如:数据从几十字节到几百KB

# 使用较大的增长因子
-f 1.5

# 场景3:数据大小差异极大
# 例如:有小字符串和大对象

# 使用更大的增长因子
-f 2.0

# 测试不同增长因子的效果
# 创建测试脚本
$ cat > /tmp/test_growth_factor.sh << 'EOF' #!/bin/bash # test_growth_factor.sh # from:www.itpux.com.qq113257174.wx:itpux-com # web: http://www.fgedu.net.cn # 测试不同增长因子下的Slab分布 for factor in 1.15 1.25 1.5 2.0; do echo "增长因子: $factor" echo "---------" # 启动测试实例 /memcached/app/bin/memcached -p 11212 -m 64 -f $factor -d -P /tmp/test_memcached.pid sleep 2 # 存储测试数据 for i in {1..100}; do size=$((50 + RANDOM % 200)) data=$(head -c $size /dev/urandom | base64) echo -e "set test:$i 0 3600 ${#data}\n$data" | nc localhost 11212 > /dev/null
done

# 查看Slab分布
echo “stats slabs” | nc localhost 11212 | grep “chunk_size”

# 停止测试实例
kill $(cat /tmp/test_memcached.pid)
rm -f /tmp/test_memcached.pid

echo “”
done

EOF

$ chmod +x /tmp/test_growth_factor.sh

3.3 Memcached数据库Slab调优实战

3.3.1 启用Slab重分配

# Slab重分配功能
# 允许在运行时重新分配Page

# 启动时启用Slab重分配
$ /memcached/app/bin/memcached -p 11211 -m 8192 -o slab_reassign -o slab_automove -d

# 参数说明
-o slab_reassign 启用Slab页重新分配
-o slab_automove 启用Slab自动移动

# 手动触发Slab重分配
# 将Slab Class 1的一个Page移动到Slab Class 5
$ echo “slabs reassign 1 5” | nc 192.168.1.100 11211
OK

# 查看重分配状态
$ echo “stats slabs” | nc 192.168.1.100 11211 | grep “slab_reassign”
STAT slab_reassign_running 0

# Slab自动移动策略
# slab_automove=0: 禁用自动移动
# slab_automove=1: 启用自动移动(默认)
# slab_automove=2: 激进模式

# 启动时配置
$ /memcached/app/bin/memcached -p 11211 -m 8192 \
-o slab_reassign \
-o slab_automove=2 \
-d

3.3.2 Slab调优脚本

# 创建Slab调优脚本
$ cat > /tmp/slab_tuning.sh << 'EOF' #!/bin/bash # slab_tuning.sh # from:www.itpux.com.qq113257174.wx:itpux-com # web: http://www.fgedu.net.cn HOST="192.168.1.100" PORT="11211" echo "Slab调优分析" echo "=============" # 获取Slab统计 STATS=$(echo "stats slabs" | nc $HOST $PORT) # 找出使用率最高的Slab Class max_usage=0 max_class=0 echo "$STATS" | grep "used_chunks" | while read line; do class=$(echo $line | awk -F: '{print $2}') used=$(echo $line | awk '{print $3}') total=$(echo "$STATS" | grep "STAT ${class}:total_chunks" | awk '{print $3}') if [ -n "$total" ] && [ $total -gt 0 ]; then usage=$(echo "scale=2; $used * 100 / $total" | bc) echo "Class $class: 使用率 ${usage}%" fi done echo "" echo "建议:" echo "1. 如果某个Class使用率接近100%,考虑增加内存或调整增长因子" echo "2. 如果某些Class使用率很低,考虑调整增长因子减少Slab Class数量" echo "3. 启用slab_reassign和slab_automove自动平衡内存" EOF $ chmod +x /tmp/slab_tuning.sh $ /tmp/slab_tuning.sh Slab调优分析 ============= Class 1: 使用率 45.78% Class 2: 使用率 34.33% Class 3: 使用率 29.30% Class 4: 使用率 27.47% Class 5: 使用率 22.89% 建议: 1. 如果某个Class使用率接近100%,考虑增加内存或调整增长因子 2. 如果某些Class使用率很低,考虑调整增长因子减少Slab Class数量 3. 启用slab_reassign和slab_automove自动平衡内存

Part04-生产案例与实战讲解

4.1 Memcached数据库内存泄漏排查实战

虽然Memcached本身不会内存泄漏,但不当的使用可能导致内存占用持续增长。更多学习教程公众号风哥教程itpux_com

4.1.1 内存占用异常排查

# 排查内存占用异常

# 1. 查看当前内存使用情况
$ echo “stats” | nc 192.168.1.100 11211 | grep -E “bytes|limit_maxbytes|curr_items”
STAT bytes 7516192768
STAT limit_maxbytes 8589934592
STAT curr_items 500000

# 内存使用率:7516192768 / 8589934592 = 87.5%

# 2. 查看Item增长趋势
$ echo “stats” | nc 192.168.1.100 11211 | grep -E “total_items|curr_items”
STAT total_items 1000000
STAT curr_items 500000

# 已存储100万条,当前存在50万条

# 3. 查看淘汰情况
$ echo “stats” | nc 192.168.1.100 11211 | grep -E “evictions|reclaimed”
STAT evictions 10000
STAT reclaimed 5000

# 有淘汰和回收,说明内存压力较大

# 4. 分析Slab使用情况
$ echo “stats slabs” | nc 192.168.1.100 11211 | grep “used_chunks” | \
awk ‘{sum+=$3} END {print “Total used chunks:”, sum}’
Total used chunks: 500000

# 5. 检查是否有大Key
$ echo “stats slabs” | nc 192.168.1.100 11211 | \
awk ‘/chunk_size/ {size=$3} /used_chunks/ {if($3>0) print “Chunk Size:”, size, “Used:”, $3}’
Chunk Size: 96 Used: 100000
Chunk Size: 120 Used: 80000
Chunk Size: 152 Used: 60000
Chunk Size: 524288 Used: 100 # 发现大Key

4.1.2 内存泄漏排查脚本

# 创建内存泄漏排查脚本
$ cat > /tmp/memory_leak_check.sh << 'EOF' #!/bin/bash # memory_leak_check.sh # from:www.itpux.com.qq113257174.wx:itpux-com # web: http://www.fgedu.net.cn HOST="192.168.1.100" PORT="11211" LOG_FILE="/tmp/memcached_memory.log" echo "时间,内存使用率,Item数,淘汰数,回收数" > $LOG_FILE

while true; do
STATS=$(echo “stats” | nc $HOST $PORT)

bytes=$(echo “$STATS” | grep “^STAT bytes” | awk ‘{print $3}’)
limit=$(echo “$STATS” | grep “limit_maxbytes” | awk ‘{print $3}’)
items=$(echo “$STATS” | grep “curr_items” | awk ‘{print $3}’)
evictions=$(echo “$STATS” | grep “^STAT evictions” | awk ‘{print $3}’)
reclaimed=$(echo “$STATS” | grep “reclaimed” | awk ‘{print $3}’)

if [ -n “$bytes” ] && [ -n “$limit” ] && [ $limit -gt 0 ]; then
usage=$(echo “scale=2; $bytes * 100 / $limit” | bc)
timestamp=$(date ‘+%Y-%m-%d %H:%M:%S’)
echo “$timestamp,$usage,$items,$evictions,$reclaimed” >> $LOG_FILE
echo “[$timestamp] 内存使用率: ${usage}%, Items: $items, Evictions: $evictions”
fi

sleep 60
done

EOF

$ chmod +x /tmp/memory_leak_check.sh
$ /tmp/memory_leak_check.sh &
[2026-04-08 10:00:00] 内存使用率: 75.50%, Items: 50000, Evictions: 200
[2026-04-08 10:01:00] 内存使用率: 76.20%, Items: 51000, Evictions: 250
[2026-04-08 10:02:00] 内存使用率: 77.00%, Items: 52000, Evictions: 300

4.2 Memcached数据库内存碎片处理实战

4.2.1 内存碎片分析

# 分析内存碎片

# 1. 计算理论内存使用
$ echo “stats slabs” | nc 192.168.1.100 11211 | \
awk ‘/chunk_size/ {size=$3} /used_chunks/ {used+=$3; total+=$3*size} END {print “理论使用:”, total, “字节”}’
理论使用: 750000000 字节

# 2. 查看实际内存使用
$ echo “stats” | nc 192.168.1.100 11211 | grep “^STAT bytes”
STAT bytes 800000000

# 3. 计算碎片率
# 碎片率 = (实际使用 – 理论使用) / 实际使用
# 碎片率 = (800000000 – 750000000) / 800000000 = 6.25%

# 4. 分析各Slab Class的碎片情况
$ cat > /tmp/fragment_analysis.sh << 'EOF' #!/bin/bash # fragment_analysis.sh # from:www.itpux.com.qq113257174.wx:itpux-com # web: http://www.fgedu.net.cn HOST="192.168.1.100" PORT="11211" echo "内存碎片分析" echo "=============" total_used=0 total_actual=0 echo "stats slabs" | nc $HOST $PORT | grep "chunk_size" | while read line; do class=$(echo $line | awk -F: '{print $2}') chunk_size=$(echo $line | awk '{print $3}') used=$(echo "stats slabs" | nc $HOST $PORT | grep "STAT ${class}:used_chunks" | awk '{print $3}') if [ -n "$used" ] && [ $used -gt 0 ]; then # 假设平均数据大小为Chunk大小的75% avg_data_size=$(echo "$chunk_size * 0.75" | bc) actual_data=$(echo "$used * $avg_data_size" | bc) allocated=$((used * chunk_size)) wasted=$(echo "$allocated - $actual_data" | bc) echo "Class $class: Chunk=$chunk_size, Used=$used, Allocated=$allocated, Actual=$actual_data, Wasted=$wasted" fi done EOF $ chmod +x /tmp/fragment_analysis.sh $ /tmp/fragment_analysis.sh 内存碎片分析 ============= Class 1: Chunk=96, Used=5000, Allocated=480000, Actual=360000, Wasted=120000 Class 2: Chunk=120, Used=3000, Allocated=360000, Actual=270000, Wasted=90000

4.2.2 减少内存碎片的方法

# 减少内存碎片的方法

# 方法1:优化增长因子
# 根据数据大小分布选择合适的增长因子
# 数据大小集中:使用较小的增长因子(如1.15)
# 数据大小分散:使用较大的增长因子(如1.5)

# 方法2:数据压缩
# 对大Value进行压缩,减少空间浪费

# 方法3:数据分片
# 将大Value拆分成多个小Value

# 方法4:调整-n参数
# 减少Item Header大小(默认48字节)

# 示例配置优化
$ /memcached/app/bin/memcached -p 11211 -m 8192 \
-n 48 \
-f 1.25 \
-I 1m \
-o slab_reassign \
-o slab_automove \
-d

# 监控碎片率脚本
$ cat > /tmp/monitor_fragment.sh << 'EOF' #!/bin/bash # monitor_fragment.sh # from:www.itpux.com.qq113257174.wx:itpux-com # web: http://www.fgedu.net.cn HOST="192.168.1.100" PORT="11211" # 获取实际内存使用 actual=$(echo "stats" | nc $HOST $PORT | grep "^STAT bytes" | awk '{print $3}') # 计算理论内存使用 theoretical=$(echo "stats slabs" | nc $HOST $PORT | \ awk '/chunk_size/ {size=$3} /used_chunks/ {if($3>0) total+=$3*size} END {print total}’)

if [ -n “$actual” ] && [ -n “$theoretical” ] && [ $actual -gt 0 ]; then
fragment_rate=$(echo “scale=2; ($actual – $theoretical) * 100 / $actual” | bc)
echo “内存碎片率: ${fragment_rate}%”
echo “实际使用: $actual 字节”
echo “理论使用: $theoretical 字节”
echo “碎片大小: $((actual – theoretical)) 字节”
fi

EOF

$ chmod +x /tmp/monitor_fragment.sh
$ /tmp/monitor_fragment.sh
内存碎片率: 6.25%
实际使用: 800000000 字节
理论使用: 750000000 字节
碎片大小: 50000000 字节

4.3 Memcached数据库Slab重分配实战

4.3.1 手动Slab重分配

# 手动Slab重分配操作

# 1. 查看当前Slab状态
$ echo “stats slabs” | nc 192.168.1.100 11211 | grep -E “chunk_size|total_pages|used_chunks”
STAT 1:chunk_size 96
STAT 1:total_pages 10
STAT 1:used_chunks 100000
STAT 5:chunk_size 240
STAT 5:total_pages 1
STAT 5:used_chunks 100

# Class 1使用率高,Class 5使用率低

# 2. 检查Slab重分配是否启用
$ echo “stats settings” | nc 192.168.1.100 11211 | grep slab
STAT slab_reassign true
STAT slab_automove 1

# 3. 手动触发重分配
# 将Class 5的一个Page移动到Class 1
$ echo “slabs reassign 5 1” | nc 192.168.1.100 11211
OK

# 4. 验证重分配结果
$ echo “stats slabs” | nc 192.168.1.100 11211 | grep -E “chunk_size|total_pages”
STAT 1:chunk_size 96
STAT 1:total_pages 11
STAT 5:chunk_size 240
STAT 5:total_pages 0

# Class 1的Page从10增加到11
# Class 5的Page从1减少到0

4.3.2 自动Slab平衡

# 启用自动Slab平衡

# 1. 启动时配置
$ /memcached/app/bin/memcached -p 11211 -m 8192 \
-o slab_reassign \
-o slab_automove=2 \
-d

# 2. 查看自动移动状态
$ echo “stats items” | nc 192.168.1.100 11211 | grep -E “evicted|number”
STAT items:1:number 100000
STAT items:1:evicted 5000
STAT items:5:number 100
STAT items:5:evicted 0

# 3. 监控Slab平衡效果
$ cat > /tmp/slab_balance_monitor.sh << 'EOF' #!/bin/bash # slab_balance_monitor.sh # from:www.itpux.com.qq113257174.wx:itpux-com # web: http://www.fgedu.net.cn HOST="192.168.1.100" PORT="11211" echo "Slab平衡监控" echo "============" while true; do timestamp=$(date '+%Y-%m-%d %H:%M:%S') # 获取各Class的使用率 echo "stats slabs" | nc $HOST $PORT | grep "used_chunks" | while read line; do class=$(echo $line | awk -F: '{print $2}') used=$(echo $line | awk '{print $3}') total=$(echo "stats slabs" | nc $HOST $PORT | grep "STAT ${class}:total_chunks" | awk '{print $3}') if [ -n "$total" ] && [ $total -gt 0 ]; then usage=$(echo "scale=2; $used * 100 / $total" | bc) echo "[$timestamp] Class $class: ${usage}%" fi done sleep 300 done EOF $ chmod +x /tmp/slab_balance_monitor.sh

Part05-风哥经验总结与分享

5.1 Memcached数据库内存管理最佳实践

5.1.1 内存规划最佳实践

  • 根据业务数据量合理规划内存大小
  • 预留足够的内存给操作系统
  • 监控内存使用率,及时扩容
  • 使用大内存页提高性能
  • 启用-M参数防止内存耗尽时数据丢失

5.1.2 Slab配置最佳实践

# Slab配置最佳实践

# 1. 分析数据大小分布
# 使用stats slabs和stats items分析

# 2. 选择合适的增长因子
# 数据集中:f = 1.15 – 1.25
# 数据分散:f = 1.25 – 1.5
# 数据差异大:f = 1.5 – 2.0

# 3. 启用Slab重分配
-o slab_reassign
-o slab_automove

# 4. 监控内存使用
# 定期检查内存使用率和淘汰次数

# 5. 优化数据存储
# 压缩大Value
# 避免存储过大的对象

5.2 Memcached数据库Slab优化最佳实践

5.2.1 Slab优化建议

  • 定期分析Slab使用情况
  • 根据数据特点调整增长因子
  • 启用Slab自动平衡
  • 监控内存碎片率
  • 及时处理内存不足问题

5.2.2 常用优化命令

# 常用Slab优化命令

# 查看Slab统计
echo “stats slabs” | nc 192.168.1.100 11211

# 查看Item统计
echo “stats items” | nc 192.168.1.100 11211

# 查看内存使用
echo “stats” | nc 192.168.1.100 11211 | grep -E “bytes|limit_maxbytes”

# 手动Slab重分配
echo “slabs reassign” | nc 192.168.1.100 11211

# 使用memcached-tool
memcached-tool 192.168.1.100:11211 display
memcached-tool 192.168.1.100:11211 stats

5.3 Memcached数据库内存管理常见问题

5.3.1 内存使用率持续增长

# 问题现象
内存使用率持续增长,接近100%

# 排查步骤
1. 检查Item数量增长趋势
2. 检查数据是否设置了过期时间
3. 检查是否有大量数据永不过期
4. 检查淘汰策略是否生效

# 解决方案
1. 为数据设置合理的过期时间
2. 增加内存容量
3. 启用LRU淘汰
4. 清理不需要的缓存数据

5.3.2 内存碎片率过高

# 问题现象
内存碎片率超过20%

# 排查步骤
1. 分析数据大小分布
2. 检查Slab Class使用情况
3. 计算各Class的空间浪费

# 解决方案
1. 调整增长因子
2. 压缩大Value
3. 重启Memcached重新分配内存
4. 启用Slab重分配

5.3.3 某个Slab Class内存不足

# 问题现象
某个Slab Class频繁淘汰数据

# 排查步骤
1. 查看该Class的使用率
2. 分析该Class对应的数据特点
3. 检查是否有异常数据

# 解决方案
1. 手动Slab重分配
2. 启用自动Slab平衡
3. 调整增长因子
4. 增加总内存

风哥总结:Memcached的内存管理机制是其高性能的关键。理解Slab Allocation原理,合理规划内存,优化Slab配置,监控内存使用,是保障Memcached稳定运行的基础。生产环境中要特别注意内存使用率、淘汰次数、碎片率等关键指标,及时进行调优和扩容。

本文由风哥教程整理发布,仅用于学习测试使用,转载注明出处:http://www.fgedu.net.cn/10327.html

联系我们

在线咨询:点击这里给我发消息

微信号:itpux-com

工作日:9:30-18:30,节假日休息