Memcached客户端库 #

一、客户端库概述 #

1.1 主流客户端库 #

text
各语言主流Memcached客户端:

Java:
- Xmemcached
- SpyMemcached
- Enqueue Memcached

Python:
- pymemcache
- python-memcached
- aiomcache(异步)

PHP:
- memcached扩展
- memcache扩展

Go:
- gomemcache
- mc

Node.js:
- memcached
- memjs

Ruby:
- dalli
- memcached

1.2 客户端选择标准 #

text
选择客户端库的标准:

1. 性能
   - 连接池支持
   - 异步操作
   - 批量操作

2. 功能
   - 一致性哈希
   - 自动故障转移
   - 序列化支持

3. 稳定性
   - 活跃维护
   - 文档完善
   - 社区支持

4. 易用性
   - API简洁
   - 配置简单
   - 错误处理

二、Java客户端 #

2.1 Xmemcached #

xml
<!-- Maven依赖 -->
<dependency>
    <groupId>com.googlecode.xmemcached</groupId>
    <artifactId>xmemcached</artifactId>
    <version>2.4.7</version>
</dependency>
java
import net.rubyeye.xmemcached.MemcachedClient;
import net.rubyeye.xmemcached.MemcachedClientBuilder;
import net.rubyeye.xmemcached.XMemcachedClientBuilder;
import net.rubyeye.xmemcached.utils.AddrUtil;

public class XmemcachedExample {
    public static void main(String[] args) throws Exception {
        // 创建客户端
        MemcachedClientBuilder builder = new XMemcachedClientBuilder(
            AddrUtil.getAddresses("localhost:11211")
        );
        MemcachedClient client = builder.build();
        
        // 存储数据
        client.set("user:1001", 3600, "{\"name\":\"John\",\"age\":25}");
        
        // 获取数据
        String value = client.get("user:1001");
        System.out.println(value);
        
        // 删除数据
        client.delete("user:1001");
        
        // 递增
        long result = client.incr("counter", 1, 0);
        System.out.println(result);
        
        // 关闭客户端
        client.shutdown();
    }
}

2.2 连接池配置 #

java
import net.rubyeye.xmemcached.MemcachedClient;
import net.rubyeye.xmemcached.MemcachedClientBuilder;
import net.rubyeye.xmemcached.XMemcachedClientBuilder;
import net.rubyeye.xmemcached.utils.AddrUtil;

public class XmemcachedPoolExample {
    public static void main(String[] args) throws Exception {
        // 创建客户端构建器
        MemcachedClientBuilder builder = new XMemcachedClientBuilder(
            AddrUtil.getAddresses("localhost:11211,localhost:11212")
        );
        
        // 配置连接池
        builder.setConnectionPoolSize(10);  // 连接池大小
        builder.setConnectTimeout(1000);     // 连接超时(毫秒)
        builder.setOpTimeout(1000);          // 操作超时(毫秒)
        
        // 配置一致性哈希
        builder.setSessionLocator(new KetamaMemcachedSessionLocator());
        
        // 配置序列化
        builder.setTranscoder(new SerializingTranscoder());
        
        MemcachedClient client = builder.build();
        
        // 使用客户端...
        
        client.shutdown();
    }
}

2.3 异步操作 #

java
import net.rubyeye.xmemcached.MemcachedClient;
import net.rubyeye.xmemcached.MemcachedClientBuilder;
import net.rubyeye.xmemcached.XMemcachedClientBuilder;
import net.rubyeye.xmemcached.utils.AddrUtil;

public class XmemcachedAsyncExample {
    public static void main(String[] args) throws Exception {
        MemcachedClientBuilder builder = new XMemcachedClientBuilder(
            AddrUtil.getAddresses("localhost:11211")
        );
        MemcachedClient client = builder.build();
        
        // 异步存储
        client.set("key1", 3600, "value1", new CountDownLatch(1));
        
        // 异步获取
        client.get("key1", new CountDownLatch(1));
        
        // 使用回调
        client.get("key2", new GetCallback<String>() {
            @Override
            public void received(String key, String value) {
                System.out.println("Got value: " + value);
            }
            
            @Override
            public void error(String key, Throwable throwable) {
                System.err.println("Error: " + throwable.getMessage());
            }
        });
        
        client.shutdown();
    }
}

三、Python客户端 #

3.1 pymemcache #

bash
# 安装
pip install pymemcache
python
from pymemcache.client.base import Client

# 创建客户端
client = Client(('localhost', 11211))

# 存储数据
client.set('user:1001', '{"name":"John","age":25}', expire=3600)

# 获取数据
value = client.get('user:1001')
print(value)

# 删除数据
client.delete('user:1001')

# 递增
result = client.incr('counter', 1)
print(result)

# 批量操作
client.set_many({
    'key1': 'value1',
    'key2': 'value2',
    'key3': 'value3'
})

values = client.get_many(['key1', 'key2', 'key3'])
print(values)

# 关闭连接
client.close()

3.2 连接池 #

python
from pymemcache.client.base import PooledClient

