1. 首页 > Memcached教程 > 正文

Memcached教程FG005-Memcached过期策略与LRU实战

本文档风哥主要介绍Memcached数据库过期策略与LRU机制相关知识,包括Memcached数据库过期机制原理、LRU算法原理、LRU结构解析、过期时间规划、LRU配置规划、淘汰策略规划、过期机制实战、LRU配置实战、LRU监控实战等内容,风哥教程参考Memcached官方文档LRU Algorithm、Cache Management等内容编写,适合DBA人员和运维人员在学习和测试中使用,如果要应用于生产环境则需要自行确认。

Part01-基础概念与理论知识

1.1 Memcached数据库过期机制原理

Memcached的过期机制是缓存管理的核心特性之一,理解其工作原理对于正确使用缓存至关重要。更多视频教程www.fgedu.net.cn

1.1.1 过期时间类型

# Memcached过期时间类型

# 1. 相对时间(秒数)
– 范围:0 – 2592000秒(30天)
– 含义:从当前时间开始的秒数
– 示例:3600表示1小时后过期

# 2. 绝对时间(Unix时间戳)
– 范围:大于2592000秒
– 含义:具体的Unix时间戳
– 示例:1712534400表示2024年4月8日

# 3. 永不过期
– 值:0
– 含义:数据永不过期(除非被淘汰)
– 注意:不推荐使用

