主流 Java 客户端对比
| 特性 | Xmemcached | SpyMemcached |
|---|---|---|
| 推荐度 | ⭐⭐⭐⭐⭐ (强烈推荐) | ⭐⭐⭐ (可用,但已不活跃) |
| 性能 | 极高,基于 NIO,连接数少,性能卓越 | 较高,基于传统的阻塞 I/O |
| 线程模型 | NIO (非阻塞 I/O),单线程处理多个连接,资源占用低 | 每个连接一个线程,高并发时资源消耗大 |
| 活跃度 | 非常活跃,持续更新,社区支持好 | 已不活跃,最后更新于多年以前,不推荐新项目使用 |
| 功能 | 功能全面,支持二进制协议、CAS 操作、分布式、一致性哈希等 | 功能齐全,但缺少一些新特性 |
| 易用性 | API 设计现代,配置简单 | API 设计也比较直观 |
对于任何新项目,请优先选择 Xmemcached,它的性能和活跃度都远超 SpyMemcached。

Xmemcached 详细介绍与使用示例
Xmemcached 是一个高性能、功能丰富的 Memcached Java 客户端。
1 添加 Maven 依赖
在你的 pom.xml 文件中添加 Xmemcached 的依赖:
<dependency>
<groupId>com.googlecode.xmemcached</groupId>
<artifactId>xmemcached</artifactId>
<version>2.4.7</version> <!-- 请使用最新版本 -->
</dependency>
2 核心概念
- MemcachedClient: 这是与 Memcached 服务器交互的核心接口,所有操作(增删改查)都通过它来完成。
- 连接池: Xmemcached 内置了连接池管理,可以高效地复用与 Memcached 服务器的连接。
- 序列化: Xmemcached 默认使用
Transcoder接口来处理 Java 对象与 Memcached 二进制数据之间的转换,默认的SerializingTranscoder使用 Java 序列化,但更推荐使用KryoTranscoder或FastJsonTranscoder等高性能序列化工具。
3 基本使用示例
下面是一个完整的、可运行的 Xmemcached 使用示例。
步骤 1: 启动 Memcached 服务
确保你的机器上已经安装并启动了 Memcached 服务,默认监听 11211 端口。