# 创建连接池客户端
client = PooledClient(
    ('localhost', 11211),
    max_pool_size=10,
    timeout=1,
    connect_timeout=1
)

# 使用客户端
client.set('key', 'value')
value = client.get('key')

# 关闭连接池
client.close()

3.3 序列化 #

python
import json
from pymemcache.client.base import Client

def json_serializer(key, value):
    if isinstance(value, str):
        return value, 1
    return json.dumps(value), 2

def json_deserializer(key, value, flags):
    if flags == 1:
        return value
    if flags == 2:
        return json.loads(value)
    raise Exception("Unknown serialization format")

# 创建客户端(带序列化)
client = Client(
    ('localhost', 11211),
    serializer=json_serializer,
    deserializer=json_deserializer
)

# 存储对象
user = {'id': 1001, 'name': 'John', 'age': 25}
client.set('user:1001', user, expire=3600)

# 获取对象
user = client.get('user:1001')
print(user)

3.4 异步客户端 #

python
import asyncio
from aiomcache import Client

async def main():
    # 创建异步客户端
    client = Client('127.0.0.1', 11211)
    
    # 存储数据
    await client.set(b'key', b'value', exptime=3600)
    
    # 获取数据
    value = await client.get(b'key')
    print(value)
    
    # 删除数据
    await client.delete(b'key')
    
    # 并发操作
    await asyncio.gather(
        client.set(b'key1', b'value1'),
        client.set(b'key2', b'value2'),
        client.set(b'key3', b'value3')
    )
    
    # 关闭连接
    client.close()

# 运行
asyncio.run(main())

3.5 一致性哈希 #

python
from pymemcache.client.hash import HashClient

# 创建一致性哈希客户端
servers = [
    ('127.0.0.1', 11211),
    ('127.0.0.1', 11212),
    ('127.0.0.1', 11213)
]

client = HashClient(
    servers,
    use_pooling=True,
    timeout=1
)

# 自动分片
client.set('key1', 'value1')
client.set('key2', 'value2')
client.set('key3', 'value3')

# 获取数据
values = client.get_many(['key1', 'key2', 'key3'])
print(values)

四、PHP客户端 #

4.1 安装扩展 #

bash
# Ubuntu/Debian
sudo apt install php-memcached

# CentOS/RHEL
sudo yum install php-memcached

# 验证安装
php -m | grep memcached

4.2 基本使用 #

php
<?php
// 创建客户端
$memcached = new Memcached();
$memcached->addServer('localhost', 11211);

// 存储数据
$memcached->set('user:1001', json_encode([
    'name' => 'John',
    'age' => 25
]), 3600);

// 获取数据
$user = $memcached->get('user:1001');
echo $user . "\n";

// 删除数据
$memcached->delete('user:1001');

// 递增
$memcached->set('counter', 0);
$result = $memcached->increment('counter', 1);
echo $result . "\n";

// 批量操作
$memcached->setMulti([
    'key1' => 'value1',
    'key2' => 'value2',
    'key3' => 'value3'
], 3600);

$values = $memcached->getMulti(['key1', 'key2', 'key3']);
print_r($values);

// 关闭连接
$memcached->quit();
?>

4.3 连接池 #

php
<?php
// 创建持久连接
$memcached = new Memcached('persistent_pool');
$memcached->addServer('localhost', 11211);

// 使用连接池
$memcached->set('key', 'value');
$value = $memcached->get('key');
?>

4.4 一致性哈希 #

php
<?php
// 创建客户端
$memcached = new Memcached();

// 添加多个服务器
$memcached->addServers([
    ['127.0.0.1', 11211],
    ['127.0.0.1', 11212],
    ['127.0.0.1', 11213]
]);

// 设置一致性哈希
$memcached->setOption(Memcached::OPT_DISTRIBUTION, Memcached::DISTRIBUTION_CONSISTENT);
$memcached->setOption(Memcached::OPT_LIBKETAMA_COMPATIBLE, true);

// 自动分片
$memcached->set('key1', 'value1');
$memcached->set('key2', 'value2');
$memcached->set('key3', 'value3');
?>

五、Go客户端 #

5.1 gomemcache #

bash
# 安装
go get github.com/bradfitz/gomemcache/memcache
go
package main

import (
    "fmt"
    "github.com/bradfitz/gomemcache/memcache"
)

func main() {
    // 创建客户端
    client := memcache.New("localhost:11211")
    
    // 存储数据
    err := client.Set(&memcache.Item{
        Key:   "user:1001",
        Value: []byte(`{"name":"John","age":25}`),
        Expiration: 3600,
    })
    if err != nil {
        panic(err)
    }
    
    // 获取数据
    item, err := client.Get("user:1001")
    if err != nil {
        panic(err)
    }
    fmt.Println(string(item.Value))
    
    // 删除数据
    err = client.Delete("user:1001")
    if err != nil {
        panic(err)
    }
    
    // 递增
    client.Set(&memcache.Item{
        Key:   "counter",
        Value: []byte("0"),
    })
    newValue, err := client.Increment("counter", 1)
    if err != nil {
        panic(err)
    }
    fmt.Println(newValue)
    
    // 批量操作
    client.SetMulti([]*memcache.Item{
        {Key: "key1", Value: []byte("value1")},
        {Key: "key2", Value: []byte("value2")},
        {Key: "key3", Value: []byte("value3")},
    })
    
    items, err := client.GetMulti([]string{"key1", "key2", "key3"})
    if err != nil {
        panic(err)
    }
    for key, item := range items {
        fmt.Printf("%s: %s\n", key, string(item.Value))
    }
}