# 过期时间判断逻辑
if (exptime == 0) {
// 永不过期
} else if (exptime <= 2592000) { // 相对时间:当前时间 + exptime real_exptime = current_time + exptime; } else { // 绝对时间:直接使用 real_exptime = exptime; }

1.1.2 惰性过期机制

# Memcached惰性过期机制

# 工作原理
Memcached不会主动扫描过期数据,而是在访问时检查

# 过期检查时机
1. get操作时检查
2. gets操作时检查
3. touch操作时检查

# 过期处理流程
┌─────────────────────────────────────────┐
│ 客户端发起get请求 │
└─────────────────┬───────────────────────┘


┌─────────────────────────────────────────┐
│ 查找Key对应的数据 │
└─────────────────┬───────────────────────┘


┌─────────────────────────────────────────┐
│ 检查数据是否过期 │
└─────────────────┬───────────────────────┘

┌─────────┴─────────┐
│ │
▼ ▼
┌───────────────┐ ┌───────────────┐
│ 未过期 │ │ 已过期 │
│ 返回数据 │ │ 删除数据 │
└───────────────┘ │ 返回空 │
└───────────────┘

# 惰性过期的优点
– 减少CPU开销
– 不需要后台线程扫描
– 简单高效

# 惰性过期的缺点
– 过期数据占用内存直到被访问
– 可能导致内存浪费

1.1.3 LRU Crawler机制

# LRU Crawler机制

# 启用LRU Crawler
-o lru_crawler

# 工作原理
后台线程定期扫描LRU链表,主动清理过期数据

# 配置参数
-o lru_crawler 启用LRU爬虫
-o lru_maintainer 启用LRU维护线程

# LRU Crawler优势
– 主动清理过期数据
– 释放内存空间
– 减少惰性过期的内存浪费

# 查看Crawler状态
$ echo “stats” | nc 192.168.1.100 11211 | grep crawler
STAT crawler_reclaimed 1000
STAT crawler_items_checked 10000

# crawler_reclaimed: Crawler回收的过期Item数
# crawler_items_checked: Crawler检查的Item数

1.2 Memcached数据库LRU算法原理

LRU(Least Recently Used,最近最少使用)是Memcached的默认淘汰策略,学习交流加群风哥微信: itpux-com

1.2.1 LRU算法概述

# LRU算法原理

# 核心思想
当内存不足时,淘汰最近最少使用的数据

# 实现方式
维护一个按访问时间排序的链表
– 新访问的数据移到链表头部
– 淘汰时从链表尾部删除

# LRU链表结构
┌─────────────────────────────────────────────────────┐
│ LRU链表 │
│ │
│ HEAD ←→ Item1 ←→ Item2 ←→ Item3 ←→ … ←→ TAIL │
│ ↑ ↑ │
│ 最近访问 最久未访问 │
│ (热点数据) (淘汰候选) │
└─────────────────────────────────────────────────────┘

# LRU操作
1. 访问数据:将数据移到链表头部
2. 存储数据:将数据插入链表头部
3. 淘汰数据:从链表尾部删除数据

# LRU优势
– 自动识别热点数据
– 公平淘汰冷数据
– 简单高效

1.2.2 分层LRU结构

# Memcached分层LRU结构

# 新版Memcached采用分层LRU
HOT LRU → WARM LRU → COLD LRU → TEMP LRU

# 各层作用
┌─────────────────────────────────────────────────────┐
│ HOT LRU │
│ – 存储新写入的数据 │
│ – 容量占比:20%(可配置) │
│ – 数据访问后可能升级到WARM │
└─────────────────────────────────────────────────────┘


┌─────────────────────────────────────────────────────┐
│ WARM LRU │
│ – 存储被访问过的数据 │
│ – 容量占比:40%(可配置) │
│ – 数据长时间未访问降级到COLD │
└─────────────────────────────────────────────────────┘


┌─────────────────────────────────────────────────────┐
│ COLD LRU │
│ – 存储长时间未访问的数据 │
│ – 容量占比:剩余空间 │
│ – 淘汰时从此层选择 │
└─────────────────────────────────────────────────────┘


┌─────────────────────────────────────────────────────┐
│ TEMP LRU │
│ – 存储临时数据(短TTL) │
│ – 独立管理,不影响其他LRU │
└─────────────────────────────────────────────────────┘

# 配置参数
-o hot_lru_pct=20 # HOT LRU占比
-o warm_lru_pct=40 # WARM LRU占比
-o temporary_ttl=N # TEMP LRU的TTL阈值

1.3 Memcached数据库LRU结构解析

1.3.1 LRU维护线程

# LRU维护线程

# 启用LRU维护线程
-o lru_maintainer

# 工作职责
1. 在各LRU层之间移动数据
2. 维护LRU链表结构
3. 处理数据淘汰

# 数据移动规则
HOT → WARM:数据被访问
WARM → COLD:数据长时间未访问
COLD → WARM:数据被访问

# 查看LRU维护状态
$ echo “stats” | nc 192.168.1.100 11211 | grep -E “lru_maintainer|moves”
STAT lru_maintainer_juggles 1000
STAT moves_to_cold 5000
STAT moves_to_warm 3000
STAT moves_within_lru 2000

# 字段说明
lru_maintainer_juggles: 维护线程执行次数
moves_to_cold: 移动到COLD的次数
moves_to_warm: 移动到WARM的次数
moves_within_lru: LRU内部移动次数

1.3.2 淘汰机制详解

# Memcached淘汰机制详解

# 触发条件
1. 内存不足时(没有空闲Chunk)
2. 需要存储新数据时

# 淘汰流程
┌─────────────────────────────────────────────────────┐
│ 需要存储新数据 │
└─────────────────┬───────────────────────────────────┘


┌─────────────────────────────────────────────────────┐
│ 查找对应Slab Class的空闲Chunk │
└─────────────────┬───────────────────────────────────┘

┌─────────┴─────────┐
│ │
▼ ▼
┌───────────────┐ ┌───────────────┐
│ 有空闲Chunk │ │ 无空闲Chunk │
│ 直接使用 │ │ 触发淘汰 │
└───────────────┘ └───────┬───────┘


┌───────────────────────────┐
│ 从COLD LRU尾部选择 │
│ 淘汰最近最少使用的数据 │
└───────────────────────────┘

# 淘汰统计
$ echo “stats” | nc 192.168.1.100 11211 | grep evict
STAT evictions 1000
STAT evicted_unfetched 500
STAT evicted_nonzero 800
STAT evicted_time 1712534400

# 字段说明
evictions: 总淘汰次数
evicted_unfetched: 未被访问就被淘汰的数据
evicted_nonzero: 非零过期时间被淘汰的数据
evicted_time: 最近淘汰的时间

Part02-生产环境规划与建议

2.1 Memcached数据库过期时间规划

合理的过期时间规划是缓存有效性的关键。学习交流加群风哥QQ113257174

2.1.1 过期时间设置原则

# Memcached过期时间设置原则

# 1. 根据数据更新频率设置
– 高频更新:短过期时间(分钟级)
– 中频更新:中等过期时间(小时级)
– 低频更新:长过期时间(天级)

# 2. 根据数据重要性设置
– 关键数据:短过期时间,确保及时更新
– 非关键数据:长过期时间,减少数据库压力

# 3. 根据业务场景设置
– 用户会话:30分钟 – 2小时
– 用户资料:1小时 – 24小时
– 商品信息:5分钟 – 1小时
– 页面缓存:1分钟 – 5分钟
– 配置数据:1天 – 7天

# 4. 避免设置
– 过期时间为0(永不过期)
– 过期时间过长(超过数据有效期)
– 过期时间过短(缓存命中率低)

2.1.2 不同场景的过期时间建议

# 不同场景的过期时间建议

# 电商场景
商品基本信息:300秒(5分钟)
商品库存:60秒(1分钟)
商品价格:300秒(5分钟)
用户购物车:1800秒(30分钟)
订单信息:3600秒(1小时)

# 社交场景
用户资料:3600秒(1小时)
好友列表:1800秒(30分钟)
动态列表:300秒(5分钟)
评论数据:600秒(10分钟)
消息列表:60秒(1分钟)

# 内容场景
文章内容:3600秒(1小时)
文章列表:300秒(5分钟)
分类信息:86400秒(1天)
标签信息:86400秒(1天)
热门内容:60秒(1分钟)

# 系统场景
系统配置:86400秒(1天)
权限信息:3600秒(1小时)
字典数据:86400秒(1天)
验证码:300秒(5分钟)

2.2 Memcached数据库LRU配置规划

2.2.1 LRU参数配置

# Memcached LRU参数配置

# 启用LRU相关功能
-o lru_crawler # 启用LRU爬虫
-o lru_maintainer # 启用LRU维护线程

# LRU层配置
-o hot_lru_pct=20 # HOT LRU占比(默认20%)
-o warm_lru_pct=40 # WARM LRU占比(默认40%)
# COLD LRU占比 = 100% – hot_lru_pct – warm_lru_pct

# TEMP LRU配置
-o temporary_ttl=61 # TTL小于此值的数据放入TEMP LRU

# 完整配置示例
$ /memcached/app/bin/memcached -p 11211 -m 8192 \
-o lru_crawler \
-o lru_maintainer \
-o hot_lru_pct=20 \
-o warm_lru_pct=40 \
-o temporary_ttl=61 \
-d

# 不同场景的LRU配置建议

# 热点数据多的场景
-o hot_lru_pct=30
-o warm_lru_pct=40

# 冷数据多的场景
-o hot_lru_pct=10
-o warm_lru_pct=30

# 临时数据多的场景
-o temporary_ttl=300

2.2.2 LRU配置优化建议

  • 启用lru_crawler:主动清理过期数据,释放内存
  • 启用lru_maintainer:自动维护LRU结构
  • 合理设置LRU占比:根据业务特点调整
  • 使用TEMP LRU:短TTL数据单独管理
  • 监控淘汰次数:及时发现问题

2.3 Memcached数据库淘汰策略规划

2.3.1 淘汰策略选择

# Memcached淘汰策略

# 策略1:LRU淘汰(默认)
内存不足时淘汰最近最少使用的数据
适用:大多数场景

# 策略2:拒绝写入(-M参数)
内存不足时返回错误,不淘汰数据
适用:数据不能丢失的场景

# 配置方式
# 默认LRU淘汰
$ /memcached/app/bin/memcached -p 11211 -m 8192 -d

# 拒绝写入模式
$ /memcached/app/bin/memcached -p 11211 -m 8192 -M -d

# 两种策略对比
┌─────────────────┬─────────────────┬─────────────────┐
│ 特性 │ LRU淘汰 │ 拒绝写入 │
├─────────────────┼─────────────────┼─────────────────┤
│ 内存满时行为 │ 淘汰旧数据 │ 返回错误 │
│ 数据安全性 │ 可能丢失数据 │ 数据不丢失 │
│ 写入成功率 │ 高 │ 内存满时失败 │
│ 适用场景 │ 缓存场景 │ 数据重要场景 │
└─────────────────┴─────────────────┴─────────────────┘

2.3.2 淘汰监控指标

# Memcached淘汰监控指标

# 关键指标
1. evictions:总淘汰次数
2. evicted_unfetched:未被访问就被淘汰的数据
3. evicted_nonzero:非零过期时间被淘汰的数据
4. reclaimed:回收的过期数据

# 监控脚本
$ cat > /tmp/eviction_monitor.sh << 'EOF' #!/bin/bash # eviction_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) evictions=$(echo "$STATS" | grep "^STAT evictions" | awk '{print $3}') evicted_unfetched=$(echo "$STATS" | grep "evicted_unfetched" | awk '{print $3}') reclaimed=$(echo "$STATS" | grep "reclaimed" | awk '{print $3}') echo "淘汰统计:" echo "总淘汰次数: $evictions" echo "未访问淘汰: $evicted_unfetched" echo "回收过期: $reclaimed" # 计算淘汰率 cmd_set=$(echo "$STATS" | grep "^STAT cmd_set" | awk '{print $3}') if [ -n "$cmd_set" ] && [ $cmd_set -gt 0 ]; then eviction_rate=$(echo "scale=4; $evictions * 100 / $cmd_set" | bc) echo "淘汰率: ${eviction_rate}%" fi EOF $ chmod +x /tmp/eviction_monitor.sh $ /tmp/eviction_monitor.sh 淘汰统计: 总淘汰次数: 1000 未访问淘汰: 500 回收过期: 800 淘汰率: 0.10%

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

3.1 Memcached数据库过期机制实战

3.1.1 设置过期时间实战

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

# 设置10秒过期
set fgedu_temp 0 10 8
tempdata
STORED

# 立即获取
get fgedu_temp
VALUE fgedu_temp 0 8
tempdata
END

# 等待10秒后获取
get fgedu_temp
END

# 设置1小时过期
set fgedu_hour 0 3600 8
hourdata
STORED

# 设置1天过期
set fgedu_day 0 86400 7
daydata
STORED

# 设置永不过期(不推荐)
set fgedu_forever 0 0 9
foreverdata
STORED

# 使用touch更新过期时间
touch fgedu_hour 7200
TOUCHED

# 验证过期时间已更新
# 数据将在2小时后过期

3.1.2 过期时间计算实战

# 过期时间计算示例

# 相对时间(秒)
# 1分钟 = 60秒
# 1小时 = 3600秒
# 1天 = 86400秒
# 1周 = 604800秒
# 30天 = 2592000秒

# 绝对时间(Unix时间戳)
# 获取当前Unix时间戳
$ date +%s
1712534400

# 计算1小时后的时间戳
$ echo $(($(date +%s) + 3600))
1712538000

# 计算1天后的时间戳
$ echo $(($(date +%s) + 86400))
1712620800

# 使用绝对时间设置过期
# 假设要在2024年4月8日12:00过期
# 对应时间戳:1712558400
set fgedu_absolute 0 1712558400 8
abs_data
STORED

# 验证过期时间
# 可以通过stats items查看

3.1.3 LRU Crawler配置实战

# 启用LRU Crawler

# 方式1:启动时配置
$ /memcached/app/bin/memcached -p 11211 -m 8192 \
-o lru_crawler \
-o lru_maintainer \
-d

# 方式2:修改Systemd服务文件
$ sudo vi /etc/systemd/system/memcached.service
[Service]
ExecStart=/memcached/app/bin/memcached -u memcached -p 11211 -m 8192 -o lru_crawler -o lru_maintainer -v

# 重载配置
$ sudo systemctl daemon-reload
$ sudo systemctl restart memcached

# 验证LRU Crawler是否启用
$ echo “stats settings” | nc 192.168.1.100 11211 | grep lru
STAT lru_crawler true
STAT lru_maintainer true
STAT hot_lru_pct 20
STAT warm_lru_pct 40

# 查看Crawler工作状态
$ echo “stats” | nc 192.168.1.100 11211 | grep crawler
STAT crawler_reclaimed 1000
STAT crawler_items_checked 10000
STAT lrutail_reflocked 10

# 手动触发LRU爬虫(高级)
$ echo “lru_crawler enable” | nc 192.168.1.100 11211
OK

3.2 Memcached数据库LRU配置实战

3.2.1 LRU层配置实战

# 配置LRU层占比

# 场景1:热点数据多
$ /memcached/app/bin/memcached -p 11211 -m 8192 \
-o lru_crawler \
-o lru_maintainer \
-o hot_lru_pct=30 \
-o warm_lru_pct=40 \
-d

# 场景2:冷数据多
$ /memcached/app/bin/memcached -p 11211 -m 8192 \
-o lru_crawler \
-o lru_maintainer \
-o hot_lru_pct=10 \
-o warm_lru_pct=30 \
-d

# 场景3:临时数据多
$ /memcached/app/bin/memcached -p 11211 -m 8192 \
-o lru_crawler \
-o lru_maintainer \
-o temporary_ttl=300 \
-d

# 查看各LRU层的数据分布
$ echo “stats items” | nc 192.168.1.100 11211 | grep number
STAT items:1:number 5000
STAT items:1:number_hot 1000
STAT items:1:number_warm 2000
STAT items:1:number_cold 2000

# 计算各层占比
# HOT: 1000/5000 = 20%
# WARM: 2000/5000 = 40%
# COLD: 2000/5000 = 40%

3.2.2 LRU维护线程监控

# 监控LRU维护线程

# 查看LRU维护统计
$ echo “stats” | nc 192.168.1.100 11211 | grep -E “lru|moves”
STAT lru_maintainer_juggles 10000
STAT moves_to_cold 5000
STAT moves_to_warm 3000
STAT moves_within_lru 2000
STAT direct_reclaims 100

# 字段说明
# lru_maintainer_juggles: 维护线程执行次数
# moves_to_cold: 移动到COLD LRU的次数
# moves_to_warm: 移动到WARM LRU的次数
# moves_within_lru: LRU内部移动次数
# direct_reclaims: 直接回收次数

# 创建LRU监控脚本
$ cat > /tmp/lru_monitor.sh << 'EOF' #!/bin/bash # lru_monitor.sh # from:www.itpux.com.qq113257174.wx:itpux-com # web: http://www.fgedu.net.cn HOST="192.168.1.100" PORT="11211" echo "LRU状态监控" echo "============" STATS=$(echo "stats" | nc $HOST $PORT) echo "LRU维护统计:" echo "$STATS" | grep -E "lru_maintainer|moves|direct_reclaims" echo "" echo "淘汰统计:" echo "$STATS" | grep -E "evictions|reclaimed" echo "" echo "各Slab Class的LRU分布:" echo "stats items" | nc $HOST $PORT | grep -E "number_hot|number_warm|number_cold" | \ awk -F: '{class=$2} {gsub(/STAT items:/, "", class); gsub(/:.*/, "", class)} \ {print "Class", class, $0}' EOF $ chmod +x /tmp/lru_monitor.sh $ /tmp/lru_monitor.sh LRU状态监控 ============ LRU维护统计: STAT lru_maintainer_juggles 10000 STAT moves_to_cold 5000 STAT moves_to_warm 3000 STAT moves_within_lru 2000 STAT direct_reclaims 100 淘汰统计: STAT evictions 1000 STAT reclaimed 800

3.3 Memcached数据库LRU监控实战

3.3.1 实时监控脚本

# 创建实时监控脚本
$ cat > /tmp/realtime_lru_monitor.sh << 'EOF' #!/bin/bash # realtime_lru_monitor.sh # from:www.itpux.com.qq113257174.wx:itpux-com # web: http://www.fgedu.net.cn HOST="192.168.1.100" PORT="11211" INTERVAL=5 echo "时间,内存使用率,Item数,淘汰次数,回收次数,移动到COLD,移动到WARM" 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}') moves_cold=$(echo "$STATS" | grep "moves_to_cold" | awk '{print $3}') moves_warm=$(echo "$STATS" | grep "moves_to_warm" | awk '{print $3}') if [ -n "$bytes" ] && [ -n "$limit" ] && [ $limit -gt 0 ]; then usage=$(echo "scale=2; $bytes * 100 / $limit" | bc) timestamp=$(date '+%H:%M:%S') echo "$timestamp,$usage,$items,$evictions,$reclaimed,$moves_cold,$moves_warm" fi sleep $INTERVAL done EOF $ chmod +x /tmp/realtime_lru_monitor.sh $ /tmp/realtime_lru_monitor.sh 时间,内存使用率,Item数,淘汰次数,回收次数,移动到COLD,移动到WARM 10:00:00,75.50,50000,1000,800,5000,3000 10:00:05,75.60,50100,1005,805,5010,3010 10:00:10,75.70,50200,1010,810,5020,3020

3.3.2 淘汰分析脚本

# 创建淘汰分析脚本
$ cat > /tmp/eviction_analysis.sh << 'EOF' #!/bin/bash # eviction_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 "============" STATS=$(echo "stats" | nc $HOST $PORT) # 获取关键指标 evictions=$(echo "$STATS" | grep "^STAT evictions" | awk '{print $3}') evicted_unfetched=$(echo "$STATS" | grep "evicted_unfetched" | awk '{print $3}') evicted_nonzero=$(echo "$STATS" | grep "evicted_nonzero" | awk '{print $3}') reclaimed=$(echo "$STATS" | grep "reclaimed" | awk '{print $3}') cmd_set=$(echo "$STATS" | grep "^STAT cmd_set" | awk '{print $3}') curr_items=$(echo "$STATS" | grep "curr_items" | awk '{print $3}') echo "" echo "基本统计:" echo "当前Item数: $curr_items" echo "总存储次数: $cmd_set" echo "总淘汰次数: $evictions" echo "" echo "淘汰详情:" echo "未访问淘汰: $evicted_unfetched" echo "非零过期淘汰: $evicted_nonzero" echo "回收过期: $reclaimed" echo "" echo "淘汰分析:" # 计算淘汰率 if [ -n "$cmd_set" ] && [ $cmd_set -gt 0 ]; then eviction_rate=$(echo "scale=4; $evictions * 100 / $cmd_set" | bc) echo "淘汰率: ${eviction_rate}%" fi # 计算未访问淘汰比例 if [ -n "$evictions" ] && [ $evictions -gt 0 ]; then unfetched_rate=$(echo "scale=2; $evicted_unfetched * 100 / $evictions" | bc) echo "未访问淘汰比例: ${unfetched_rate}%" fi echo "" echo "建议:" if [ $evictions -gt 10000 ]; then echo "- 淘汰次数较多,建议增加内存" fi if [ -n "$unfetched_rate" ] && [ $(echo "$unfetched_rate > 50″ | bc) -eq 1 ]; then
echo “- 未访问淘汰比例高,建议优化过期时间设置”
fi

EOF

$ chmod +x /tmp/eviction_analysis.sh
$ /tmp/eviction_analysis.sh
淘汰分析报告
============

基本统计:
当前Item数: 50000
总存储次数: 100000
总淘汰次数: 1000

淘汰详情:
未访问淘汰: 500
非零过期淘汰: 800
回收过期: 800

淘汰分析:
淘汰率: 1.0000%
未访问淘汰比例: 50.00%

建议:
– 未访问淘汰比例高,建议优化过期时间设置

Part04-生产案例与实战讲解

4.1 Memcached数据库数据淘汰案例

以下是一个真实的数据淘汰问题排查案例。更多学习教程公众号风哥教程itpux_com

4.1.1 问题现象

# 问题现象
缓存命中率突然下降,数据库压力增大

# 排查步骤

# 1. 查看淘汰统计
$ echo “stats” | nc 192.168.1.100 11211 | grep -E “evictions|get_hits|get_misses”
STAT get_hits 45000
STAT get_misses 5000
STAT evictions 50000

# 发现淘汰次数异常高

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

# 内存已满

# 3. 查看Item数量
$ echo “stats” | nc 192.168.1.100 11211 | grep curr_items
STAT curr_items 100000

# 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: 100000

# 5. 计算命中率
# 命中率 = 45000 / (45000 + 5000) = 90%
# 命中率正常,但淘汰次数异常

4.1.2 问题分析与解决

# 问题分析
# 淘汰次数高说明内存不足,数据频繁被淘汰

# 解决方案

# 方案1:增加内存
$ sudo vi /etc/systemd/system/memcached.service
ExecStart=/memcached/app/bin/memcached -u memcached -p 11211 -m 16384 …
# 内存从8GB增加到16GB

$ sudo systemctl daemon-reload
$ sudo systemctl restart memcached

# 方案2:优化过期时间
# 检查是否有大量数据未设置过期时间
$ echo “stats items” | nc 192.168.1.100 11211 | grep “evicted_nonzero”
STAT items:1:evicted_nonzero 10000

# 发现大量非零过期时间的数据被淘汰
# 说明过期时间设置不合理

# 方案3:启用LRU Crawler
$ /memcached/app/bin/memcached -p 11211 -m 8192 \
-o lru_crawler \
-o lru_maintainer \
-d

# 方案4:调整LRU层占比
# 如果热点数据多
$ /memcached/app/bin/memcached -p 11211 -m 8192 \
-o lru_crawler \
-o lru_maintainer \
-o hot_lru_pct=30 \
-d

# 验证效果
$ echo “stats” | nc 192.168.1.100 11211 | grep evictions
STAT evictions 100
# 淘汰次数明显下降

4.2 Memcached数据库LRU调优案例

4.2.1 LRU调优场景

# 场景:电商商品缓存

# 问题
# 商品访问模式:少量热门商品访问频繁,大量冷门商品访问少
# 导致冷门商品占用大量内存,热门商品可能被淘汰

# 分析
$ echo “stats items” | nc 192.168.1.100 11211 | grep -E “number_hot|number_warm|number_cold”
STAT items:1:number_hot 500
STAT items:1:number_warm 1000
STAT items:1:number_cold 4500

# COLD LRU占比过高(75%)

# 调优方案
# 增加HOT和WARM LRU占比
$ /memcached/app/bin/memcached -p 11211 -m 8192 \
-o lru_crawler \
-o lru_maintainer \
-o hot_lru_pct=30 \
-o warm_lru_pct=50 \
-d

# 验证调优效果
$ echo “stats items” | nc 192.168.1.100 11211 | grep -E “number_hot|number_warm|number_cold”
STAT items:1:number_hot 1500
STAT items:1:number_warm 2500
STAT items:1:number_cold 1000

# HOT和WARM占比提高,热门商品更容易保留

4.2.2 TEMP LRU应用案例

# 场景:验证码缓存

# 问题
# 验证码TTL很短(5分钟),但占用大量内存
# 影响其他重要数据的缓存

# 解决方案:使用TEMP LRU
$ /memcached/app/bin/memcached -p 11211 -m 8192 \
-o lru_crawler \
-o lru_maintainer \
-o temporary_ttl=300 \
-d

# 验证码数据(TTL=300秒)将存入TEMP LRU
# 不影响HOT/WARM/COLD LRU

# 存储验证码
set verify:phone:13800138000 0 300 6
123456
STORED

# 查看TEMP LRU状态
$ echo “stats items” | nc 192.168.1.100 11211 | grep “number_temp”
STAT items:1:number_temp 1000

# TEMP LRU独立管理,不影响其他数据

4.3 Memcached数据库过期优化案例

4.3.1 过期时间优化案例

# 场景:用户资料缓存

# 问题
# 用户资料更新频率低,但缓存过期时间设置过短
# 导致频繁查询数据库

# 分析
# 当前过期时间:300秒(5分钟)
# 实际更新频率:平均每天更新1次

# 优化方案
# 1. 延长过期时间
# 用户资料:3600秒(1小时)

# 2. 更新时主动刷新缓存
# 用户更新资料后,立即更新缓存

# 优化前
set user:profile:1001 1 300 100
{“id”:1001,”name”:”fgedu”,”age”:30}

# 优化后
set user:profile:1001 1 3600 100
{“id”:1001,”name”:”fgedu”,”age”:30}

# 效果对比
# 优化前:缓存命中率 60%
# 优化后:缓存命中率 95%

4.3.2 惰性过期问题优化

# 问题
# 大量过期数据未被访问,占用内存

# 分析
$ echo “stats” | nc 192.168.1.100 11211 | grep -E “bytes|curr_items|expired_unfetched”
STAT bytes 8000000000
STAT curr_items 100000
STAT expired_unfetched 50000

# 有大量过期数据未被访问

# 解决方案:启用LRU Crawler
$ /memcached/app/bin/memcached -p 11211 -m 8192 \
-o lru_crawler \
-d

# 验证效果
$ echo “stats” | nc 192.168.1.100 11211 | grep crawler
STAT crawler_reclaimed 45000

# Crawler主动回收了过期数据

# 内存使用下降
$ echo “stats” | nc 192.168.1.100 11211 | grep bytes
STAT bytes 6000000000

Part05-风哥经验总结与分享

5.1 Memcached数据库过期策略最佳实践

5.1.1 过期时间设置建议

  • 根据数据更新频率设置合理的过期时间
  • 避免设置过期时间为0(永不过期)
  • 热点数据可设置较长的过期时间
  • 实时性要求高的数据设置较短的过期时间
  • 使用touch命令动态更新过期时间

5.1.2 过期机制配置建议

# Memcached过期机制配置建议

# 1. 启用LRU Crawler
-o lru_crawler

# 2. 启用LRU维护线程
-o lru_maintainer

# 3. 合理配置TEMP LRU
-o temporary_ttl=300

# 4. 监控过期相关指标
– expired_unfetched
– crawler_reclaimed
– reclaimed

5.2 Memcached数据库LRU最佳实践

5.2.1 LRU配置建议

# Memcached LRU配置建议

# 基础配置
-o lru_crawler # 必须启用
-o lru_maintainer # 必须启用

# 根据业务特点调整LRU占比

# 热点数据多
-o hot_lru_pct=30
-o warm_lru_pct=40

# 冷数据多
-o hot_lru_pct=10
-o warm_lru_pct=30

# 临时数据多
-o temporary_ttl=300

# 监控关键指标
– evictions
– moves_to_cold
– moves_to_warm
– lru_maintainer_juggles

5.2.2 淘汰策略选择建议

  • 缓存场景:使用默认LRU淘汰
  • 数据重要场景:使用-M参数拒绝写入
  • 混合场景:根据数据重要性选择

5.3 Memcached数据库过期与LRU常见问题

5.3.1 缓存命中率低

# 问题分析
# 1. 过期时间设置过短
# 2. 内存不足导致频繁淘汰
# 3. 数据访问模式问题

# 解决方案
# 1. 延长过期时间
# 2. 增加内存
# 3. 优化LRU配置
# 4. 分析访问模式,调整缓存策略

5.3.2 内存使用率高但淘汰少

# 问题分析
# 1. 数据过期时间过长
# 2. 存在大量永不过期的数据
# 3. 惰性过期导致过期数据未被清理

# 解决方案
# 1. 检查过期时间设置
# 2. 启用LRU Crawler主动清理
# 3. 分析数据分布,优化存储策略

5.3.3 淘汰次数异常高

# 问题分析
# 1. 内存不足
# 2. 数据量增长过快
# 3. 过期时间设置不合理

# 解决方案
# 1. 增加内存
# 2. 优化过期时间
# 3. 启用LRU Crawler
# 4. 分析数据访问模式

风哥总结:Memcached的过期策略和LRU机制是缓存管理的核心。合理设置过期时间,启用LRU Crawler和LRU维护线程,根据业务特点调整LRU层占比,监控淘汰和回收指标,是保障缓存系统高效运行的关键。生产环境中要特别注意缓存命中率、淘汰次数、内存使用率等关键指标,及时进行调优。

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

联系我们

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

微信号:itpux-com

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