locust分布式压测

玩转locust
1.当实现分布式压测时,可在init回调中设置中止测试的情况,也可在init中实现注册master端的消息和worker的消息,可用

environment.runner.send_message(注册的消息类型, 发送的数据)进行数据传输,实现master和worker进行传输信息

2.

'''''''''
#创建集合点,当locust实例产生完成时触发
'''
all_locusts_spawned = Semaphore()
#上锁
all_locusts_spawned.acquire()

上面步骤进上锁,当我们在test_start事件回调上进行释放锁时,可实现在开始测试前等待所有用户加载完成在执行locust的task

3.LoadTestShape,不可与设置用户数和设置增长用户速率一起使用,会覆盖!

这个类在locust启动的时候,会检测,有这个类,locust会一直根据这个类下面的

tick函数返回的元组(int,folat),来进行用户的速率变化,比如你想实现在某段时间内增加用户数量,某段时间内减少用户数量,只要控制tick的返回就行了(用户总数,速率/个)
from locust.runners import MasterRunner, WorkerRunner,STATE_STOPPING, STATE_STOPPED, STATE_CLEANUP,LocalRunner
from locust import HttpUser, TaskSet, task, events, LoadTestShape
from gevent._semaphore import Semaphore
import json
import traceback
import gevent
import time


'''请求成功时触发'''
def on_request_success(request_type, name, response_time, response_length):

    print( 'success  Type: {}, Name: {}, Time: {}ms, length: {}'
           .format(request_type, name, response_time,response_length))

'''请求失败时触发'''
def on_request_failure(request_type, name, response_time, response_length,exception):
    print('failure  Type: {}, Name: {}, Time: {}ms, exception: {}, response_length:{}'
          .format(request_type, name, response_time,exception,response_length))

'''在执行locust类内发生异常时触发'''
def on_locust_error(locust_instance, exception, tb):
    print("error  locust_instance: {}, exception: {}, traceback: {}"
          .format(locust_instance, exception,traceback.format_tb(tb)))

#退出进程时回调
def on_quitting(environment,**kwargs):
    print("Test quit")

'''
#停止测试的时候客户端会调这个方法发送数据到主节点这边
'''
def on_test_stop(environment,**kwargs):
    if not isinstance(environment.runner, MasterRunner):
        print("Cleaning up test data")
        #节点往主节点发送的数据
        environment.runner.send_message('acknowledge_users', f"Thanks for the Cleaning up test data users!")
    else:
        users = [
            {"name": "User1"},
            {"name": "User2"},
            {"name": "User3"},
        ]
        environment.runner.send_message('test_users', users)

'''
#定义worker节点注册的消息
# Fired when the worker receives a message of type 'test_users'
'''
def setup_test_users(environment, msg, **kwargs):
    for user in msg.data:
        print(f"User {user['name']} received")
    environment.runner.send_message('acknowledge_users', f"Thanks for the {len(msg.data)} users!")

'''
#定义matser节点注册的消息
#Fired when the master receives a message of type 'acknowledge_users!!!!
'''
def on_acknowledge(msg, **kwargs):
    print("recv worker data :{}".format(msg.data))


'''
#主动退出进程时:environment.process_exit_code = 0
#判断错误率大于多少N主动退出进程
#判断响应时间大于多少N主动退出进程
#判断响应时间
'''
def checker(environment):
    while not environment.runner.state in [STATE_STOPPING, STATE_STOPPED, STATE_CLEANUP]:
        time.sleep(1)
        if environment.stats.total.fail_ratio > 0.01:
            print("Test failed due to failure ratio > 1%,code=1")
            environment.process_exit_code = 1
            '''这个语句是退出'''
            environment.runner.quit()
        elif environment.stats.total.avg_response_time > 200:
            print("Test failed due to average response time ratio > 200 ms,code=1")
            environment.process_exit_code = 1
        elif environment.stats.total.get_response_time_percentile(0.95) > 300:
            print("Test failed due to 95th percentile response time > 800 ms,code=1")
            environment.process_exit_code = 1
        else:
            environment.process_exit_code = 0
            print("Test Normal task exit code=0")
'''
#初始化时绑定的重写方法,该类中进行了worler和master节点的消息注册
'''
def on_locust_init(environment, **kwargs):
    if not isinstance(environment.runner, MasterRunner):
        '''
        #初始化的时候注册消息,客户端的消息,往客户端的往这个类型发就行
        '''
        environment.runner.register_message('test_users', setup_test_users)
    if not isinstance(environment.runner, WorkerRunner):
        '''
        #初始化的时候注册消息,服务端的消息,往后服务端往这个类型发就行
        '''
        environment.runner.register_message('acknowledge_users', on_acknowledge)

    if isinstance(environment.runner, MasterRunner) or isinstance(environment.runner, LocalRunner):
        gevent.spawn(checker, environment)


def on_test_start(environment, **kwargs):
    '''如果运行环境不是主节点'''
    if not isinstance(environment.runner, MasterRunner):
        users = [
            {"name": "User1"},
            {"name": "User2"},
            {"name": "User3"},
        ]
        environment.runner.send_message('test_users', users)





'''''''''
#创建集合点,当locust实例产生完成时触发
'''
all_locusts_spawned = Semaphore()
#上锁
all_locusts_spawned.acquire()
'''
#生成所有locust用户时触发
'''
def on_hatch_complete(**kwargs):
    #释放锁
    all_locusts_spawned.release()

'''
#事件回调绑定
'''
events.spawning_complete.add_listener(on_hatch_complete)
events.request_success.add_listener(on_request_success)
events.request_failure.add_listener(on_request_failure)
events.user_error.add_listener(on_locust_error)
events.quitting.add_listener(on_quitting)
events.init.add_listener(on_locust_init)

