Memcached 完全指南 / 第 1 章:Memcached 简介
第 1 章:Memcached 简介
1.1 历史起源
Memcached 最初由 Brad Fitzpatrick 于 2003 年为 LiveJournal 开发,目的是解决高并发读取场景下的数据库压力问题。
发展时间线
| 时间 | 事件 |
|---|---|
| 2003 | Brad Fitzpatrick 为 LiveJournal 开发初版 |
| 2004 | 开源发布,迅速被 Facebook、YouTube、Twitter 等采用 |
| 2008 | Facebook 部署超过 28 台 Memcached 服务器,缓存 28TB 数据 |
| 2009 | Memcached 1.4 发布,引入二进制协议 |
| 2012 | 引入多线程支持(-t 参数) |
| 2017 | Memcached 1.5 引入 LRU 维护(lru_maintainer) |
| 2020 | Memcached 1.6 引入 meta 协议、TLS 支持 |
| 2024 | 持续维护,广泛部署于全球各大互联网公司 |
核心设计理念
Memcached 的设计哲学可以用三个词概括:简单、快速、分布式。
┌─────────────────────────────────────────────┐
│ Memcached 设计原则 │
├─────────────────────────────────────────────┤
│ 1. K/V 存储:只做一件事,做到极致 │
│ 2. 内存优先:数据只存在内存中,重启即丢失 │
│ 3. 无持久化:不做 RDB/AOF,简化设计 │
│ 4. 客户端分片:服务端无中心,客户端路由 │
│ 5. O(1) 复杂度:所有操作常数时间 │
│ 6. 懒惰删除:过期数据不立即回收,按需清理 │
└─────────────────────────────────────────────┘
1.2 核心特性
特性概览
| 特性 | 说明 |
|---|---|
| 存储模型 | Key-Value,Value 最大 1MB(可配置) |
| 数据类型 | 仅 String(二进制安全) |
| 持久化 | 无,纯内存 |
| 集群方案 | 客户端一致性哈希分片 |
| 线程模型 | 多线程(主从 Reactor) |
| 协议 | 文本协议 / 二进制协议 / Meta 协议 |
| 过期策略 | 惰性删除 + LRU 淘汰 |
| 原子操作 | incr / decr / CAS |
| 内存管理 | Slab Allocator |
为什么选择 Memcached?
场景一:纯粹的缓存层
如果你的需求是"查询 → 缓存 → 返回",不需要复杂数据结构,Memcached 是最佳选择:
# 典型缓存流程
Client → 查询 Memcached
├── 命中 → 直接返回(< 1ms)
└── 未命中 → 查数据库 → 写入缓存 → 返回
场景二:大规模分布式缓存
Memcached 的客户端分片架构天然支持水平扩展:
┌─── Memcached Node 1 (2GB)
Client ──哈希路由──┼─── Memcached Node 2 (2GB)
├─── Memcached Node 3 (2GB)
└─── Memcached Node N (2GB)
1.3 适用场景
非常适合的场景
| 场景 | 说明 | 示例 |
|---|---|---|
| 数据库查询缓存 | 缓存 SQL 查询结果,降低 DB 压力 | 用户信息、商品详情 |
| Session 存储 | 分布式会话管理 | PHP Session Handler |
| 页面片段缓存 | 缓存渲染后的 HTML 片段 | 导航栏、侧边栏 |
| 计数器/限流 | 利用 incr/decr 原子操作 | API 限流、文章阅读量 |
| Token 缓存 | 短期 Token 存储 | JWT 黑名单、验证码 |
| 热点数据 | 高频读取的小数据 | 配置项、排行榜快照 |
不适合的场景
| 场景 | 原因 | 推荐方案 |
|---|---|---|
| 需要持久化 | 数据重启丢失 | Redis / MySQL |
| 复杂数据结构 | 只支持 String | Redis(Hash/List/Set) |
| 大 Value 存储 | 默认最大 1MB | Redis / 本地文件 |
| 发布订阅 | 不支持 Pub/Sub | Redis / RabbitMQ |
| 数据分析 | 无聚合能力 | Redis / ClickHouse |
| 事务操作 | 无 MULTI/EXEC | Redis |
1.4 Memcached vs Redis
这是最常被问到的问题。两者都是优秀的内存缓存,但定位不同。
架构对比
Memcached 架构: Redis 架构:
┌──────────────┐ ┌──────────────┐
│ Client │ │ Client │
│ (一致性哈希) │ │ │
└──┬───┬───┬───┘ └──────┬───────┘
│ │ │ │
▼ ▼ ▼ ▼
┌──┐ ┌──┐ ┌──┐ ┌──────────────┐
│N1│ │N2│ │N3│ ← 无中心 │ Redis Server │ ← 有中心
└──┘ └──┘ └──┘ │ (主从/集群) │
└──────────────┘
功能对比表
| 维度 | Memcached | Redis |
|---|---|---|
| 数据结构 | String Only | String / Hash / List / Set / ZSet / Stream |
| 持久化 | 无 | RDB + AOF |
| 集群 | 客户端分片 | Redis Cluster / Sentinel |
| 多线程 | 原生多线程 | 6.0+ 多线程 I/O |
| 内存效率 | 更高(Slab 预分配) | 较低(jemalloc 碎片) |
| 单 Value 限制 | 1MB(可调) | 512MB |
| 原子操作 | incr/decr/CAS | 丰富(Lua/Transaction) |
| 发布订阅 | 不支持 | 支持 |
| Lua 脚本 | 不支持 | 支持 |
| 过期策略 | 惰性 + LRU | 惰性 + 定期 |
| 协议复杂度 | 简单 | RESP 协议 |
| 运维复杂度 | 低 | 中高(集群模式) |
| 内存开销/Key | ~70 bytes | ~100+ bytes |
| 适用规模 | 超大规模缓存 | 中大规模 + 业务逻辑 |
性能对比(单节点,小 Value)
| 操作 | Memcached | Redis | 备注 |
|---|---|---|---|
| GET (100B) | ~200K QPS | ~180K QPS | 同等硬件 |
| SET (100B) | ~180K QPS | ~160K QPS | 同等硬件 |
| 内存效率 | 1x | 1.2-1.5x | Memcached 更省 |
| 延迟 P99 | < 1ms | < 1ms | 无显著差异 |
| 连接数上限 | 数万 | 数万 | 取决于配置 |
注意:以上数据为参考值,实际性能受硬件、网络、Value 大小、并发量等因素影响。
选型决策树
需要持久化?
├── 是 → Redis
└── 否 → 需要复杂数据结构?
├── 是 → Redis
└── 否 → 需要发布订阅/Lua 脚本?
├── 是 → Redis
└── 否 → 纯缓存 + 大规模 + 高吞吐?
├── 是 → Memcached ✓
└── 否 → 两者均可(团队熟悉度决定)
1.5 谁在使用 Memcached?
大规模部署案例
| 公司 | 规模 | 用途 |
|---|---|---|
| 数万台,PB 级缓存 | 社交图谱、News Feed | |
| 数千台 | Timeline 缓存 | |
| YouTube | 数千台 | 视频元数据 |
| Wikipedia | 数百台 | 页面缓存 |
| Slack | 数百台 | 会话与消息缓存 |
| GitHub | 内部使用 | API 结果缓存 |
Facebook 的经典架构
Facebook 在 2013 年的 USENIX 论文《Scaling Memcache at Facebook》中描述了其架构:
用户请求
│
▼
┌─────────┐ ┌──────────┐ ┌───────────┐
│ Web 层 │────▶│ McRouter │────▶│ Memcached │
│ (PHP) │ │ (代理层) │ │ 集群 │
└─────────┘ └──────────┘ └───────────┘
│ │
▼ ▼
┌─────────┐ ┌───────────┐
│ MySQL │◀────── 失效通知 ───│ 集群间 │
│ 集群 │ │ 复制 │
└─────────┘ └───────────┘
1.6 Memcached 的局限性
了解局限性同样重要:
已知限制
| 限制项 | 说明 | 解决方案 |
|---|---|---|
| 无持久化 | 重启数据丢失 | 上层补偿(DB 回源) |
| 单线程命令执行 | 命令串行处理 | 1.6+ 改进 |
| 最大 Key 长度 | 250 字节 | 合理设计 Key |
| 最大 Value | 1MB(默认) | 拆分或外部存储 |
| 无集群管理 | 需客户端/MC Router | 使用代理层 |
| LRU 全局 | Slab 级别 LRU | lru_maintainer |
| 无访问控制 | 无 ACL | SASL / 网络隔离 |
1.7 本教程路线图
基础篇(第 1-5 章)
├── 了解 Memcached(你在这里)
├── 安装与部署
├── 架构原理
├── 核心命令
└── 数据类型与序列化
进阶篇(第 6-10 章)
├── Slab 分配器详解
├── LRU 淘汰策略
├── 一致性哈希
├── 多线程模型
└── 通信协议
运维篇(第 11-14 章)
├── 安全加固
├── 监控与告警
├── 性能优化
└── Docker 部署
实战篇(第 15-16 章)
├── 多语言客户端
└── 生产最佳实践
1.8 快速体验
如果等不及看完全部教程,可以先用 Docker 快速体验:
# 启动 Memcached
docker run -d --name mc-test -p 11211:11211 memcached:1.6-alpine
# 安装命令行客户端
sudo apt-get install -y libmemcached-tools # Debian/Ubuntu
# 或
brew install libmemcached # macOS
# 使用 telnet 连接(最简单的方式)
telnet localhost 11211
# 尝试基本操作
set mykey 0 3600 5 # 设置 Key,Flags=0,TTL=3600秒,5字节
hello # 值
STORED # 返回结果
get mykey # 获取
VALUE mykey 0 5 # 返回
hello
END
quit # 退出
扩展阅读
小结
| 要点 | 内容 |
|---|---|
| 本质 | 简单、快速的分布式内存 K/V 缓存 |
| 最大优势 | 极致简单 + 极致性能 + 原生多线程 |
| 最大局限 | 无持久化、仅 String、无集群管理 |
| 选型建议 | 纯缓存场景优先考虑 Memcached |