缓存02:Memcached

从简单 KV 缓存、内存管理到与 Redis 选型对比,拆解 Memcached 在简单缓存场景下的优势和局限。

字数 1625 阅读时长 ≈ 5 分钟 2026-7-13 2026-7-13
缓存02:Memcached

Memcached 不是”功能丰富的缓存”,而是”极致简单的 KV 缓存”。它的核心场景是简单 Key-Value 缓存、Session 共享、跨语言共享数据,支持内存级读写、LRU 淘汰和 slab 内存管理,适合简单缓存、跨语言 Session、临时数据共享。

这篇文章围绕三个核心点:简单 KV 缓存、内存管理、与 Redis 选型,把 Memcached 的设计逻辑和适用场景讲清楚。

为什么选 Memcached,而不是 Redis

先定位清楚:Memcached 的核心场景是简单 KV 缓存,只支持 String 类型,不支持复杂数据结构,适合 Session 共享、跨语言缓存、临时数据存储。

与 Redis 的核心差异:

维度MemcachedRedis
数据结构只支持 String5 种基础 + 4 种高级
持久化不支持,重启丢数据RDB + AOF,支持数据恢复
集群不原生支持,需客户端分片主从、哨兵、Cluster 三种模式
分布式锁不支持支持(SETNX)
内存管理slab 分配,内存碎片少jemalloc,内存碎片较多
线程模型多线程,性能稳定单线程,高并发时性能下降
协议自定义协议,客户端较少RESP 协议,客户端丰富
跨语言客户端跨语言(C、Java、Python、PHP)客户端丰富,但以 Java/Go 为主

简单判断:简单 KV 缓存、跨语言 Session、不需要持久化 → Memcached 合适。复杂数据结构、分布式锁、持久化、集群 → Redis 合适。

核心架构:多线程 + slab 内存管理

Memcached 的架构简单,但有两个设计点值得讲:多线程和 slab 内存管理。

多线程模型

Memcached 是多线程模型:

  • 主线程:监听端口,接收连接,分配给工作线程
  • 工作线程:处理请求,读写内存,响应客户端

多线程的好处:高并发时性能稳定,不会像 Redis 单线程那样因某个慢命令阻塞整个服务。代价:锁竞争,多线程访问共享数据需要加锁。

Memcached 的锁粒度:

  • 全局锁:早期版本,全局锁,性能差
  • 分段锁:新版本,每个 slab 类一个锁,减少锁竞争

多线程模型适合简单 KV 操作,不适合复杂数据结构(如 Redis 的 ZSet、Hash)。

Slab 内存管理

Memcached 的内存管理采用 slab 分配器:

  • slab class:按固定大小划分内存块,如 slab class 1 存储 96B 的 item,slab class 2 存储 120B 的 item
  • page:每个 slab class 分配多个 page(默认 1MB),page 内切分成多个 chunk
  • chunk:存储实际数据,大小固定,根据 item 大小选择合适 chunk

slab 的好处:减少内存碎片,分配和释放内存效率高。代价:内存浪费,chunk 大小固定,item 大小不足 chunk 时浪费空间(如 item 50B,chunk 96B,浪费 46B)。

内存分配策略:

item 大小 → 选择最接近的 slab class → 分配 chunk 存储

如果某个 slab class 的内存用完,会从其他 slab class 的 LRU 尾部淘汰 item,释放 chunk。

LRU 淘汰策略

Memcached 使用 LRU(Least Recently Used)淘汰策略:

  • 每个 slab class 维护一个 LRU 链表
  • 新 item 插入链表头部,访问 item 时移到头部
  • 内存不足时,淘汰链表尾部的 item

LRU 淘汰的坑:缓存污染。大 Value 占用大量 chunk,可能挤掉小 Value 的热点数据。建议控制 Value 大小,避免单个 item 过大。

简单 KV 缓存:Memcached 的唯一能力

Memcached 只支持 String 类型,不支持复杂数据结构。核心命令:

命令说明
set key value存储 KV,覆盖已存在的 Key
get key获取 Value
add key value存储 KV,Key 已存在则失败
replace key value更新 Value,Key 不存在则失败
delete key删除 Key
incr key value数值递增,适合计数器
decr key value数值递减

Memcached 不支持事务、Lua 脚本、发布订阅,只做简单 KV 缓存。

与 Redis String 的差异

维度Memcached StringRedis String
最大 Value1MB(可配置)512MB
数值操作INCR/DECR,简单INCR/DECR/INCRBY/DECRBY
过期时间支持,精确到秒支持,精确到毫秒
序列化客户端负责客户端负责

Memcached 适合存储简单字符串、序列化后的对象、Session 数据。

Session 共享:Memcached 的典型场景

Memcached 的典型场景是跨语言 Session 共享:

  • 用户登录:Web 服务器将 Session 写入 Memcached
  • 请求路由:负载均衡将请求路由到任意 Web 服务器
  • Session 读取:Web 服务器从 Memcached 读取 Session

Memcached 的跨语言客户端(C、Java、Python、PHP、Ruby)让它在多语言环境下成为 Session 共享的选择。

配置示例(Java + Spring Session + Memcached):

<bean class="org.springframework.session.data.memcached.config.annotation.web.http.MemcachedHttpSessionConfiguration">
    <property name="memcachedClient" ref="memcachedClient"/>
</bean>

Redis 也支持 Session 共享,但 Memcached 更轻量、多语言客户端更成熟。

与 Redis 选型对比

场景MemcachedRedis
简单 KV 缓存合适,性能稳定合适,功能更多
Session 共享合适,跨语言客户端成熟合适,功能更多
复杂数据结构不支持支持(Hash、ZSet、List)
分布式锁不支持支持(SETNX)
持久化不支持支持(RDB + AOF)
集群不原生支持,需客户端分片支持(主从、哨兵、Cluster)
计数器支持,但功能简单支持,INCRBY/DECRBY

简单判断:只做简单 KV 缓存、不需要持久化、不需要复杂数据结构 → Memcached 合适。需要复杂数据结构、分布式锁、持久化、集群 → Redis 合适。

常见误区

误区真实情况
Memcached 比 Redis 性能高性能接近,Memcached 多线程在高并发时更稳定,Redis 单线程在简单命令时更快
Memcached 不支持过期支持,精确到秒
Memcached 可以存储复杂对象只支持 String,复杂对象需要序列化后存储
Memcached 可以做分布式锁不支持,只能用 add 做简单锁,不推荐

项目判断

引入 Memcached 时,先回答三个问题:

  1. 缓存场景:是否只需要简单 KV 缓存,不需要复杂数据结构?
  2. 持久化:是否不需要持久化,重启丢数据可接受?
  3. 跨语言:是否需要跨语言客户端(如 Java + PHP 共享 Session)?

如果只需要简单 KV 缓存、不需要持久化、需要跨语言共享 → Memcached 合适。如果需要复杂数据结构、分布式锁、持久化、集群 → Redis 合适。

线上排查 Memcached 问题:

  • 内存不足:检查 slab 内存分配,调整 maxbytes 参数,控制 Value 大小
  • 命中率低:检查缓存策略,是否 Value 过大导致淘汰,增加内存或调整 LRU
  • 连接数满:检查连接数限制 maxconns,增加连接数或优化客户端连接池