This article appeared in:Walker AI

Due to the high performance testing requirements of the company at present, several popular pressure testing tools have been investigated. Since Jmeter and LoadRunner realize concurrency based on multi-threading, which is determined by the operating system, it is difficult for a single machine to generate a large number of concurrent threads due to frequent context switching and kernel scheduling. Jmeter is written in The Java language, but Java does not support the coroutine mechanism. The Python language implements coroutines in the form of async/await, and Locust is based on Python. So this time I will focus on the Locust performance testing tool.

First of all, we have to understand that only create pressure to evaluate the performance of the project, performance testing is the key to produce a large number of concurrent through tools, and the principle of concurrent strength depends on tool because Locust is a lightweight, script design more flexible, a lot of heavy pressure measuring tool can realize the function can also be implemented in the Locust. Locust in Python can achieve high concurrency in a more lightweight way, so we’ll show you how to get started with locust quickly, with introductions to important features and code examples.

1. Characteristics of Locust

(1) Develop scripts based on Python; (2) Open source free, secondary development; (3) Distributed execution. Configure master and slave(master and slave machines) to continuously initiate requests to the system on multiple machines; (4) Event-driven. Unlike other tools that use processes and threads to simulate users, Locust uses the GEvent library’s support for coroutines to achieve higher orders of magnitude of concurrency; (5) Do not support monitoring of the machine under test, need to cooperate with the assistance of other tools; (6) In the Locust class, there is a client attribute, which corresponds to the virtual user as a client has the ability to request, that is, we often say the request method; Therefore, when using Locust, we need to inherit the Locust class first, and then bind the client implementation class in the client property of the inheritance subclass. (7) HttpUser uses requests.Session, so all subsequent tasks are logged in; (8) Version changes: after the 1.0 version of the update focus is to replace HttpLocust with Httpuser, task_set task set needs the data type for the list type, and task_set needs to change to tasks.

2. Index system and common usage process of Locust

(1) Response time: a measure of the processing efficiency of a system. It is a measure of the time it takes to complete a task from the beginning. Response time usually increases with the increase of load; (2) Throughput: an indicator reflecting the processing capacity of the system, which refers to the measurement of the work completed within a unit of time. It can be comprehensively evaluated from the perspective of the client or the server. (3) Transaction processing capability (TPS is RPS in LOCUST) : the corresponding situation of processing a transaction, usually including three indicators, one is the response time of processing the business, the second is the success rate of processing the business, and the third is the number of businesses that can be processed in a unit of time (per second, per minute, per hour, etc.).

CMD Command execution script

Web UI operations (The Web UI does not automatically stop. You need to manually stop the web UI). Go to the py level in the project directory; Locust -f test.py or locust -f test.py –host=http://example.com; Open the browser, enter the Web interface, and add the total number of simulated users and the number of virtual users started per second. http://localhost:8089; Test result interface:

Command run

Locust -f test.py — no-web-c 100 -r 20 -t 5 or locust -f test.py –host=http://example.com — no-web-c 100 -r 20 -t 5; -c: indicates the number of users. -r: number generated per second; -t: limits the running time. -n: total number of requests.

3. Syntax of Locust

(1) Define a task class. The name of the class can be defined by itself; (2) SequentialTaskSet; (3) SequentialTaskSet; (4) SequentialTaskSet; (3) The SequentialTaskSet class is inherited when the task requests in the class are sequential; (4) The TaskSet class can be inherited in no order;

