Memcached性能优化 #

一、性能优化概述 #

1.1 性能指标 #

text
Memcached性能指标:

1. 吞吐量
   - 每秒处理的请求数(QPS)
   - 读操作:100,000+ QPS
   - 写操作:80,000+ QPS

2. 延迟
   - 请求响应时间
   - 本地网络:0.1-1ms
   - 跨机房:1-10ms

3. 命中率
   - 缓存命中比例
   - 目标:> 90%

4. 内存使用率
   - 内存占用比例
   - 目标:< 80%

1.2 性能瓶颈 #

text
常见性能瓶颈:

1. 网络带宽
   - 大量数据传输
   - 网络延迟高

2. CPU
   - 序列化/反序列化
   - 数据压缩

3. 内存
   - 内存不足导致淘汰
   - 内存碎片

4. 连接数
   - 连接数不足
   - 连接创建开销

二、配置优化 #

2.1 内存配置 #

bash
# 内存大小
memcached -m 2048

# 建议:
# - 根据数据量设置
# - 预留20%余量
# - 监控内存使用

# 最大Item大小
memcached -I 1m

# 建议:
# - 默认1MB足够
# - 大数据考虑分片或压缩

# 禁用淘汰
memcached -M

# 建议:
# - 内存满时返回错误
# - 需要监控内存使用

2.2 网络配置 #

bash
# 监听端口
memcached -p 11211

# 监听IP
memcached -l 127.0.0.1

# 建议:
# - 只监听内网IP
# - 不要监听0.0.0.0

# 最大连接数
memcached -c 4096

# 建议:
# - 根据并发量设置
# - 预留一定余量

# UDP端口
memcached -U 11211

# 建议:
# - 读取密集场景启用
# - 不保证可靠性

2.3 线程配置 #

bash
# 工作线程数
memcached -t 8

# 建议:
# - 根据CPU核心数设置
# - 一般设置为CPU核心数

# 连接后台线程
memcached -t 8 -R 20

# 参数说明:
# -t  工作线程数
# -R  每个事件的最大请求数

2.4 Slab配置 #

bash
# 增长因子
memcached -f 1.15

# 建议:
# - 默认1.25
# - 数据大小集中时调小
# - 数据大小分散时调大

# 最小Chunk大小
memcached -n 80

# 建议:
# - 根据最小数据大小设置
# - 避免浪费内存

# Slab页大小
memcached -L 2m

# 建议:
# - 默认1MB
# - 大数据场景可以增大

2.5 高级配置 #

bash
# 启用大内存页
memcached -L

# 建议:
# - 减少TLB miss
# - 提高性能

# 启用LRU爬虫
memcached -o lru_crawler

# 建议:
# - 后台清理过期数据
# - 提高内存利用率

# 启用Slab重新分配
memcached -o slab_reassign,slab_automove=1

# 建议:
# - 自动平衡Slab
# - 减少内存碎片

# 禁用CAS
memcached -C

# 建议:
# - 不需要CAS时禁用
# - 减少内存占用

三、使用优化 #

3.1 键命名优化 #

python
# 不好的做法
key = "user_information_cache_user_id_1001_profile_data"

# 好的做法
key = "u:1001:p"

# 说明:
# - 键名越短越好
# - 但要保持可读性
# - 键名也占用内存

3.2 数据大小优化 #

python
# 不好的做法
data = {
    "user_id": 1001,
    "user_name": "John Doe",
    "user_email": "john@example.com",
    "user_description": "A very long description..."
}

# 好的做法
data = {
    "id": 1001,
    "name": "John Doe",
    "email": "john@example.com"
}

# 说明:
# - 去除不必要的字段
# - 缩短字段名
# - 大文本单独存储或压缩

3.3 批量操作 #

python
# 不好的做法
for user_id in user_ids:
    user = client.get(f"user:{user_id}")
    users.append(user)

# 好的做法
keys = [f"user:{user_id}" for user_id in user_ids]
users = client.get_many(keys)

# 说明:
# - 使用批量操作
# - 减少网络往返
# - 提高性能

3.4 连接池 #

python
from pymemcache.client.base import PooledClient

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

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

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

# 说明:
# - 使用连接池
# - 复用连接
# - 减少连接开销

3.5 异步操作 #

python
# 不好的做法
result1 = client.get("key1")
result2 = client.get("key2")
result3 = client.get("key3")

# 好的做法(使用异步客户端)
import asyncio
from aiomcache import Client

async def get_data():
    client = Client('127.0.0.1', 11211)
    
    # 并发获取
    results = await asyncio.gather(
        client.get(b"key1"),
        client.get(b"key2"),
        client.get(b"key3")
    )
    
    return results

# 说明:
# - 使用异步客户端
# - 并发操作
# - 提高吞吐量

