locust高级特性详解

事件系统深度应用

全局事件监听

Locust的事件系统就像是一个"消息广播站",可以在特定时机执行自定义逻辑:

  • @events.test_start.add_listener
  • @events.test_stop.add_listener
  • @events.user_error.add_listener
from locust import HttpUser, task, events
import logging

# 配置日志
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

@events.test_start.add_listener
def on_test_start(environment, **kwargs):
    """测试开始时执行"""
    logger.info("🚀 压测开始!准备发射...")
    # 可以在这里做一些初始化工作
    # 比如清理测试数据、发送通知等

@events.test_stop.add_listener  
def on_test_stop(environment, **kwargs):
    """测试结束时执行"""
    logger.info("🏁 压测结束!开始分析结果...")
    # 可以在这里做清理工作
    # 比如生成报告、发送邮件等

@events.user_error.add_listener
def on_user_error(user_instance, exception, tb, **kwargs):
    """用户出错时执行"""
    logger.error(f"❌ 用户出错: {exception}")
    # 可以记录详细错误信息,便于调试

class AdvancedUser(HttpUser):
    wait_time = between(1, 2)
    host = "https://httpbin.org"
    
    @task
    def test_api(self):
        self.client.get("/get")

自定义统计指标

有时候默认的统计指标不够用,我们可以自定义:

  • @events.request_success.add_listener
  • @events.request_failure.add_listener
from locust import HttpUser, task, events
from locust.stats import stats_history
import time

# 自定义统计数据存储
custom_stats = {
    "business_success_count": 0,
    "business_error_count": 0,
    "total_processing_time": 0
}

@events.request_success.add_listener
def on_request_success(request_type, name, response_time, response_length, **kwargs):
    """请求成功时的自定义统计"""
    if "business_api" in name:
        custom_stats["business_success_count"] += 1
        custom_stats["total_processing_time"] += response_time

@events.request_failure.add_listener  
def on_request_failure(request_type, name, response_time, response_length, exception, **kwargs):
    """请求失败时的自定义统计"""
    if "business_api" in name:
        custom_stats["business_error_count"] += 1

class BusinessUser(HttpUser):
    wait_time = between(1, 2)
    host = "https://httpbin.org"
    
    @task
    def business_api_call(self):
        """业务API调用"""
        start_time = time.time()
        
        with self.client.get("/json", name="business_api", catch_response=True) as response:
            # 业务逻辑验证
            if response.status_code == 200:
                data = response.json()
                if "slideshow" in data:
                    response.success()
                else:
                    response.failure("业务数据格式错误")
            else:
                response.failure(f"HTTP错误: {response.status_code}")

集合点功能实现

集合点是性能测试中的重要概念,让所有用户在某个时刻同时执行操作

  • @events.spawning_complete.add_listener
from locust import HttpUser, task, events
from gevent._semaphore import BoundedSemaphore
import time

# 创建集合点信号量
rendezvous_point = BoundedSemaphore()
rendezvous_point.acquire()  # 初始状态为锁定

@events.spawning_complete.add_listener
def on_spawning_complete(**kwargs):
    """所有用户启动完成后释放集合点"""
    print("🚦 所有用户已就位,释放集合点!")
    rendezvous_point.release()

class RendezvousUser(HttpUser):
    wait_time = between(1, 2)
    host = "https://httpbin.org"
    
    @task
    def synchronized_task(self):
        """需要同步执行的任务"""
        print(f"用户 {self.user_id} 到达集合点,等待其他用户...")
        
        # 等待集合点释放
        rendezvous_point.acquire()
        rendezvous_point.release()  # 立即释放,让其他用户也能通过
        
        print(f"用户 {self.user_id} 开始同步执行任务")
        
        # 同时执行的关键操作
        start_time = time.time()
        response = self.client.get("/get")
        end_time = time.time()
        
        print(f"用户 {self.user_id} 完成任务,耗时: {end_time - start_time:.2f}秒")
    
    def on_start(self):
        """为每个用户分配唯一ID"""
        import uuid
        self.user_id = str(uuid.uuid4())[:8]