import random from locust import HttpUser, task, between, SequentialTaskSet, tag class MyTaskCase(SequentialTaskSet): Setup def on_start(self): Pass # @task a decorator in Python that tells the following method to be a task. # This decorator and the following method have been copied several times. With a change, you can write out multiple interfaces. We need to import the header from locust, import task.task.tag ("leave_1") def regist_(self): # Define the request header as a class variable so that other tasks can call this variable self.headers = {" content-type ": "application/json"} self.username = "locust_" + str(random.randint(10000, Data = {"name": self.username, "PWD ": # catch_response = "True"; # catch_response = "True"; Post (URL, json=data, headers=self. Headers, catch_response=True) as RSP: If rsp.status_code > 400: print(rsp.text) rsp.failure('regist_ interface failed! Def login_(self): url = '/erp/loginIn' data = {"name": self.username, "PWD ": self.pwd} with self.client.post(url, json=data, headers=self.headers, catch_response=True) as rsp: Self.token = rsp.json()['token'] if rsp.status_code < 400 \ and rsp.json()['code'] == "200": Rsp.success () else: rsp.failure('login_ interface failed! Def getUser_ (self): url = '/erp/user' def getUser_ (self): url = '/erp/user' Self.client. Get (url, headers=headers, catch_response=True) as RSP: If rsp.status_code < 400: rsp.success() else: rsp.failure(' getUser_ interface failed! ') # teardown def on_stop(self): pass # define a run class that inherits from the HttpUser class, so introduce class UserRun(HttpUser) from locust: Tasks = [MyTaskCase] # Set interval from locust to between wait_time = between(0.1, 3)

4. Example of single interface pressure test

#! /usr/bin/env python # -*- coding: utf-8 -*- from locust import task,TaskSet,HttpUser class UserTasks(TaskSet): @task def getIndex(self): Get ("/path") print("here") class WebUser(HttpUser): Tasks = [UserTasks] # Interval between requests min_wait = 1000 max_wait = 2000

Run:

In the terminal, enter the following command: locust -f Locust file to be executed py –host= http://domain name or IP port of the tested server… For example, “locust -f locust_test.py –host=http://localhost:8082”. If the command is successfully executed, the system displays the service port, for example, * : 8089. At this time, you can access the machine IP :8089 through a browser and see the task test page.

Spawn Rate (Users SPAWNED/Second) Number of users generated per second

5. Pressure test examples for business use cases

The following uses a login interface and an ID interface as an example

# #! /usr/bin/env python # # -*- coding: utf-8 -*- from locust import task,TaskSet,HttpUser,tag from random import randint import json class UserTasks(TaskSet): def on_start(self): # Prepare for test, Request received mostly dictionary format of the self. The loginData = [{" username ":" 1 ", "paswordword" : "1"}, {" username ":" 2 ", "paswordword" : "2"}, {" username ", "3", "paswordword" : "3"}] print (" -- -- -- -- -- -- -- -- -- -- -- on_start -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - ") # statement below is a login task @ task (1) the def doLogin(self): RanIndex = randint(1,len(self.logindata) self.loginData[ranIndex],catch_response=True) if "login-pass" in response.text: response.success() else: response.failure("Can not login!" @task def get_goods(self) Body = {"good_name" :"apple"} # Send request and response= self.client. Post ("/path2",data = body,catch_response=True) newText = json.loads(response.txt) if "game_id" in newText[0].keys(): response.success() else: response.failure("Can not get!" Tasks = {doLogin:1, get_goods:2} Class WebUser(User): @task @tag("tag1", "tag2") def my_task(self): pass class WebUser(HttpUser): # declare which class is the set of tasks to execute, Tasks in a task set are executed with the assigned weight of 1:2. Tasks = [UserTasks] # Interval between min and Max wait requests min_WAIT = 1000 max_wait = 2000 # locust -f Locust_test. py --host=http://localhost:8082 # Number of total users to simulate # Spawn rate (users) Spawned /second) The number of users per second

Note: Non-task requests will also be displayed in the Locust statistics panel if the request values of the task interface require the parameters returned by other interfaces. If you want to focus only on statistics for the task interface, you need to use the native requests library for dependent requests.

6. Data monitoring tool recommendation

(1) If the company has built a monitoring system, please ask the operation and maintenance assistance to check on the platform, such as Grafana; (2) Linux detection tool Nmon; (3) Windows comes with Perfmon; (4) Use Python’s PSUIL library to customize the detection frequency and indicator parameters, and the data needs to be processed separately;

7. To summarize

Compared with other tools such as JMeter, Locust has much higher degrees of freedom based on Python language, and can customize the implementation method of special protocols. Moreover, LocUST based on coroutine is easier to construct the performance automation test platform, if the configuration of the pressure test machine is limited, but also want to meet the high concurrency. Using Locust is a wise choice.


PS: more dry technology, pay attention to the public, | xingzhe_ai 】, and walker to discuss together!