应用 Locust 快速上手写压测

http://www.moye.me/2017/06/24/locust-load-testing/

引子

locust_logo 做为一个压测工具(库),locust 其实解决这么一个问题:AB 之类压测工具不能编写复杂的因果逻辑,而现实场景中,待压的服务往往是有一套完整执行流程的,比如 APP 要访问一个 API,是需要先鉴权(验明不是非 APP 访问),再登录换 Token,然后才是 API 调用……

这一切,在 locust 中都很容易实现,本质上,应用 locust 做压测,就是在写 Python 程序,只是它集成了一套不错的 UI,外加并发的benchmark功能。

至于写个压测为什么要用Python,是因为:这玩意心智负担低,你谷歌SO复制粘贴一把梭,直接上手就能写,大脑无需切换context,调试成本也低,没有比这语言更棒的了 ?

骨架

一个 locust 压测程序的最简配置就是一个 .py 程序文件,按照约定,我们给它命名为 locustfile.py,它大概由这么两部分组成:

  • 一个 TaskSet 类:里面放置你需要测试的各种任务,这些任务用 @task 装饰器来标记(洋气)
  • 一个 Locust 类:它的一个实例就代表一个了用户,同时它提供了用户并发访问的能力;它的 task_set 成员需要引用  TaskSet 类,那是它要执行的任务。

当然,locustfile.py 还有很多实用的配置,如 父子任务/等待时长/权重 等设置,细节可参见 官网文档

举个栗子

我现在有一个 API 需要压测,它的服务端大概是这么设计的:

  • 这个 API 地址是 http://example.org/api/dummy/test
  • 任何访问这个 API 的请求,都需要在 Headers 的 Authorization 中提供登录后才会有的 Token
  • 而要进行登录,需要提供这些 Headers:
    • Content-Type: application/json
    • timestamp:发起请求时APP 的时间戳
    • nonce:一个随机数
    • checksum: HMACSHA1(timestamp + nonce, secretKey),是的,一次哈希,并且这个 secretKey 是仅 APP 和 服务端 才知道的密钥
    • 以及正确的 用户名/密码 对
  • 登录地址是 http://example.org/api/users/login,在验明正身后,会下发 JSON 格式的 JWT token

OK,因为够复杂,所以要写程序来做压测了,Python 干这个,工程复杂度正好

一个实现

环境:

  • Python:2.7.11
  • Locust: 0.7.3

代码:

 

Python

from __future__ import print_function from locust import HttpLocust, TaskSet, task from hashlib import sha1 import time import uuid import hmac import base64 import httplib import json secret = "__HOLY_SECRET_KEY__" username = "Luke" password = "I'mYourFather" host = "http://example.org" loginUrl = "/api/users/login" apiUrl = "/api/dummy/test" def hmacsha1(plaintext, secret): return hmac.new(secret, plaintext, sha1).hexdigest() def timestamp(): return str(int(time.time())) def nonce(): return str(uuid.uuid1()) def auth_header(): ts = timestamp() nc = nonce() checksum = hmacsha1(ts + nc, secret) return {"Content-type": "application/json", "timestamp": ts, "nonce": nc, "checksum": checksum} class MyTaskSet(TaskSet): def on_start(self): self.tokenInfo = None headers = auth_header() data = json.dumps({"username": username,"password": password}) response = self.client.request(method="POST", url= loginUrl, data = data, headers = headers) print("LOGIN RESULT:", response.status_code, response.content) if response.status_code == 200: self.tokenInfo = json.loads(response.content) @task def dummy_test(self): if self.tokenInfo is not None: token = self.tokenInfo["token"] headers = auth_header() headers["Authorization"] = "Bearer " + token response = self.client.request(method="GET", url= apiUrl, headers = headers) print("API RESULT:", response.status_code, response.content) class MyLocust(HttpLocust): task_set = MyTaskSet host = host

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

from __future__ import print_function

from locust import HttpLocust, TaskSet, task

from hashlib import sha1

import time

import uuid

import hmac

import base64

import httplib

import json

 

secret = "__HOLY_SECRET_KEY__"

username = "Luke"

password = "I'mYourFather"

host = "http://example.org"

loginUrl = "/api/users/login"

apiUrl = "/api/dummy/test"

 

def hmacsha1(plaintext, secret):

    return hmac.new(secret, plaintext, sha1).hexdigest()

def timestamp():

    return str(int(time.time()))

def nonce():

    return str(uuid.uuid1())

def auth_header():

    ts = timestamp()

    nc = nonce()

    checksum = hmacsha1(ts + nc, secret)

    return {"Content-type": "application/json",

            "timestamp": ts,

             "nonce": nc,

             "checksum": checksum}

 

class MyTaskSet(TaskSet):

    def on_start(self):

        self.tokenInfo = None

        headers = auth_header()

        data = json.dumps({"username": username,"password": password})

        response = self.client.request(method="POST", url= loginUrl,

                                       data = data,

                                       headers = headers)

        print("LOGIN RESULT:", response.status_code, response.content)

        if response.status_code == 200:

            self.tokenInfo = json.loads(response.content)

 

    @task

    def dummy_test(self):

        if self.tokenInfo is not None:

            token = self.tokenInfo["token"]

            headers = auth_header()

            headers["Authorization"] = "Bearer " + token

            response = self.client.request(method="GET", url= apiUrl,

                                           headers = headers)

            print("API RESULT:", response.status_code, response.content)

 

class MyLocust(HttpLocust):

    task_set = MyTaskSet

    host = host

 

跑一个

先安装 Locust:

Shell

pip install locustio

1

pip install locustio

shell 里直接运行,locust 默认会运行 locustfile.py:

Shell

locust

1

locust

命令行会在服务起来后提示:

Shell

Starting web monitor at *:8089

1

Starting web monitor at *:8089

然后就可以在浏览器中访问 http://127.0.0.1:8089/

locust-look-and-feel

输入希望同时访问的用户数,及每用户的秒并发量,开始压测:

locust-benchmark-new

在这个过程中,可以随时停止测试,调整参数,当然,也可以在测试数据收集完成后,导出测试结果:

locust-result-export

 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值