3.6 数据压缩 #

python
import gzip
import json

def compress_data(data):
    json_str = json.dumps(data)
    return gzip.compress(json_str.encode())

def decompress_data(compressed):
    json_str = gzip.decompress(compressed).decode()
    return json.loads(json_str)

# 使用
data = {"id": 1001, "name": "John", "description": "..." * 1000}
compressed = compress_data(data)
client.set("user:1001", compressed, flags=3)

# 说明:
# - 大数据压缩存储
# - 减少内存占用
# - 减少网络传输

四、客户端优化 #

4.1 一致性哈希 #

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)

# 说明:
# - 自动分片
# - 节点增减影响小
# - 提高可用性

4.2 失败重试 #

python
from pymemcache.client.base import Client

class RetryClient:
    def __init__(self, server, max_retries=3):
        self.client = Client(server)
        self.max_retries = max_retries
    
    def get(self, key):
        for i in range(self.max_retries):
            try:
                return self.client.get(key)
            except Exception as e:
                if i == self.max_retries - 1:
                    raise
                continue
    
    def set(self, key, value, expire=0):
        for i in range(self.max_retries):
            try:
                return self.client.set(key, value, expire=expire)
            except Exception as e:
                if i == self.max_retries - 1:
                    raise
                continue

# 使用
client = RetryClient(('localhost', 11211))
client.set("key", "value")

4.3 超时设置 #

python
from pymemcache.client.base import Client

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

# 说明:
# - 设置合理的超时时间
# - 避免长时间等待
# - 快速失败

4.4 本地缓存 #

python
import time
from functools import lru_cache

class LocalCacheClient:
    def __init__(self, client, ttl=1):
        self.client = client
        self.ttl = ttl
        self.cache = {}
        self.timestamps = {}
    
    def get(self, key):
        now = time.time()
        
        # 检查本地缓存
        if key in self.cache:
            if now - self.timestamps[key] < self.ttl:
                return self.cache[key]
        
        # 从远程获取
        value = self.client.get(key)
        
        # 更新本地缓存
        if value is not None:
            self.cache[key] = value
            self.timestamps[key] = now
        
        return value

# 使用
client = Client(('localhost', 11211))
local_client = LocalCacheClient(client, ttl=1)

五、架构优化 #

5.1 分布式部署 #

text
分布式部署架构:

┌──────────┐     ┌──────────┐     ┌──────────┐
│  节点1    │     │  节点2    │     │  节点3    │
│  11211   │     │  11212   │     │  11213   │
└────┬─────┘     └────┬─────┘     └────┬─────┘
     │                │                │
     └────────────────┼────────────────┘
                      ▼
              ┌──────────────┐
              │   客户端分片   │
              │  一致性哈希    │
              └──────────────┘

优点:
1. 提高容量
2. 提高性能
3. 提高可用性

5.2 主从复制 #

text
Memcached不支持主从复制

替代方案:
1. 客户端双写
   - 写入多个节点
   - 读取任意节点

2. 使用代理
   - Twemproxy
   - Mcrouter

3. 使用Redis
   - 支持主从复制
   - 支持持久化

5.3 多级缓存 #

text
多级缓存架构:

┌─────────────────────────────────────┐
│           应用层                     │
├─────────────────────────────────────┤
│  L1: 本地缓存(内存)                │
│  - 最快                             │
│  - 容量小                           │
├─────────────────────────────────────┤
│  L2: Memcached(分布式缓存)         │
│  - 较快                             │
│  - 容量大                           │
├─────────────────────────────────────┤
│  L3: Redis(持久化缓存)             │
│  - 较慢                             │
│  - 可持久化                         │
├─────────────────────────────────────┤
│  L4: 数据库                         │
│  - 最慢                             │
│  - 数据源                           │
└─────────────────────────────────────┘

六、性能测试 #

6.1 使用memslap #

bash
# 安装
sudo apt install libmemcached-tools

# 基本测试
memslap --servers=127.0.0.1:11211

# 指定并发数
memslap --servers=127.0.0.1:11211 --concurrency=10

# 指定测试次数
memslap --servers=127.0.0.1:11211 --execute-number=10000

# 测试结果示例
Threads connecting to servers 1
Took 1.234 seconds to load data
Total operations: 10000
Gets: 8000
Sets: 2000
Hits: 7500
Misses: 500

6.2 使用mcperf #

bash
# 安装
git clone https://github.com/antirez/mcperf.git
cd mcperf
make

# 测试
./mcperf --servers=127.0.0.1:11211

# 指定参数
./mcperf --servers=127.0.0.1:11211 --num-conns=10 --num-calls=1000

# 测试结果示例
Total: 10000 operations
Rate: 81234.56 ops/sec
Latency: 0.123 ms (avg)

