外观
Memcached 数据过期
数据过期机制
1. 数据过期的定义与作用
- 数据过期:指 Memcached 中存储的数据在达到预设的时间后自动失效并被删除的机制
- 过期时间:也称为 TTL(Time To Live),单位为秒
- 作用:
- 自动清理不再需要的数据
- 释放内存空间
- 确保数据的时效性
- 避免缓存数据与源数据不一致
2. 数据过期的类型
绝对过期:
- 从数据存储时开始计算,经过固定时间后过期
- 例如:设置 TTL 为 3600 秒,数据将在存储 1 小时后过期
- 最常用的过期类型
相对过期:
- 从数据最后一次访问开始计算,经过固定时间后过期
- 例如:设置 TTL 为 3600 秒,数据在 1 小时内未被访问则过期
- 适用于热点数据,可延长热点数据的生存时间
3. 数据过期的限制
最大 TTL:
- Memcached 支持的最大 TTL 为 2^31-1 秒(约 68 年)
- 当设置 TTL 为 0 时,表示数据永不过期
- 当设置 TTL 大于 30 天(2592000 秒)时,Memcached 会将其视为 Unix 时间戳
精度:
- 过期时间的精度为秒级
- 实际过期时间可能会有轻微延迟
- 过期检查是周期性的,不是实时的
4. 过期检查方式
惰性删除:
- 当客户端访问数据时,检查数据是否过期
- 若过期,则删除数据并返回未命中
- 优点:节省 CPU 资源,只在必要时检查
- 缺点:过期数据可能会占用内存较长时间
主动删除:
- Memcached 定期主动检查并删除过期数据
- 默认每 60 秒运行一次过期检查
- 每次检查随机选择 100 个 item
- 若其中超过 25% 的 item 过期,则继续检查
- 优点:及时释放内存空间
- 缺点:消耗一定的 CPU 资源
5. 过期删除流程
- 标记过期:当数据达到过期时间时,被标记为过期
- 删除检查:通过惰性删除或主动删除机制检查过期数据
- 内存回收:删除过期数据,回收内存空间
- 更新统计:更新
expired_unfetched或evicted_unfetched等统计指标
6. 过期与驱逐的区别
| 特性 | 过期(Expiration) | 驱逐(Eviction) |
|---|---|---|
| 触发原因 | 达到预设的 TTL | 内存不足 |
| 处理方式 | 自动删除 | 根据驱逐策略删除 |
| 优先级 | 高(过期数据优先被删除) | 低(只有在内存不足时才发生) |
| 统计指标 | expired_unfetched | evictions |
数据过期配置
1. 设置过期时间
命令行设置:
set key flags exptime bytes [noreply] valueexptime:过期时间(秒)- 示例:
set mykey 0 3600 5\nvalue(设置过期时间为 1 小时)
不同客户端设置方式:
- Java:
memcachedClient.set("mykey", 3600, "value") - Python:
client.set("mykey", "value", time=3600) - PHP:
$memcached->set("mykey", "value", 3600) - Node.js:
client.set("mykey", "value", {expiry: 3600}, callback)
- Java:
2. 批量设置过期时间
touch 命令:用于更新现有键的过期时间,不改变键值
touch key exptime [noreply]- 示例:
touch mykey 7200(将过期时间延长至 2 小时)
- 示例:
批量操作:
- 部分客户端支持批量设置过期时间
- 可通过循环调用
touch命令实现批量更新
3. 清除过期数据
flush_all 命令:
- 用于清除所有缓存数据
- 可带过期时间参数,表示延迟清除
- 示例:
flush_all 3600(1 小时后清除所有数据) - 注意:该命令会清除所有数据,使用需谨慎
清除特定前缀的键:
- Memcached 不直接支持按前缀清除
- 需通过遍历所有键或使用命名空间实现
- 推荐使用命名空间管理相关键
过期策略优化
1. 合理设置 TTL
根据数据特性设置:
- 频繁变化的数据:TTL 较短(分钟级)
- 稳定数据:TTL 较长(小时或天级)
- 静态数据:可设置较长 TTL 或永不过期
避免 TTL 过于集中:
- 设置随机过期时间,避免缓存雪崩
- 示例:
TTL = base_ttl + random(0, variation) - 推荐 variation 为 base_ttl 的 10%-20%
考虑业务需求:
- 兼顾数据时效性和缓存命中率
- 避免频繁更新导致的性能开销
2. 命名空间管理
命名空间的作用:
- 方便管理相关的键
- 支持批量失效
- 避免键冲突
实现方式:
- 在键名前添加前缀:
{namespace}:{key} - 通过更新命名空间版本实现批量失效
- 示例:python
# 获取命名空间版本 ns_version = client.get("user_namespace") or 1 # 构造带命名空间的键 key = f"user:{ns_version}:{user_id}" # 批量失效:更新命名空间版本 client.incr("user_namespace")
- 在键名前添加前缀:
3. 热点数据处理
热点数据识别:
- 通过监控工具识别热点数据
- 分析访问日志,统计访问频率
- 使用 Memcached 的
stats detail命令
热点数据优化:
- 延长热点数据的 TTL
- 考虑使用本地缓存
- 避免热点数据集中过期
- 实现多级缓存架构
4. 缓存雪崩预防
缓存雪崩:
- 定义:大量缓存数据同时过期,导致大量请求回源
- 影响:后端数据库负载激增,可能导致系统崩溃
预防措施:
- 设置随机过期时间
- 采用分层缓存架构
- 实现缓存预热
- 配置合理的重试和降级机制
- 监控缓存命中率,及时发现异常
过期数据监控
1. 监控指标
- expired_unfetched:过期且未被获取的 item 数量
- evicted_unfetched:因内存不足而驱逐且未被获取的 item 数量
- curr_items:当前存储的 item 数量
- total_items:自启动以来存储的总 item 数量
- evictions:因内存不足而驱逐的 item 数量
2. 监控方法
命令行监控:
bashecho stats | nc localhost 11211 | grep -E "expired_unfetched|evicted_unfetched|curr_items|total_items|evictions"监控系统:
- Prometheus + Grafana:通过 exporter 采集过期相关指标
- Zabbix:使用内置的 Memcached 模板
- Datadog:自动采集 Memcached 指标
3. 告警设置
告警阈值:
- expired_unfetched 增长率异常升高
- evictions 持续增加
- curr_items 突然下降
- 命中率突然下降
告警渠道:
- 即时通讯工具(企业微信、钉钉等)
- 短信/电话(紧急情况)
- 邮件(非紧急情况)
常见过期问题及解决方案
1. 数据提前过期
症状:数据在设置的 TTL 之前就被删除
可能原因:
- 内存不足导致数据被驱逐
- 系统时间变化
- 客户端与服务器时间不一致
- Memcached 版本 bug
解决方案:
- 增加内存容量
- 检查系统时间和时区设置
- 确保客户端与服务器时间同步
- 升级到稳定版本
2. 数据过期后仍可访问
症状:数据超过 TTL 后仍能被获取
可能原因:
- 惰性删除机制,数据未被访问
- 主动删除机制尚未运行
- TTL 设置为 0(永不过期)
解决方案:
- 手动访问数据触发惰性删除
- 等待主动删除机制运行(默认 60 秒)
- 检查 TTL 设置是否正确
- 使用
flush_all命令强制清除
3. 缓存雪崩
症状:大量请求回源,后端数据库负载激增
可能原因:
- 大量数据同时过期
- 缓存服务不可用
- 热点数据集中过期
解决方案:
- 设置随机过期时间
- 采用分层缓存架构
- 实现缓存预热
- 配置合理的重试和降级机制
- 监控缓存命中率,及时发现异常
4. 缓存穿透
症状:大量请求访问不存在的数据,导致回源
可能原因:
- 恶意攻击
- 业务逻辑问题
- 数据已删除但请求仍在进行
解决方案:
- 实现布隆过滤器
- 缓存空值
- 限制请求频率
- 验证请求参数
过期策略最佳实践
1. TTL 设计原则
分层设置:
- 核心数据:较短 TTL(分钟级)
- 热点数据:较长 TTL(小时级)
- 静态数据:长期 TTL(天级或更长)
随机化 TTL:
- 在基础 TTL 上添加随机值
- 避免缓存雪崩
- 推荐随机范围为基础 TTL 的 10%-20%
动态调整:
- 根据业务需求和数据变化频率调整 TTL
- 监控命中率,优化 TTL 设置
- 实现自适应 TTL 机制
2. 命名空间管理
使用命名空间:
- 按业务模块或数据类型划分命名空间
- 方便管理和批量失效
- 避免键冲突
命名空间版本控制:
- 使用版本号管理命名空间
- 通过更新版本号实现批量失效
- 示例:
{namespace}:{version}:{key}
3. 监控与优化
建立监控体系:
- 监控过期相关指标
- 设置合理的告警阈值
- 定期分析过期数据分布
优化过期检查:
- 调整主动删除的频率(通过
maxconns_fast等参数) - 优化内存使用,减少驱逐
- 合理设置 slab 分配,减少内存浪费
- 调整主动删除的频率(通过
4. 结合业务场景
电商场景:
- 商品信息:TTL 较短(30 分钟)
- 促销信息:根据活动时间设置 TTL
- 用户会话:TTL 较长(几小时)
新闻资讯场景:
- 热点新闻:TTL 较短(15 分钟)
- 普通新闻:TTL 较长(几小时)
- 历史新闻:TTL 更长(几天)
社交场景:
- 用户动态:TTL 较短(5 分钟)
- 好友列表:TTL 较长(几小时)
- 静态资料:长期 TTL
案例分析
1. 缓存雪崩导致数据库过载
背景:
- 某电商平台在大促期间,大量商品缓存同时过期
- 导致大量请求回源到数据库
- 数据库 CPU 使用率达到 100%,系统响应缓慢
原因分析:
- 所有商品缓存设置了相同的 TTL(24 小时)
- 大促开始时集中加载商品数据,导致 24 小时后集中过期
- 没有设置随机过期时间,引发缓存雪崩
解决方案:
- 立即增加数据库资源,缓解压力
- 优化缓存 TTL 设置,添加随机值
- 实现缓存预热,避免集中加载
- 采用分层缓存架构,减轻数据库压力
- 建立缓存雪崩告警机制
结果:
- 系统恢复正常
- 后续大促未再出现缓存雪崩
- 数据库负载明显降低
2. 热点数据过期导致性能波动
背景:
- 某新闻平台的热点新闻缓存过期
- 导致大量请求回源,系统响应时间从 50ms 增加到 500ms
- 影响用户体验
原因分析:
- 热点新闻设置了固定的 TTL(15 分钟)
- 新闻发布后 15 分钟,缓存过期
- 大量用户同时访问,导致回源压力增大
解决方案:
- 优化热点数据识别机制
- 对热点新闻延长 TTL(60 分钟)
- 实现热点数据本地缓存
- 增加缓存节点,分散负载
结果:
- 系统响应时间恢复正常
- 热点新闻访问稳定
- 建立了热点数据自动识别和优化机制
常见问题(FAQ)
Q1: 如何设置 Memcached 数据永不过期?
A1: 设置 TTL 为 0 即可实现永不过期:
set mykey 0 0 5
value注意:永不过期的数据只会在内存不足时被驱逐,或通过 flush_all 命令清除。
Q2: Memcached 过期时间的精度是多少?
A2: Memcached 过期时间的精度为秒级。实际过期时间可能会有轻微延迟,因为过期检查是周期性的,不是实时的。
Q3: 如何更新现有键的过期时间?
A3: 可以使用 touch 命令更新现有键的过期时间,不改变键值:
touch mykey 7200也可以通过重新 set 键来更新过期时间,但会覆盖原键值。
Q4: 如何批量清除特定前缀的键?
A4: Memcached 不直接支持按前缀清除,但可以通过以下方法实现:
- 使用命名空间管理相关键,通过更新命名空间版本实现批量失效
- 遍历所有键,手动删除匹配前缀的键(仅适用于小型缓存)
- 使用第三方工具或客户端库提供的按前缀清除功能
Q5: 为什么过期数据仍占用内存?
A5: 因为 Memcached 使用惰性删除和主动删除相结合的机制:
- 惰性删除:只有在访问数据时才检查过期
- 主动删除:每 60 秒随机检查 100 个 item
过期数据会在被访问或被主动检查到时删除,释放内存。
Q6: 如何避免缓存雪崩?
A6: 避免缓存雪崩的方法:
- 设置随机过期时间,避免数据集中过期
- 采用分层缓存架构,提高系统容错能力
- 实现缓存预热,避免集中加载
- 配置合理的重试和降级机制
- 监控缓存命中率,及时发现异常
- 实现热点数据识别和特殊处理