'''
#主节点才触发
'''
events.test_start.add_listener(on_test_start)
events.test_stop.add_listener(on_test_stop)

header={"Content-Type": "application/json;charset=UTF-8"}
class WebsiteTasks(TaskSet):

    '''
    #进行初始化的工作,每个Locust用户开始做的第一件事
    '''
    def on_start(self):
        payload = {
            "username": "13592945579",
            "password": "5632721",
        }
        # self.client属性使用Python request库的所有方法,调用和使用方法和requests完全一致;
        with self.client.post("/user/signin",data=json.dumps(payload),catch_response=True,headers=header) as response:
            if response.status_code==200:
                response.success()
            else:
                response.failure("on_start请求失败!")


    '''
    #通过@task()装饰的方法为一个事务,方法的参数用于指定该行为的执行权重,参数越大每次被虚拟用户执行的概率越高,默认为1
    '''
    @task(1)
    def index(self):
        payload = {
            "username": "13592945579",
            "password": "5632721",
        }
        # self.client.request_name = "/blog?id=[id]" #自定义locust报告中Statistics的Name名称,进行分组显示
        with self.client.post("/user/signin",data=json.dumps(payload),catch_response=True,headers=header) as respone:#self.client属性使用Python request库的所有方法,调用和使用方法和requests完全一致;
            if respone.status_code == 200:
                respone.success()
            else:
                respone.failure("index请求失败!")


    @task(2)
    def test01(self):
        payload = {
            "username": "13592945579",
            "password": "5632721",
        }

        with self.client.post("/user/signin",data=json.dumps(payload),catch_response=True,headers=header) as respone:#self.client属性使用Python request库的所有方法,调用和使用方法和requests完全一致;
            try:
                if respone.status_code == 200:
                    respone.catch_response = True
                else:
                    respone.failure("test01请求失败!")
            except json.JSONDecodeError:
                respone.failure("Response could not be decoded as JSON!")
            except KeyError:  # 字典类型的数据,操作的变量没有该键时会报这个错
                respone.failure("Response did not contain expected key 'greeting'")


                # @task(1)
    # def about(self):
    #     self.client.get("/about/")

class WebsiteUser(HttpUser):
    # host     = "172.168.8.113:5000" #被测系统的host,在终端中启动locust时没有指定--host参数时才会用到
    host = "http://127.0.0.1:5000"
    tasks = [WebsiteTasks]          #TaskSet类,该类定义用户任务信息,必填。这里就是:WebsiteTasks类名,因为该类继承TaskSet;
    min_wait = 5000  #每个用户执行两个任务间隔时间的上下限(毫秒),具体数值在上下限中随机取值,若不指定默认间隔时间固定为1秒
    max_wait = 15000
    # def stop(self, force=False):
    #     self.stop(True)

'''
#定义长期跑的时候,用户增长量和下滑量和停止时间,这个模式会覆盖config配置的模式
'''
# class MyCustomShape(LoadTestShape):
#     time_limit = 10
#     time_avg=70
#     spawn_rate = 1
#     user_count=0
#     count_avg=20
#     end_time=90
#
#     def tick(self):
#         run_time = self.get_run_time()
#         '''
#         #如果运行时间小于设定的时间就以最大用户数下滑
#         '''
#
#         if run_time < self.time_limit and run_time <self.time_avg:
#
#             self.user_count=self.user_count+self.spawn_rate
#             if self.user_count<self.count_avg:
#                 print("run_time< self.time_limit:",self.user_count,"run_time:{}".format(run_time))
#                 return (self.user_count,self.spawn_rate)
#             elif self.user_count>self.count_avg:
#                 return (self.count_avg,self.spawn_rate)
#
#         elif run_time > self.time_limit and run_time<self.time_avg:
#             '''
#             #如果运行时间大于设定的时间就以最大用户数下滑
#             '''
#             if self.user_count<self.count_avg:
#                 self.user_count = self.user_count+self.spawn_rate
#                 return (self.user_count, (self.spawn_rate))
#             elif self.user_count>self.count_avg and run_time<self.time_avg:
#                 # self.user_count=self.user_count-self.spawn_rate
#                 print("run_time > self.time_limit:",self.user_count,"run_time:{}".format(run_time))
#                 return (self.count_avg, (self.spawn_rate))
#             elif self.user_count>=self.count_avg and run_time>self.time_avg:
#                 # self.user_count=self.user_count-self.spawn_rate
#                 return (self.count_avg, -(self.spawn_rate))
#         elif run_time>=self.time_avg and run_time<=self.end_time:
#             print("run_time = self.time_limit:", self.user_count, "run_time:{}".format(run_time))
#             return (self.count_avg, (self.spawn_rate))
#
#         elif run_time>self.end_time:
#             self.user_count = self.user_count - self.spawn_rate
#             return (self.count_avg, -(self.spawn_rate))

if __name__ == '__main__':
    import os
    # os.system("locust -f G:\\script_xlink\\locust_py\\script_WebsiteTasks.py  --host=http://127.0.0.1:5000")
    # os.system("locust -f G:\\script_xlink\\locust_py\\script_WebsiteTasks.py --master --host=http://172.168.8.113:5000")
    # os.system("locust -f G:\\script_xlink\\locust_py\\script_WebsiteTasks.py --master" )
    # os.system("locust -f G:\\script_xlink\\locust_py\\script_WebsiteTasks.py --worker")
    os.system("locust --config=G:\script_xlink\locust_py\config\config.conf")
    # os.system("locust -f G:\\script_xlink\\locust_py\\script_WebsiteTasks.py --master --expect-workers=1 --headless" )

config:

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值