自定义负债模型 LoadTestShape

阶梯式负载

from locust import LoadTestShape

class StepLoadShape(LoadTestShape):
    """
    阶梯式负载模型
    每60秒增加10个用户,最多100个用户
    """
    
    step_time = 60  # 每步持续时间
    step_load = 10  # 每步增加的用户数
    spawn_rate = 2  # 用户启动速率
    time_limit = 600  # 总测试时间
    
    def tick(self):
        run_time = self.get_run_time()
        
        if run_time > self.time_limit:
            return None  # 停止测试
        
        current_step = run_time // self.step_time
        user_count = (current_step + 1) * self.step_load
        
        # 限制最大用户数
        user_count = min(user_count, 100)
        
        return (user_count, self.spawn_rate)

class MyUser(HttpUser):
    wait_time = between(1, 2)
    host = "https://httpbin.org"
    
    @task
    def test_endpoint(self):
        self.client.get("/get")

波浪式负载

import math

class WaveLoadShape(LoadTestShape):
    """
    波浪式负载模型
    用户数量呈正弦波变化
    """
    
    min_users = 10
    max_users = 100
    wave_period = 300  # 波浪周期(秒)
    
    def tick(self):
        run_time = self.get_run_time()
        
        if run_time > 600:  # 10分钟后停止
            return None
        
        # 计算当前用户数(正弦波)
        wave_progress = (run_time % self.wave_period) / self.wave_period
        user_count = self.min_users + (self.max_users - self.min_users) * \
                    (math.sin(2 * math.pi * wave_progress) + 1) / 2
        
        return (int(user_count), 5)

HTTP客户端自定义

自定义认证AuthBase

from requests.auth import AuthBase
import hmac
import hashlib
import time

class CustomAuth(AuthBase):
    """自定义认证类"""
    
    def __init__(self, access_key, secret_key):
        self.access_key = access_key
        self.secret_key = secret_key
    
    def __call__(self, request):
        # 添加时间戳
        timestamp = str(int(time.time()))
        
        # 生成签名
        string_to_sign = f"{request.method}\n{request.url}\n{timestamp}"
        signature = hmac.new(
            self.secret_key.encode(),
            string_to_sign.encode(),
            hashlib.sha256
        ).hexdigest()
        
        # 添加认证头
        request.headers['X-Access-Key'] = self.access_key
        request.headers['X-Timestamp'] = timestamp
        request.headers['X-Signature'] = signature
        
        return request

class AuthenticatedUser(HttpUser):
    wait_time = between(1, 2)
    host = "https://api.example.com"
    
    def on_start(self):
        """设置自定义认证"""
        self.client.auth = CustomAuth("your_access_key", "your_secret_key")
    
    @task
    def protected_api(self):
        """调用需要认证的API"""
        self.client.get("/protected/resource")

连接池优化

from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry

class OptimizedUser(HttpUser):
    wait_time = between(1, 2)
    host = "https://httpbin.org"
    
    def on_start(self):
        """优化HTTP连接"""
        # 配置重试策略
        retry_strategy = Retry(
            total=3,
            backoff_factor=1,
            status_forcelist=[429, 500, 502, 503, 504],
        )
        
        # 配置连接适配器
        adapter = HTTPAdapter(
            pool_connections=10,  # 连接池大小
            pool_maxsize=20,      # 最大连接数
            max_retries=retry_strategy
        )
        
        # 应用到客户端
        self.client.mount("http://", adapter)
        self.client.mount("https://", adapter)
        
        # 设置超时
        self.client.timeout = (5, 30)  # 连接超时5秒,读取超时30秒
    
    @task
    def optimized_request(self):
        """优化后的请求"""
        self.client.get("/get")

实时监控和告警

自定义监控指标

from locust import HttpUser, task, events
import psutil
import time