5.2 多服务器配置 #

go
package main

import (
    "fmt"
    "github.com/bradfitz/gomemcache/memcache"
)

func main() {
    // 创建多服务器客户端
    client := memcache.New(
        "localhost:11211",
        "localhost:11212",
        "localhost:11213",
    )
    
    // 自动分片
    client.Set(&memcache.Item{
        Key:   "key1",
        Value: []byte("value1"),
    })
    
    client.Set(&memcache.Item{
        Key:   "key2",
        Value: []byte("value2"),
    })
    
    // 获取数据
    item, err := client.Get("key1")
    if err != nil {
        panic(err)
    }
    fmt.Println(string(item.Value))
}

六、Node.js客户端 #

6.1 memcached #

bash
# 安装
npm install memcached
javascript
const Memcached = require('memcached');

// 创建客户端
const client = new Memcached('localhost:11211');

// 存储数据
client.set('user:1001', JSON.stringify({
    name: 'John',
    age: 25
}), 3600, (err) => {
    if (err) {
        console.error(err);
    }
});

// 获取数据
client.get('user:1001', (err, data) => {
    if (err) {
        console.error(err);
        return;
    }
    console.log(JSON.parse(data));
});

// 删除数据
client.del('user:1001', (err) => {
    if (err) {
        console.error(err);
    }
});

// 递增
client.incr('counter', 1, (err, result) => {
    if (err) {
        console.error(err);
        return;
    }
    console.log(result);
});

// 批量操作
client.setMulti({
    'key1': 'value1',
    'key2': 'value2',
    'key3': 'value3'
}, 3600, (err) => {
    if (err) {
        console.error(err);
    }
});

client.getMulti(['key1', 'key2', 'key3'], (err, data) => {
    if (err) {
        console.error(err);
        return;
    }
    console.log(data);
});

// 关闭连接
client.end();

6.2 多服务器配置 #

javascript
const Memcached = require('memcached');

// 创建多服务器客户端
const client = new Memcached([
    'localhost:11211',
    'localhost:11212',
    'localhost:11213'
], {
    retries: 2,
    timeout: 1000,
    remove: true,
    failOverServers: ['localhost:11214']
});

// 自动分片
client.set('key1', 'value1', 3600, (err) => {
    if (err) {
        console.error(err);
    }
});

七、客户端最佳实践 #

7.1 连接管理 #

python
# 不好的做法
def get_user(user_id):
    client = Client(('localhost', 11211))
    user = client.get(f'user:{user_id}')
    client.close()
    return user

# 好的做法
client = PooledClient(('localhost', 11211), max_pool_size=10)

def get_user(user_id):
    return client.get(f'user:{user_id}')

7.2 错误处理 #

python
from pymemcache.client.base import Client

def safe_get(client, key, default=None):
    try:
        value = client.get(key)
        return value if value is not None else default
    except Exception as e:
        print(f"Error getting key {key}: {e}")
        return default

def safe_set(client, key, value, expire=3600):
    try:
        client.set(key, value, expire=expire)
        return True
    except Exception as e:
        print(f"Error setting key {key}: {e}")
        return False

# 使用
client = Client(('localhost', 11211))
user = safe_get(client, 'user:1001', default={})
safe_set(client, 'user:1001', user, expire=3600)

7.3 超时设置 #

python
from pymemcache.client.base import Client

# 设置超时
client = Client(
    ('localhost', 11211),
    timeout=1,         # 操作超时(秒)
    connect_timeout=1  # 连接超时(秒)
)

7.4 重试机制 #

python
import time
from pymemcache.client.base import Client

def retry_operation(func, max_retries=3, delay=0.1):
    for i in range(max_retries):
        try:
            return func()
        except Exception as e:
            if i == max_retries - 1:
                raise
            time.sleep(delay)
    return None

# 使用
client = Client(('localhost', 11211))

result = retry_operation(lambda: client.get('key'))

八、总结 #

客户端库选择:

语言 推荐客户端 特点
Java Xmemcached 功能全面、性能好
Python pymemcache 简单易用、支持异步
PHP memcached 官方扩展、功能完善
Go gomemcache 官方推荐、简单高效
Node.js memcached 社区活跃、功能丰富

最佳实践:

  1. 使用连接池
  2. 设置合理的超时
  3. 实现错误处理
  4. 使用批量操作
  5. 配置一致性哈希

下一步,让我们学习Memcached的分布式缓存!

最后更新:2026-03-27