步骤 2: 编写 Java 代码
import net.rubyeye.xmemcached.MemcachedClient;
import net.rubyeye.xmemcached.MemcachedClientBuilder;
import net.rubyeye.xmemcached.XMemcachedClientBuilder;
import net.rubyeye.xmemcached.auth.AuthInfo;
import net.rubyeye.xmemcached.command.BinaryCommandFactory;
import net.rubyeye.xmemcached.exception.MemcachedException;
import net.rubyeye.xmemcached.utils.AddrUtil;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.concurrent.TimeoutException;
public class XmemcachedExample {
public static void main(String[] args) {
// 1. 创建 MemcachedClientBuilder
// AddrUtil.getAddresses("localhost:11211") 解析 "host:port" 格式的字符串
MemcachedClientBuilder builder = new XMemcachedClientBuilder(
AddrUtil.getAddresses("localhost:11211"));
// 可选配置:设置连接池大小
builder.setConnectionPoolSize(10);
// 可选配置:使用二进制协议(默认就是,但显式声明更清晰)
builder.setCommandFactory(new BinaryCommandFactory());
// 可选配置:如果Memcached设置了认证
// builder.setAuthInfo("user", "password");
MemcachedClient memcachedClient = null;
try {
// 2. 构建并启动 MemcachedClient
memcachedClient = builder.build();
System.out.println("成功连接到 Memcached 服务器!");
// 3. 基本操作示例
// 设置一个键值对 (key, value, 过期时间(秒))
// key 已存在,则覆盖
System.out.println("正在设置键 'user:1001'...");
memcachedClient.set("user:1001", 3600, "张三"); // 3600秒后过期
System.out.println("设置成功!");
// 获取一个键值对
System.out.println("正在获取键 'user:1001' 的值...");
String name = memcachedClient.get("user:1001");
System.out.println("获取到的值: " + name);
// 添加一个键值对(key 不存在才添加)
System.out.println("尝试添加一个新键 'user:1002'...");
boolean added = memcachedClient.add("user:1002", 3600, "李四");
System.out.println("添加操作结果: " + (added ? "成功" : "失败(可能已存在)"));
// 替换一个键值对(key 存在才替换)
System.out.println("尝试替换键 'user:1001' 的值...");
boolean replaced = memcachedClient.replace("user:1001", 3600, "王五");
System.out.println("替换操作结果: " + (replaced ? "成功" : "失败(可能不存在)"));
String newName = memcachedClient.get("user:1001");
System.out.println("替换后的值: " + newName);
// 删除一个键值对
System.out.println("正在删除键 'user:1002'...");
memcachedClient.delete("user:1002");
System.out.println("删除成功!");
// 验证删除
String deletedValue = memcachedClient.get("user:1002");
System.out.println("尝试获取已删除的键 'user:1002',结果: " + deletedValue);
} catch (IOException e) {
System.err.println("创建 MemcachedClient 时发生 IO 异常: " + e.getMessage());
} catch (MemcachedException e) {
System.err.println("Memcached 操作发生异常: " + e.getMessage());
} catch (TimeoutException e) {
System.err.println("Memcached 操作超时: " + e.getMessage());
} finally {
// 4. 关闭客户端,释放资源
if (memcachedClient != null) {
try {
memcachedClient.shutdown();
System.out.println("MemcachedClient 已关闭。");
} catch (IOException e) {
System.err.println("关闭 MemcachedClient 时发生异常: " + e.getMessage());
}
}
}
}
}
4 高级功能:CAS (Check-And-Set)
CAS 是 Memcached 的重要特性,用于实现原子性操作,避免并发更新问题,它类似于数据库的乐观锁。
// CAS 操作示例
try {
// 1. 获取带 CAS ID 的值
CASValue<String> casValue = memcachedClient.getWithCAS("user:1001");
if (casValue != null) {
String currentValue = casValue.getValue();
long casId = casValue.getCas(); // 获取 CAS ID
System.out.println("当前值: " + currentValue + ", CAS ID: " + casId);
// 2. 尝试用新值和旧的 CAS ID 进行更新
String newValue = currentValue + " (已更新)";
boolean casResult = memcachedClient.cas("user:1001", 3600, newValue, casId);
if (casResult) {
System.out.println("CAS 更新成功!");
} else {
System.out.println("CAS 更新失败!值已被其他客户端修改。");
}
}
} catch (Exception e) {
e.printStackTrace();
}
SpyMemcached (备选方案)
虽然不推荐新项目使用,但了解它也有好处,尤其是在维护旧项目时。
1 添加 Maven 依赖
<dependency>
<groupId>net.spy</groupId>
<artifactId>spymemcached</artifactId>
<version>2.12.3</version> <!-- 已不再更新,此为最后一个稳定版本 -->
</dependency>
2 基本使用示例
import net.spy.memcached.MemcachedClient;
import java.net.InetSocketAddress;
import java.util.concurrent.Future;
public class SpyMemcachedExample {
public static void main(String[] args) {
MemcachedClient memcachedClient = null;
try {
// 创建客户端,连接到本地 Memcached
memcachedClient = new MemcachedClient(new InetSocketAddress("localhost", 11211));
System.out.println("成功连接到 Memcached 服务器!");
// 异步设置
Future<Boolean> setFuture = memcachedClient.set("asyncKey", 3600, "异步值");
// 可以检查操作是否完成
setFuture.get(); // 阻塞直到操作完成
System.out.println("异步设置完成。");
// 同步获取
Object value = memcachedClient.get("asyncKey");
System.out.println("获取到的值: " + value);
// 同步删除
memcachedClient.delete("asyncKey");
} catch (Exception e) {
e.printStackTrace();
} finally {
if (memcachedClient != null) {
memcachedClient.shutdown();
}
}
}
}
最佳实践与注意事项
-
连接管理:
(图片来源网络,侵删)- 全局唯一:在应用中,
MemcachedClient应该是全局唯一的,通常通过依赖注入(如 Spring 的@Bean)来管理。 - 生命周期:在应用启动时初始化,在应用关闭时调用
shutdown()释放资源。
- 全局唯一:在应用中,
-
序列化选择:
- 避免 Java 序列化:默认的 Java 序列化性能较差,且存在安全风险。
- 推荐使用高性能序列化:
- Kryo: 速度极快,体积小。
- Protostuff / Protobuf: Google 出品,性能和兼容性都很好。
- Fastjson / Jackson: 如果你已经在项目中大量使用它们,可以配合使用。
-
Key 的设计:
- 简洁明了:Key 应该具有可读性,
user:1001:profile。 - 避免过长:过长的 Key 会占用更多内存和网络带宽。
- 避免特殊字符:最好使用字母、数字、下划线等。
- 简洁明了:Key 应该具有可读性,
-
Value 的大小:
- Memcached 单个 item 的最大值通常是 1MB,避免存储过大的对象。
-
缓存穿透与雪崩:
- 缓存穿透:查询一个根本不存在的数据,解决方案:缓存空对象或使用布隆过滤器。
- 缓存雪崩:大量 key 同时过期,导致所有请求直接打到数据库,解决方案:设置随机的过期时间。
-
监控:
- 定期使用
stats命令监控 Memcached 服务器的状态(如curr_items,total_items,bytes_used,evictions等)。 - 很多客户端库(如 Xmemcached)提供了
stats()方法来获取这些信息。
- 定期使用
希望这份详细的指南能帮助你顺利地在 Java 项目中使用 Memcached!