class SystemMonitor:
    """系统资源监控"""
    
    def __init__(self):
        self.start_time = time.time()
        self.cpu_samples = []
        self.memory_samples = []
    
    def collect_metrics(self):
        """收集系统指标"""
        cpu_percent = psutil.cpu_percent()
        memory_percent = psutil.virtual_memory().percent
        
        self.cpu_samples.append(cpu_percent)
        self.memory_samples.append(memory_percent)
        
        # 检查告警条件
        if cpu_percent > 80:
            print(f"⚠️  CPU使用率过高: {cpu_percent}%")
        
        if memory_percent > 80:
            print(f"⚠️  内存使用率过高: {memory_percent}%")

# 全局监控实例
monitor = SystemMonitor()

@events.test_start.add_listener
def start_monitoring(environment, **kwargs):
    """开始监控"""
    print("📊 开始系统监控...")

@events.request_success.add_listener
def on_success(request_type, name, response_time, response_length, **kwargs):
    """请求成功时收集指标"""
    monitor.collect_metrics()

class MonitoredUser(HttpUser):
    wait_time = between(1, 2)
    host = "https://httpbin.org"
    
    @task
    def monitored_request(self):
        """被监控的请求"""
        self.client.get("/get")

测试报告定制

生成自定义报告

from locust import events
import json
import os
from datetime import datetime

class CustomReporter:
    """自定义报告生成器"""
    
    def __init__(self):
        self.test_start_time = None
        self.test_end_time = None
        self.custom_data = {
            "test_info": {},
            "performance_metrics": {},
            "error_summary": []
        }
    
    def generate_report(self, environment):
        """生成自定义报告"""
        stats = environment.stats
        
        # 收集基本信息
        self.custom_data["test_info"] = {
            "start_time": self.test_start_time.isoformat(),
            "end_time": self.test_end_time.isoformat(),
            "duration": (self.test_end_time - self.test_start_time).total_seconds(),
            "total_users": environment.runner.user_count
        }
        
        # 收集性能指标
        self.custom_data["performance_metrics"] = {
            "total_requests": stats.total.num_requests,
            "total_failures": stats.total.num_failures,
            "average_response_time": stats.total.avg_response_time,
            "rps": stats.total.current_rps,
            "failure_rate": stats.total.fail_ratio
        }
        
        # 保存报告
        report_file = f"custom_report_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json"
        with open(report_file, 'w', encoding='utf-8') as f:
            json.dump(self.custom_data, f, ensure_ascii=False, indent=2)
        
        print(f"📋 自定义报告已生成: {report_file}")

# 全局报告器实例
reporter = CustomReporter()

@events.test_start.add_listener
def on_test_start(environment, **kwargs):
    reporter.test_start_time = datetime.now()

@events.test_stop.add_listener
def on_test_stop(environment, **kwargs):
    reporter.test_end_time = datetime.now()
    reporter.generate_report(environment)

高级技巧总结

1. 性能调优建议

  • 合理设置用户数:不要一味追求高并发,要根据实际业务场景
  • 监控客户端资源:确保压测机器不成为瓶颈
  • 使用连接池:减少连接建立开销
  • 适当的等待时间:模拟真实用户行为

2.调优技巧

# 开发时使用调试模式
import logging
logging.basicConfig(level=logging.DEBUG)

# 单用户调试
if __name__ == "__main__":
    from locust.env import Environment
    
    env = Environment(user_classes=[MyUser])
    env.create_local_runner()
    env.runner.start(1, spawn_rate=1)
    
    import time
    time.sleep(10)
    env.runner.quit()

3. 最佳实践

  • 模块化设计:将公共功能抽取为基类

  • 数据驱动:使用外部数据文件驱动测试

  • 环境隔离:不同环境使用不同配置

  • 持续集成:集成到CI/CD流水线

参考 https://www.coder-ljx.cn:8825/stressStabilityTest/

posted @ 2025-11-12 15:47  hjy1995  阅读(4)  评论(0)    收藏  举报