游戏性能测试
目录
05. 游戏性能测试
性能测试和压力测试完全指南
性能测试基础
核心指标
- 响应时间: 请求到响应的时间
- 吞吐量(TPS): 每秒处理的事务数
- 并发用户数: 同时在线用户数
- 错误率: 失败请求的百分比
- CPU使用率: 服务器CPU占用
- 内存使用: 服务器内存占用
Locust压力测试
安装和配置
pip install locust
基础用法
# locustfile.py
from locust import HttpUser, task, between
class GameUser(HttpUser):
"""游戏用户行为模拟"""
# 用户操作间隔时间
wait_time = between(1, 3)
def on_start(self):
"""每个用户开始时执行"""
# 登录
response = self.client.post('/api/login', json={
'username': 'test_user',
'password': 'test123'
})
self.token = response.json()['token']
@task(3) # 权重3,执行频率更高
def get_player_info(self):
"""获取玩家信息"""
self.client.get('/api/player/info', headers={
'Authorization': f'Bearer {self.token}'
})
@task(2)
def battle(self):
"""进行战斗"""
self.client.post('/api/battle/start', json={
'enemy_id': 1001
}, headers={
'Authorization': f'Bearer {self.token}'
})
@task(1)
def get_leaderboard(self):
"""查看排行榜"""
self.client.get('/api/leaderboard')
运行测试:
# Web界面模式
locust -f locustfile.py --host=https://api.game.com
# 无界面模式
locust -f locustfile.py --host=https://api.game.com \
--users 100 --spawn-rate 10 --run-time 5m --headless
高级场景
from locust import HttpUser, TaskSet, task, between
import random
class PlayerBehavior(TaskSet):
"""玩家行为集"""
@task(5)
def browse_shop(self):
"""浏览商店"""
self.client.get('/api/shop/items')
@task(3)
def buy_item(self):
"""购买物品"""
item_id = random.randint(1, 100)
self.client.post(f'/api/shop/buy/{item_id}')
@task(2)
def upgrade_weapon(self):
"""升级武器"""
self.client.post('/api/weapon/upgrade', json={
'weapon_id': random.randint(1, 10)
})
class GameUser(HttpUser):
tasks = [PlayerBehavior]
wait_time = between(1, 5)
def on_start(self):
"""登录"""
self.client.post('/api/login', json={
'username': f'user_{random.randint(1, 10000)}',
'password': 'test123'
})
分布式测试
# 主节点
locust -f locustfile.py --master --host=https://api.game.com
# 从节点1
locust -f locustfile.py --worker --master-host=192.168.1.100
# 从节点2
locust -f locustfile.py --worker --master-host=192.168.1.100
性能监控
响应时间监控
import time
from locust import HttpUser, task, events
# 自定义统计
custom_stats = []
@events.request.add_listener
def on_request(request_type, name, response_time, response_length, exception, **kwargs):
"""记录每个请求"""
if exception:
print(f"请求失败: {name} - {exception}")
else:
custom_stats.append({
'name': name,
'response_time': response_time,
'timestamp': time.time()
})
class GameUser(HttpUser):
@task
def test_api(self):
self.client.get('/api/test')
@events.test_stop.add_listener
def on_test_stop(environment, **kwargs):
"""测试结束后分析数据"""
if custom_stats:
import statistics
times = [s['response_time'] for s in custom_stats]
print(f"\n性能统计:")
print(f"平均响应时间: {statistics.mean(times):.2f}ms")
print(f"中位数: {statistics.median(times):.2f}ms")
print(f"P95: {sorted(times)[int(len(times)*0.95)]:.2f}ms")
print(f"P99: {sorted(times)[int(len(times)*0.99)]:.2f}ms")
实时监控仪表盘
# 使用Grafana + InfluxDB
from locust import HttpUser, task, events
from influxdb import InfluxDBClient
# 连接InfluxDB
client = InfluxDBClient(host='localhost', port=8086, database='locust')
@events.request.add_listener
def on_request(request_type, name, response_time, response_length, exception, **kwargs):
"""发送数据到InfluxDB"""
json_body = [{
'measurement': 'api_performance',
'tags': {
'request_type': request_type,
'name': name,
},
'fields': {
'response_time': response_time,
'response_length': response_length,
'success': 1 if not exception else 0
}
}]
client.write_points(json_body)
Python性能分析
CPU分析 - cProfile
import cProfile
import pstats
def expensive_function():
"""耗时函数"""
result = 0
for i in range(1000000):
result += i * i
return result
# 性能分析
profiler = cProfile.Profile()
profiler.enable()
expensive_function()
profiler.disable()
# 查看结果
stats = pstats.Stats(profiler)
stats.sort_stats('cumulative')
stats.print_stats(10) # 显示前10个最耗时的函数
装饰器方式:
import cProfile
@cProfile.profile
def game_logic():
"""游戏逻辑"""
# ... 游戏代码 ...
pass
内存分析 - memory_profiler
pip install memory-profiler
from memory_profiler import profile
@profile
def load_game_data():
"""加载游戏数据"""
large_list = [i for i in range(1000000)]
large_dict = {i: i*2 for i in range(100000)}
return large_list, large_dict
# 运行
python -m memory_profiler script.py
行级性能分析 - line_profiler
pip install line-profiler
@profile
def calculate_damage(player, enemy):
"""计算伤害"""
base_damage = player.attack
defense_reduction = enemy.defense * 0.5
final_damage = max(1, base_damage - defense_reduction)
critical = random.random() < player.crit_rate
if critical:
final_damage *= 2
return final_damage
# 运行
kernprof -l -v script.py
数据库性能测试
SQL查询性能
import time
import psycopg2
def test_query_performance():
"""测试查询性能"""
conn = psycopg2.connect(
host="localhost",
database="game_db",
user="user",
password="password"
)
cursor = conn.cursor()
# 测试查询
start_time = time.time()
cursor.execute("SELECT * FROM players WHERE level > 50")
results = cursor.fetchall()
query_time = time.time() - start_time
print(f"查询时间: {query_time:.3f}秒")
print(f"结果数量: {len(results)}")
cursor.close()
conn.close()
# 批量插入性能测试
def test_bulk_insert():
"""测试批量插入性能"""
conn = psycopg2.connect(...)
cursor = conn.cursor()
data = [(f'player_{i}', i, 100) for i in range(10000)]
start_time = time.time()
cursor.executemany(
"INSERT INTO players (name, level, hp) VALUES (%s, %s, %s)",
data
)
conn.commit()
insert_time = time.time() - start_time
print(f"插入10000条数据耗时: {insert_time:.3f}秒")
print(f"TPS: {10000/insert_time:.2f}")
WebSocket性能测试
import asyncio
import websockets
import time
async def test_websocket_performance():
"""测试WebSocket性能"""
uri = "ws://game.com/ws"
async with websockets.connect(uri) as websocket:
# 发送消息
start_time = time.time()
for i in range(100):
await websocket.send(f"Message {i}")
response = await websocket.recv()
duration = time.time() - start_time
print(f"100次往返耗时: {duration:.3f}秒")
print(f"平均延迟: {duration/100*1000:.2f}ms")
# 运行
asyncio.run(test_websocket_performance())
性能测试报告
自动生成报告
import pandas as pd
import matplotlib.pyplot as plt
from datetime import datetime
class PerformanceReport:
"""性能测试报告生成器"""
def __init__(self):
self.results = []
def add_result(self, api, response_time, success):
"""添加测试结果"""
self.results.append({
'api': api,
'response_time': response_time,
'success': success,
'timestamp': datetime.now()
})
def generate_report(self, output_file='performance_report.html'):
"""生成HTML报告"""
df = pd.DataFrame(self.results)
# 计算统计数据
stats = df.groupby('api').agg({
'response_time': ['mean', 'median', 'min', 'max'],
'success': 'sum'
})
# 生成图表
fig, axes = plt.subplots(2, 2, figsize=(15, 10))
# 响应时间分布
df['response_time'].hist(bins=50, ax=axes[0, 0])
axes[0, 0].set_title('响应时间分布')
axes[0, 0].set_xlabel('响应时间(ms)')
# API性能对比
stats['response_time']['mean'].plot(kind='bar', ax=axes[0, 1])
axes[0, 1].set_title('各API平均响应时间')
# 时间序列
df.plot(x='timestamp', y='response_time', ax=axes[1, 0])
axes[1, 0].set_title('响应时间趋势')
# 成功率
success_rate = df.groupby('api')['success'].mean()
success_rate.plot(kind='bar', ax=axes[1, 1])
axes[1, 1].set_title('各API成功率')
plt.tight_layout()
plt.savefig('performance_charts.png')
# 生成HTML报告
html = f"""
<html>
<head><title>性能测试报告</title></head>
<body>
<h1>性能测试报告</h1>
<h2>测试统计</h2>
{stats.to_html()}
<h2>性能图表</h2>
<img src="performance_charts.png">
</body>
</html>
"""
with open(output_file, 'w', encoding='utf-8') as f:
f.write(html)
print(f"报告已生成: {output_file}")
实战案例
游戏登录压力测试
from locust import HttpUser, task, between
import random
import string
class GameLoginTest(HttpUser):
"""登录压力测试"""
wait_time = between(1, 2)
def generate_username(self):
"""生成随机用户名"""
return ''.join(random.choices(string.ascii_letters, k=10))
@task
def login(self):
"""测试登录"""
username = self.generate_username()
response = self.client.post('/api/login', json={
'username': username,
'password': 'test123'
})
if response.status_code == 200:
token = response.json().get('token')
# 使用token进行后续操作
self.client.get('/api/player/info', headers={
'Authorization': f'Bearer {token}'
})
游戏战斗性能测试
class BattlePerformanceTest(HttpUser):
"""战斗系统性能测试"""
wait_time = between(0.5, 1)
def on_start(self):
"""初始化"""
# 登录
response = self.client.post('/api/login', json={
'username': 'test_user',
'password': 'test123'
})
self.token = response.json()['token']
@task(10)
def start_battle(self):
"""开始战斗"""
self.client.post('/api/battle/start',
json={'enemy_id': random.randint(1, 100)},
headers={'Authorization': f'Bearer {self.token}'}
)
@task(5)
def attack(self):
"""攻击"""
self.client.post('/api/battle/attack',
json={'skill_id': random.randint(1, 10)},
headers={'Authorization': f'Bearer {self.token}'}
)
@task(1)
def use_item(self):
"""使用道具"""
self.client.post('/api/battle/use_item',
json={'item_id': random.randint(1, 5)},
headers={'Authorization': f'Bearer {self.token}'}
)
性能优化建议
1. 数据库优化
- 添加索引
- 使用连接池
- 查询优化
- 批量操作
2. 缓存策略
- Redis缓存热点数据
- 本地缓存
- CDN加速
3. 代码优化
- 算法优化
- 异步处理
- 减少IO操作
4. 架构优化
- 负载均衡
- 水平扩展
- 微服务架构
下一步
继续学习: