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(本地)
九、总结 #
性能优化要点:
| 方面 | 优化方法 |
|---|---|
| 配置 | 内存、线程、网络 |
| 使用 | 批量、连接池、异步 |
| 架构 | 分布式、多级缓存 |
| 监控 | 命中率、内存、连接 |
最佳实践:
- 合理配置参数
- 使用批量操作
- 使用连接池
- 监控关键指标
- 优化数据大小
下一步,让我们学习Memcached的监控与调试!
最后更新:2026-03-27