6.3 自定义测试脚本 #

python
import time
import threading
from pymemcache.client.base import Client

def benchmark(client, num_operations):
    start_time = time.time()
    
    for i in range(num_operations):
        key = f"key:{i}"
        value = f"value:{i}"
        
        # 写入
        client.set(key, value)
        
        # 读取
        client.get(key)
    
    end_time = time.time()
    
    duration = end_time - start_time
    ops_per_sec = (num_operations * 2) / duration
    
    print(f"Operations: {num_operations * 2}")
    print(f"Duration: {duration:.2f} seconds")
    print(f"Rate: {ops_per_sec:.2f} ops/sec")

# 运行测试
client = Client(('localhost', 11211))
benchmark(client, 10000)

七、性能监控 #

7.1 关键指标 #

bash
# 查看统计信息
stats
STAT cmd_get 10000        # get命令次数
STAT cmd_set 5000         # set命令次数
STAT get_hits 8000        # 命中次数
STAT get_misses 2000      # 未命中次数
STAT bytes 1000000        # 存储字节数
STAT curr_connections 10  # 当前连接数
STAT evictions 100        # 淘汰次数
END

# 计算关键指标
命中率 = get_hits / (get_hits + get_misses)
内存使用率 = bytes / limit_maxbytes

7.2 监控脚本 #

bash
#!/bin/bash
# monitor_performance.sh

HOST="127.0.0.1"
PORT="11211"

# 获取统计信息
stats=$(echo "stats" | nc $HOST $PORT)

# 解析数据
cmd_get=$(echo "$stats" | grep "STAT cmd_get" | awk '{print $3}')
cmd_set=$(echo "$stats" | grep "STAT cmd_set" | awk '{print $3}')
get_hits=$(echo "$stats" | grep "STAT get_hits" | awk '{print $3}')
get_misses=$(echo "$stats" | grep "STAT get_misses" | awk '{print $3}')
bytes=$(echo "$stats" | grep "STAT bytes " | awk '{print $3}')
maxbytes=$(echo "$stats" | grep "STAT limit_maxbytes" | awk '{print $3}')
curr_connections=$(echo "$stats" | grep "STAT curr_connections" | awk '{print $3}')
evictions=$(echo "$stats" | grep "STAT evictions" | awk '{print $3}')

# 计算指标
if [ $((get_hits + get_misses)) -gt 0 ]; then
    hit_rate=$(echo "scale=2; $get_hits * 100 / ($get_hits + $get_misses)" | bc)
else
    hit_rate=0
fi

mem_usage=$(echo "scale=2; $bytes * 100 / $maxbytes" | bc)

# 输出结果
echo "Memcached性能监控"
echo "=================="
echo "QPS (get): $cmd_get"
echo "QPS (set): $cmd_set"
echo "命中率: ${hit_rate}%"
echo "内存使用率: ${mem_usage}%"
echo "当前连接数: $curr_connections"
echo "淘汰次数: $evictions"

八、性能优化最佳实践 #

8.1 配置清单 #

bash
# 生产环境推荐配置
memcached -d -m 2048 -p 11211 -u memcache -c 4096 -t 8 -f 1.15 \
  -o lru_crawler,slab_reassign,slab_automove=1 \
  -L -I 1m

# 参数说明:
# -m 2048    : 2GB内存
# -p 11211   : 端口
# -u memcache: 运行用户
# -c 4096    : 最大连接数
# -t 8       : 工作线程数
# -f 1.15    : 增长因子
# -o ...     : 高级选项
# -L         : 大内存页
# -I 1m      : 最大Item大小

8.2 使用清单 #

text
使用优化清单:

1. 使用批量操作
   ✓ get_many
   ✓ set_many

2. 使用连接池
   ✓ PooledClient

3. 合理设置过期时间
   ✓ 添加随机值

4. 数据压缩
   ✓ 大数据压缩

5. 异步操作
   ✓ 异步客户端

6. 本地缓存
   ✓ 多级缓存

8.3 监控清单 #

text
监控清单:

1. 命中率
   ✓ > 90%

2. 内存使用率
   ✓ < 80%

3. 淘汰次数
   ✓ 监控增长

4. 连接数
   ✓ 监控峰值

5. 响应时间
   ✓ < 1ms(本地)

九、总结 #

性能优化要点:

方面 优化方法
配置 内存、线程、网络
使用 批量、连接池、异步
架构 分布式、多级缓存
监控 命中率、内存、连接

最佳实践:

  1. 合理配置参数
  2. 使用批量操作
  3. 使用连接池
  4. 监控关键指标
  5. 优化数据大小

下一步,让我们学习Memcached的监控与调试!

最后更新:2026-03-27